[mmdb] 02/08: Imported Upstream version 2.0.1

Frédéric-Emmanuel Picca picca at moszumanska.debian.org
Wed Dec 31 09:32:43 UTC 2014


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

picca pushed a commit to branch master
in repository mmdb.

commit f3af8fbe7a5ae3222c781b26bad4c548b6166e65
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date:   Wed Sep 10 21:39:50 2014 +0200

    Imported Upstream version 2.0.1
---
 Makefile.am                               |   56 +-
 Makefile.in                               |  482 +--
 README                                    |   99 +-
 aclocal.m4                                |  276 +-
 configure                                 |   51 +-
 configure.ac                              |    6 +-
 mmdb/bfgs_min.cpp                         |  936 -----
 mmdb/bfgs_min.h                           |  257 --
 mmdb/file_.cpp                            | 1857 ----------
 mmdb/file_.h                              |  302 --
 mmdb/linalg_.cpp                          |  987 ------
 mmdb/linalg_.h                            |  233 --
 mmdb/machine_.cpp                         |  148 -
 mmdb/math_.cpp                            |  199 --
 mmdb/math_.h                              |   73 -
 mmdb/mattype_.cpp                         | 2116 ------------
 mmdb/mattype_.h                           |  659 ----
 mmdb/mmdb_align.cpp                       | 1219 -------
 mmdb/mmdb_align.h                         |  189 -
 mmdb/mmdb_atom.cpp                        | 3495 -------------------
 mmdb/mmdb_atom.h                          |  739 ----
 mmdb/mmdb_bondmngr.cpp                    |  125 -
 mmdb/mmdb_chain.cpp                       | 2568 --------------
 mmdb/mmdb_chain.h                         |  674 ----
 mmdb/mmdb_cifdefs.cpp                     |  122 -
 mmdb/mmdb_cifdefs.h                       |  327 --
 mmdb/mmdb_coormngr.cpp                    | 4360 -----------------------
 mmdb/mmdb_coormngr.h                      |  951 -----
 mmdb/mmdb_cryst.cpp                       | 2288 -------------
 mmdb/mmdb_cryst.h                         |  462 ---
 mmdb/mmdb_defs.h                          |  259 --
 mmdb/mmdb_file.cpp                        | 3060 -----------------
 mmdb/mmdb_file.h                          |  650 ----
 mmdb/mmdb_graph.cpp                       | 2460 -------------
 mmdb/mmdb_graph.h                         |  484 ---
 mmdb/mmdb_manager.cpp                     |  392 ---
 mmdb/mmdb_manager.h                       |  122 -
 mmdb/mmdb_mask.cpp                        |  246 --
 mmdb/mmdb_mmcif.cpp                       | 3671 --------------------
 mmdb/mmdb_mmcif.h                         | 2129 ------------
 mmdb/mmdb_model.cpp                       | 5313 ----------------------------
 mmdb/mmdb_model.h                         | 1085 ------
 mmdb/mmdb_sbase.cpp                       |  320 --
 mmdb/mmdb_sbase.h                         |  142 -
 mmdb/mmdb_sbase0.cpp                      | 3124 -----------------
 mmdb/mmdb_sbase0.h                        |  746 ----
 mmdb/mmdb_selmngr.cpp                     | 3393 ------------------
 mmdb/mmdb_selmngr.h                       |  624 ----
 mmdb/mmdb_symop.cpp                       | 1009 ------
 mmdb/mmdb_symop.h                         |  173 -
 mmdb/mmdb_tables.cpp                      |  750 ----
 mmdb/mmdb_tables.h                        |  129 -
 mmdb/mmdb_title.cpp                       | 2653 --------------
 mmdb/mmdb_title.h                         |  734 ----
 mmdb/mmdb_uddata.cpp                      |  537 ---
 mmdb/mmdb_uddata.h                        |  152 -
 mmdb/mmdb_utils.cpp                       | 1974 -----------
 mmdb/mmdb_utils.h                         |  639 ----
 mmdb/mmdb_xml.cpp                         |  954 ------
 mmdb/mmdb_xml.h                           |  148 -
 mmdb/random_n.cpp                         |  235 --
 mmdb/stream_.cpp                          |  106 -
 mmdb/stream_.h                            |  192 --
 mmdb.pc.in => mmdb2.pc.in                 |    5 +-
 {mmdb => mmdb2}/hybrid_36.cpp             |    0
 {mmdb => mmdb2}/hybrid_36.h               |    0
 mmdb2/mmdb_atom.cpp                       | 3486 +++++++++++++++++++
 mmdb2/mmdb_atom.h                         |  732 ++++
 mmdb2/mmdb_bondmngr.cpp                   |  121 +
 {mmdb => mmdb2}/mmdb_bondmngr.h           |   52 +-
 mmdb2/mmdb_chain.cpp                      | 2575 ++++++++++++++
 mmdb2/mmdb_chain.h                        |  662 ++++
 mmdb2/mmdb_cifdefs.cpp                    |  369 ++
 mmdb2/mmdb_cifdefs.h                      |  329 ++
 mmdb2/mmdb_coormngr.cpp                   | 4347 +++++++++++++++++++++++
 mmdb2/mmdb_coormngr.h                     |  959 ++++++
 mmdb2/mmdb_cryst.cpp                      | 2312 +++++++++++++
 mmdb2/mmdb_cryst.h                        |  458 +++
 mmdb2/mmdb_defs.h                         |  271 ++
 {mmdb => mmdb2}/mmdb_ficif.cpp            |   81 +-
 {mmdb => mmdb2}/mmdb_ficif.h              |   47 +-
 mmdb2/mmdb_io_file.cpp                    | 1873 ++++++++++
 mmdb2/mmdb_io_file.h                      |  301 ++
 mmdb2/mmdb_io_stream.cpp                  |  112 +
 mmdb2/mmdb_io_stream.h                    |  193 ++
 mmdb2/mmdb_machine_.cpp                   |  155 +
 mmdb/machine_.h => mmdb2/mmdb_machine_.h  |  157 +-
 mmdb2/mmdb_manager.cpp                    |  389 +++
 mmdb2/mmdb_manager.h                      |  124 +
 mmdb2/mmdb_mask.cpp                       |  240 ++
 {mmdb => mmdb2}/mmdb_mask.h               |   76 +-
 mmdb2/mmdb_math_.cpp                      |  203 ++
 mmdb2/mmdb_math_.h                        |   77 +
 mmdb2/mmdb_math_align.cpp                 | 1226 +++++++
 mmdb2/mmdb_math_align.h                   |  195 ++
 mmdb2/mmdb_math_bfgsmin.cpp               |  938 +++++
 mmdb2/mmdb_math_bfgsmin.h                 |  260 ++
 mmdb2/mmdb_math_fft.cpp                   |  338 ++
 mmdb2/mmdb_math_fft.h                     |   93 +
 mmdb2/mmdb_math_graph.cpp                 | 2461 +++++++++++++
 mmdb2/mmdb_math_graph.h                   |  494 +++
 mmdb2/mmdb_math_linalg.cpp                |  990 ++++++
 mmdb2/mmdb_math_linalg.h                  |  236 ++
 mmdb2/mmdb_math_rand.cpp                  |  241 ++
 mmdb/random_n.h => mmdb2/mmdb_math_rand.h |   79 +-
 mmdb2/mmdb_mattype.cpp                    | 2087 +++++++++++
 mmdb2/mmdb_mattype.h                      |  652 ++++
 mmdb2/mmdb_mmcif_.cpp                     | 3666 ++++++++++++++++++++
 mmdb2/mmdb_mmcif_.h                       | 2146 ++++++++++++
 mmdb2/mmdb_model.cpp                      | 5332 +++++++++++++++++++++++++++++
 mmdb2/mmdb_model.h                        | 1073 ++++++
 mmdb2/mmdb_root.cpp                       | 3054 +++++++++++++++++
 mmdb2/mmdb_root.h                         |  639 ++++
 {mmdb => mmdb2}/mmdb_rwbrook.cpp          | 1762 +++++-----
 {mmdb => mmdb2}/mmdb_rwbrook.h            |  591 ++--
 mmdb2/mmdb_selmngr.cpp                    | 3421 ++++++++++++++++++
 mmdb2/mmdb_selmngr.h                      |  634 ++++
 mmdb2/mmdb_seqsuperpose.cpp               |  366 ++
 mmdb2/mmdb_seqsuperpose.h                 |  134 +
 mmdb2/mmdb_symop.cpp                      | 1001 ++++++
 mmdb2/mmdb_symop.h                        |  168 +
 mmdb2/mmdb_tables.cpp                     |  748 ++++
 mmdb2/mmdb_tables.h                       |  127 +
 mmdb2/mmdb_title.cpp                      | 2662 ++++++++++++++
 mmdb2/mmdb_title.h                        |  696 ++++
 mmdb2/mmdb_uddata.cpp                     |  534 +++
 mmdb2/mmdb_uddata.h                       |  154 +
 mmdb2/mmdb_utils.cpp                      | 1994 +++++++++++
 mmdb2/mmdb_utils.h                        |  633 ++++
 mmdb2/mmdb_xml_.cpp                       |  986 ++++++
 mmdb2/mmdb_xml_.h                         |  162 +
 131 files changed, 62814 insertions(+), 65726 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 2f33492..209f5cc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,38 +1,34 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-lib_LTLIBRARIES = mmdb/libmmdb.la
+lib_LTLIBRARIES = mmdb2/libmmdb2.la
 
 pkginclude_HEADERS = \
-mmdb/bfgs_min.h       mmdb/mmdb_atom.h     mmdb/mmdb_ficif.h   \
-mmdb/mmdb_rwbrook.h   mmdb/mmdb_uddata.h   mmdb/file_.h        \
-mmdb/mmdb_bondmngr.h  mmdb/mmdb_file.h     mmdb/mmdb_sbase0.h  \
-mmdb/mmdb_utils.h     mmdb/linalg_.h       mmdb/mmdb_chain.h   \
-mmdb/mmdb_graph.h     mmdb/mmdb_sbase.h    mmdb/mmdb_xml.h     \
-mmdb/machine_.h       mmdb/mmdb_cifdefs.h  mmdb/mmdb_manager.h \
-mmdb/mmdb_selmngr.h   mmdb/random_n.h      mmdb/math_.h        \
-mmdb/mmdb_coormngr.h  mmdb/mmdb_mask.h     mmdb/mmdb_symop.h   \
-mmdb/stream_.h        mmdb/mattype_.h      mmdb/mmdb_cryst.h   \
-mmdb/mmdb_mmcif.h     mmdb/mmdb_tables.h   mmdb/mmdb_align.h   \
-mmdb/mmdb_defs.h      mmdb/mmdb_model.h    mmdb/mmdb_title.h   \
-mmdb/hybrid_36.h
-
-
-mmdb_libmmdb_la_SOURCES = \
-mmdb/bfgs_min.cpp     mmdb/mmdb_bondmngr.cpp mmdb/mmdb_manager.cpp    \
-mmdb/mmdb_symop.cpp   mmdb/file_.cpp         mmdb/mmdb_chain.cpp      \
-mmdb/mmdb_mask.cpp    mmdb/mmdb_tables.cpp   mmdb/linalg_.cpp         \
-mmdb/mmdb_cifdefs.cpp mmdb/mmdb_mmcif.cpp    mmdb/mmdb_title.cpp      \
-mmdb/machine_.cpp     mmdb/mmdb_coormngr.cpp mmdb/mmdb_model.cpp      \
-mmdb/mmdb_uddata.cpp  mmdb/math_.cpp         mmdb/mmdb_cryst.cpp      \
-mmdb/mmdb_rwbrook.cpp mmdb/mmdb_utils.cpp    mmdb/mattype_.cpp        \
-mmdb/mmdb_ficif.cpp   mmdb/mmdb_sbase0.cpp   mmdb/mmdb_xml.cpp        \
-mmdb/mmdb_align.cpp   mmdb/mmdb_file.cpp     mmdb/mmdb_sbase.cpp      \
-mmdb/random_n.cpp     mmdb/mmdb_atom.cpp     mmdb/mmdb_graph.cpp      \
-mmdb/mmdb_selmngr.cpp mmdb/stream_.cpp       mmdb/hybrid_36.cpp
-
-mmdb_libmmdb_la_LDFLAGS = -no-undefined
+mmdb2/hybrid_36.h		mmdb2/mmdb_io_file.h		mmdb2/mmdb_math_graph.h		mmdb2/mmdb_seqsuperpose.h \
+mmdb2/mmdb_atom.h		mmdb2/mmdb_io_stream.h		mmdb2/mmdb_math_linalg.h	mmdb2/mmdb_symop.h        \
+mmdb2/mmdb_bondmngr.h		mmdb2/mmdb_machine_.h		mmdb2/mmdb_math_rand.h		mmdb2/mmdb_tables.h       \
+mmdb2/mmdb_chain.h		mmdb2/mmdb_manager.h		mmdb2/mmdb_mattype.h		mmdb2/mmdb_title.h        \
+mmdb2/mmdb_cifdefs.h		mmdb2/mmdb_mask.h		mmdb2/mmdb_mmcif_.h		mmdb2/mmdb_uddata.h       \
+mmdb2/mmdb_coormngr.h		mmdb2/mmdb_math_.h		mmdb2/mmdb_model.h		mmdb2/mmdb_utils.h        \
+mmdb2/mmdb_cryst.h		mmdb2/mmdb_math_align.h		mmdb2/mmdb_root.h		mmdb2/mmdb_xml_.h         \
+mmdb2/mmdb_defs.h		mmdb2/mmdb_math_bfgsmin.h	mmdb2/mmdb_rwbrook.h		mmdb2/mmdb_ficif.h	  \
+mmdb2/mmdb_math_fft.h		mmdb2/mmdb_selmngr.h
+
+
+mmdb2_libmmdb2_la_SOURCES = \
+mmdb2/hybrid_36.cpp		mmdb2/mmdb_io_stream.cpp	mmdb2/mmdb_math_linalg.cpp	mmdb2/mmdb_symop.cpp      \
+mmdb2/mmdb_atom.cpp		mmdb2/mmdb_machine_.cpp		mmdb2/mmdb_math_rand.cpp	mmdb2/mmdb_tables.cpp     \
+mmdb2/mmdb_bondmngr.cpp		mmdb2/mmdb_manager.cpp		mmdb2/mmdb_mattype.cpp		mmdb2/mmdb_title.cpp      \
+mmdb2/mmdb_chain.cpp		mmdb2/mmdb_mask.cpp		mmdb2/mmdb_mmcif_.cpp		mmdb2/mmdb_uddata.cpp     \
+mmdb2/mmdb_cifdefs.cpp		mmdb2/mmdb_math_.cpp		mmdb2/mmdb_model.cpp		mmdb2/mmdb_utils.cpp      \
+mmdb2/mmdb_coormngr.cpp		mmdb2/mmdb_math_align.cpp	mmdb2/mmdb_root.cpp		mmdb2/mmdb_xml_.cpp       \
+mmdb2/mmdb_cryst.cpp		mmdb2/mmdb_math_bfgsmin.cpp	mmdb2/mmdb_rwbrook.cpp		mmdb2/mmdb_ficif.cpp	  \
+mmdb2/mmdb_math_fft.cpp		mmdb2/mmdb_selmngr.cpp		mmdb2/mmdb_io_file.cpp		mmdb2/mmdb_math_graph.cpp \
+mmdb2/mmdb_seqsuperpose.cpp
+
+mmdb2_libmmdb2_la_LDFLAGS = -no-undefined
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = mmdb.pc
+pkgconfig_DATA = mmdb2.pc
+
 
diff --git a/Makefile.in b/Makefile.in
index 6e8eade..bb9dde5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.12.2 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2012 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -17,23 +17,51 @@
 
 
 VPATH = @srcdir@
-am__make_dryrun = \
-  { \
-    am__dry=no; \
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
     case $$MAKEFLAGS in \
       *\\[\ \	]*) \
-        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
-          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
-      *) \
-        for am__flg in $$MAKEFLAGS; do \
-          case $$am__flg in \
-            *=*|--*) ;; \
-            *n*) am__dry=yes; break;; \
-          esac; \
-        done;; \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
     esac; \
-    test $$am__dry = yes; \
-  }
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
 pkgdatadir = $(datadir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
@@ -53,19 +81,19 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = .
-DIST_COMMON = README $(am__configure_deps) $(pkginclude_HEADERS) \
-	$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
-	$(srcdir)/config.h.in $(srcdir)/mmdb.pc.in \
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/configure $(am__configure_deps) \
+	$(srcdir)/config.h.in $(srcdir)/mmdb2.pc.in \
+	$(top_srcdir)/build-aux/depcomp $(pkginclude_HEADERS) AUTHORS \
+	COPYING COPYING.LESSER INSTALL README build-aux/ar-lib \
+	build-aux/config.guess build-aux/config.sub build-aux/depcomp \
+	build-aux/install-sh build-aux/missing build-aux/ltmain.sh \
 	$(top_srcdir)/build-aux/ar-lib \
 	$(top_srcdir)/build-aux/config.guess \
 	$(top_srcdir)/build-aux/config.sub \
-	$(top_srcdir)/build-aux/depcomp \
 	$(top_srcdir)/build-aux/install-sh \
 	$(top_srcdir)/build-aux/ltmain.sh \
-	$(top_srcdir)/build-aux/missing $(top_srcdir)/configure \
-	AUTHORS COPYING COPYING.LESSER INSTALL build-aux/ar-lib \
-	build-aux/config.guess build-aux/config.sub build-aux/depcomp \
-	build-aux/install-sh build-aux/ltmain.sh build-aux/missing
+	$(top_srcdir)/build-aux/missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
 	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -77,7 +105,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES = mmdb.pc
+CONFIG_CLEAN_FILES = mmdb2.pc
 CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
@@ -109,28 +137,31 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
 	"$(DESTDIR)$(pkgincludedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES)
-mmdb_libmmdb_la_LIBADD =
+mmdb2_libmmdb2_la_LIBADD =
 am__dirstamp = $(am__leading_dot)dirstamp
-am_mmdb_libmmdb_la_OBJECTS = mmdb/bfgs_min.lo mmdb/mmdb_bondmngr.lo \
-	mmdb/mmdb_manager.lo mmdb/mmdb_symop.lo mmdb/file_.lo \
-	mmdb/mmdb_chain.lo mmdb/mmdb_mask.lo mmdb/mmdb_tables.lo \
-	mmdb/linalg_.lo mmdb/mmdb_cifdefs.lo mmdb/mmdb_mmcif.lo \
-	mmdb/mmdb_title.lo mmdb/machine_.lo mmdb/mmdb_coormngr.lo \
-	mmdb/mmdb_model.lo mmdb/mmdb_uddata.lo mmdb/math_.lo \
-	mmdb/mmdb_cryst.lo mmdb/mmdb_rwbrook.lo mmdb/mmdb_utils.lo \
-	mmdb/mattype_.lo mmdb/mmdb_ficif.lo mmdb/mmdb_sbase0.lo \
-	mmdb/mmdb_xml.lo mmdb/mmdb_align.lo mmdb/mmdb_file.lo \
-	mmdb/mmdb_sbase.lo mmdb/random_n.lo mmdb/mmdb_atom.lo \
-	mmdb/mmdb_graph.lo mmdb/mmdb_selmngr.lo mmdb/stream_.lo \
-	mmdb/hybrid_36.lo
-mmdb_libmmdb_la_OBJECTS = $(am_mmdb_libmmdb_la_OBJECTS)
+am_mmdb2_libmmdb2_la_OBJECTS = mmdb2/hybrid_36.lo \
+	mmdb2/mmdb_io_stream.lo mmdb2/mmdb_math_linalg.lo \
+	mmdb2/mmdb_symop.lo mmdb2/mmdb_atom.lo mmdb2/mmdb_machine_.lo \
+	mmdb2/mmdb_math_rand.lo mmdb2/mmdb_tables.lo \
+	mmdb2/mmdb_bondmngr.lo mmdb2/mmdb_manager.lo \
+	mmdb2/mmdb_mattype.lo mmdb2/mmdb_title.lo mmdb2/mmdb_chain.lo \
+	mmdb2/mmdb_mask.lo mmdb2/mmdb_mmcif_.lo mmdb2/mmdb_uddata.lo \
+	mmdb2/mmdb_cifdefs.lo mmdb2/mmdb_math_.lo mmdb2/mmdb_model.lo \
+	mmdb2/mmdb_utils.lo mmdb2/mmdb_coormngr.lo \
+	mmdb2/mmdb_math_align.lo mmdb2/mmdb_root.lo mmdb2/mmdb_xml_.lo \
+	mmdb2/mmdb_cryst.lo mmdb2/mmdb_math_bfgsmin.lo \
+	mmdb2/mmdb_rwbrook.lo mmdb2/mmdb_ficif.lo \
+	mmdb2/mmdb_math_fft.lo mmdb2/mmdb_selmngr.lo \
+	mmdb2/mmdb_io_file.lo mmdb2/mmdb_math_graph.lo \
+	mmdb2/mmdb_seqsuperpose.lo
+mmdb2_libmmdb2_la_OBJECTS = $(am_mmdb2_libmmdb2_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-mmdb_libmmdb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+mmdb2_libmmdb2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
-	$(AM_CXXFLAGS) $(CXXFLAGS) $(mmdb_libmmdb_la_LDFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS) $(mmdb2_libmmdb2_la_LDFLAGS) \
 	$(LDFLAGS) -o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
@@ -166,8 +197,8 @@ AM_V_CXXLD = $(am__v_CXXLD_ at AM_V@)
 am__v_CXXLD_ = $(am__v_CXXLD_ at AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
-SOURCES = $(mmdb_libmmdb_la_SOURCES)
-DIST_SOURCES = $(mmdb_libmmdb_la_SOURCES)
+SOURCES = $(mmdb2_libmmdb2_la_SOURCES)
+DIST_SOURCES = $(mmdb2_libmmdb2_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -175,6 +206,24 @@ am__can_run_installinfo = \
   esac
 DATA = $(pkgconfig_DATA)
 HEADERS = $(pkginclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
@@ -318,37 +367,32 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I m4
-lib_LTLIBRARIES = mmdb/libmmdb.la
+lib_LTLIBRARIES = mmdb2/libmmdb2.la
 pkginclude_HEADERS = \
-mmdb/bfgs_min.h       mmdb/mmdb_atom.h     mmdb/mmdb_ficif.h   \
-mmdb/mmdb_rwbrook.h   mmdb/mmdb_uddata.h   mmdb/file_.h        \
-mmdb/mmdb_bondmngr.h  mmdb/mmdb_file.h     mmdb/mmdb_sbase0.h  \
-mmdb/mmdb_utils.h     mmdb/linalg_.h       mmdb/mmdb_chain.h   \
-mmdb/mmdb_graph.h     mmdb/mmdb_sbase.h    mmdb/mmdb_xml.h     \
-mmdb/machine_.h       mmdb/mmdb_cifdefs.h  mmdb/mmdb_manager.h \
-mmdb/mmdb_selmngr.h   mmdb/random_n.h      mmdb/math_.h        \
-mmdb/mmdb_coormngr.h  mmdb/mmdb_mask.h     mmdb/mmdb_symop.h   \
-mmdb/stream_.h        mmdb/mattype_.h      mmdb/mmdb_cryst.h   \
-mmdb/mmdb_mmcif.h     mmdb/mmdb_tables.h   mmdb/mmdb_align.h   \
-mmdb/mmdb_defs.h      mmdb/mmdb_model.h    mmdb/mmdb_title.h   \
-mmdb/hybrid_36.h
-
-mmdb_libmmdb_la_SOURCES = \
-mmdb/bfgs_min.cpp     mmdb/mmdb_bondmngr.cpp mmdb/mmdb_manager.cpp    \
-mmdb/mmdb_symop.cpp   mmdb/file_.cpp         mmdb/mmdb_chain.cpp      \
-mmdb/mmdb_mask.cpp    mmdb/mmdb_tables.cpp   mmdb/linalg_.cpp         \
-mmdb/mmdb_cifdefs.cpp mmdb/mmdb_mmcif.cpp    mmdb/mmdb_title.cpp      \
-mmdb/machine_.cpp     mmdb/mmdb_coormngr.cpp mmdb/mmdb_model.cpp      \
-mmdb/mmdb_uddata.cpp  mmdb/math_.cpp         mmdb/mmdb_cryst.cpp      \
-mmdb/mmdb_rwbrook.cpp mmdb/mmdb_utils.cpp    mmdb/mattype_.cpp        \
-mmdb/mmdb_ficif.cpp   mmdb/mmdb_sbase0.cpp   mmdb/mmdb_xml.cpp        \
-mmdb/mmdb_align.cpp   mmdb/mmdb_file.cpp     mmdb/mmdb_sbase.cpp      \
-mmdb/random_n.cpp     mmdb/mmdb_atom.cpp     mmdb/mmdb_graph.cpp      \
-mmdb/mmdb_selmngr.cpp mmdb/stream_.cpp       mmdb/hybrid_36.cpp
-
-mmdb_libmmdb_la_LDFLAGS = -no-undefined
+mmdb2/hybrid_36.h		mmdb2/mmdb_io_file.h		mmdb2/mmdb_math_graph.h		mmdb2/mmdb_seqsuperpose.h \
+mmdb2/mmdb_atom.h		mmdb2/mmdb_io_stream.h		mmdb2/mmdb_math_linalg.h	mmdb2/mmdb_symop.h        \
+mmdb2/mmdb_bondmngr.h		mmdb2/mmdb_machine_.h		mmdb2/mmdb_math_rand.h		mmdb2/mmdb_tables.h       \
+mmdb2/mmdb_chain.h		mmdb2/mmdb_manager.h		mmdb2/mmdb_mattype.h		mmdb2/mmdb_title.h        \
+mmdb2/mmdb_cifdefs.h		mmdb2/mmdb_mask.h		mmdb2/mmdb_mmcif_.h		mmdb2/mmdb_uddata.h       \
+mmdb2/mmdb_coormngr.h		mmdb2/mmdb_math_.h		mmdb2/mmdb_model.h		mmdb2/mmdb_utils.h        \
+mmdb2/mmdb_cryst.h		mmdb2/mmdb_math_align.h		mmdb2/mmdb_root.h		mmdb2/mmdb_xml_.h         \
+mmdb2/mmdb_defs.h		mmdb2/mmdb_math_bfgsmin.h	mmdb2/mmdb_rwbrook.h		mmdb2/mmdb_ficif.h	  \
+mmdb2/mmdb_math_fft.h		mmdb2/mmdb_selmngr.h
+
+mmdb2_libmmdb2_la_SOURCES = \
+mmdb2/hybrid_36.cpp		mmdb2/mmdb_io_stream.cpp	mmdb2/mmdb_math_linalg.cpp	mmdb2/mmdb_symop.cpp      \
+mmdb2/mmdb_atom.cpp		mmdb2/mmdb_machine_.cpp		mmdb2/mmdb_math_rand.cpp	mmdb2/mmdb_tables.cpp     \
+mmdb2/mmdb_bondmngr.cpp		mmdb2/mmdb_manager.cpp		mmdb2/mmdb_mattype.cpp		mmdb2/mmdb_title.cpp      \
+mmdb2/mmdb_chain.cpp		mmdb2/mmdb_mask.cpp		mmdb2/mmdb_mmcif_.cpp		mmdb2/mmdb_uddata.cpp     \
+mmdb2/mmdb_cifdefs.cpp		mmdb2/mmdb_math_.cpp		mmdb2/mmdb_model.cpp		mmdb2/mmdb_utils.cpp      \
+mmdb2/mmdb_coormngr.cpp		mmdb2/mmdb_math_align.cpp	mmdb2/mmdb_root.cpp		mmdb2/mmdb_xml_.cpp       \
+mmdb2/mmdb_cryst.cpp		mmdb2/mmdb_math_bfgsmin.cpp	mmdb2/mmdb_rwbrook.cpp		mmdb2/mmdb_ficif.cpp	  \
+mmdb2/mmdb_math_fft.cpp		mmdb2/mmdb_selmngr.cpp		mmdb2/mmdb_io_file.cpp		mmdb2/mmdb_math_graph.cpp \
+mmdb2/mmdb_seqsuperpose.cpp
+
+mmdb2_libmmdb2_la_LDFLAGS = -no-undefined
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = mmdb.pc
+pkgconfig_DATA = mmdb2.pc
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -403,8 +447,9 @@ $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
 
 distclean-hdr:
 	-rm -f config.h stamp-h1
-mmdb.pc: $(top_builddir)/config.status $(srcdir)/mmdb.pc.in
+mmdb2.pc: $(top_builddir)/config.status $(srcdir)/mmdb2.pc.in
 	cd $(top_builddir) && $(SHELL) ./config.status $@
+
 install-libLTLIBRARIES: $(lib_LTLIBRARIES)
 	@$(NORMAL_INSTALL)
 	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
@@ -439,109 +484,123 @@ clean-libLTLIBRARIES:
 	  echo rm -f $${locs}; \
 	  rm -f $${locs}; \
 	}
-mmdb/$(am__dirstamp):
-	@$(MKDIR_P) mmdb
-	@: > mmdb/$(am__dirstamp)
-mmdb/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) mmdb/$(DEPDIR)
-	@: > mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/bfgs_min.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_bondmngr.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_manager.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_symop.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/file_.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_chain.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_mask.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_tables.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/linalg_.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_cifdefs.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_mmcif.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_title.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/machine_.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_coormngr.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_model.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_uddata.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/math_.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_cryst.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_rwbrook.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_utils.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mattype_.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_ficif.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_sbase0.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_xml.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_align.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_file.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_sbase.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/random_n.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_atom.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_graph.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/mmdb_selmngr.lo: mmdb/$(am__dirstamp) \
-	mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/stream_.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/hybrid_36.lo: mmdb/$(am__dirstamp) mmdb/$(DEPDIR)/$(am__dirstamp)
-mmdb/libmmdb.la: $(mmdb_libmmdb_la_OBJECTS) $(mmdb_libmmdb_la_DEPENDENCIES) $(EXTRA_mmdb_libmmdb_la_DEPENDENCIES) mmdb/$(am__dirstamp)
-	$(AM_V_CXXLD)$(mmdb_libmmdb_la_LINK) -rpath $(libdir) $(mmdb_libmmdb_la_OBJECTS) $(mmdb_libmmdb_la_LIBADD) $(LIBS)
+mmdb2/$(am__dirstamp):
+	@$(MKDIR_P) mmdb2
+	@: > mmdb2/$(am__dirstamp)
+mmdb2/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) mmdb2/$(DEPDIR)
+	@: > mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/hybrid_36.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_io_stream.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_linalg.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_symop.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_atom.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_machine_.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_rand.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_tables.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_bondmngr.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_manager.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_mattype.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_title.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_chain.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_mask.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_mmcif_.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_uddata.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_cifdefs.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_model.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_utils.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_coormngr.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_align.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_root.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_xml_.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_cryst.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_bfgsmin.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_rwbrook.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_ficif.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_fft.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_selmngr.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_io_file.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_math_graph.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+mmdb2/mmdb_seqsuperpose.lo: mmdb2/$(am__dirstamp) \
+	mmdb2/$(DEPDIR)/$(am__dirstamp)
+
+mmdb2/libmmdb2.la: $(mmdb2_libmmdb2_la_OBJECTS) $(mmdb2_libmmdb2_la_DEPENDENCIES) $(EXTRA_mmdb2_libmmdb2_la_DEPENDENCIES) mmdb2/$(am__dirstamp)
+	$(AM_V_CXXLD)$(mmdb2_libmmdb2_la_LINK) -rpath $(libdir) $(mmdb2_libmmdb2_la_OBJECTS) $(mmdb2_libmmdb2_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
-	-rm -f mmdb/*.$(OBJEXT)
-	-rm -f mmdb/*.lo
+	-rm -f mmdb2/*.$(OBJEXT)
+	-rm -f mmdb2/*.lo
 
 distclean-compile:
 	-rm -f *.tab.c
 
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/bfgs_min.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/file_.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/hybrid_36.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/linalg_.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/machine_.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/math_.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mattype_.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_align.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_atom.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_bondmngr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_chain.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_cifdefs.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_coormngr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_cryst.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_ficif.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_file.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_graph.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_manager.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_mask.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_mmcif.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_model.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_rwbrook.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_sbase.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_sbase0.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_selmngr.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_symop.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_tables.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_title.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_uddata.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_utils.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/mmdb_xml.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/random_n.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at mmdb/$(DEPDIR)/stream_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/hybrid_36.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_atom.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_bondmngr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_chain.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_cifdefs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_coormngr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_cryst.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_ficif.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_io_file.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_io_stream.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_machine_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_manager.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_mask.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_align.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_bfgsmin.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_fft.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_graph.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_linalg.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_math_rand.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_mattype.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_mmcif_.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_model.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_root.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_rwbrook.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_selmngr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_seqsuperpose.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_symop.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_tables.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_title.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_uddata.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_utils.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at mmdb2/$(DEPDIR)/mmdb_xml_.Plo at am__quote@
 
 .cpp.o:
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -572,7 +631,7 @@ mostlyclean-libtool:
 
 clean-libtool:
 	-rm -rf .libs _libs
-	-rm -rf mmdb/.libs mmdb/_libs
+	-rm -rf mmdb2/.libs mmdb2/_libs
 
 distclean-libtool:
 	-rm -f libtool config.lt
@@ -619,26 +678,15 @@ uninstall-pkgincludeHEADERS:
 	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
 	dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
 
-ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
-	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
-	unique=`for i in $$list; do \
-	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
-	      END { if (nonempty) { for (i in files) print i; }; }'`; \
-	mkid -fID $$unique
-tags: TAGS
-
-TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
-		$(TAGS_FILES) $(LISP)
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
 	set x; \
 	here=`pwd`; \
-	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
-	unique=`for i in $$list; do \
-	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
-	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	$(am__define_uniq_tagged_files); \
 	shift; \
 	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
 	  test -n "$$unique" || unique=$$empty_fix; \
@@ -650,15 +698,11 @@ TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
 	      $$unique; \
 	  fi; \
 	fi
-ctags: CTAGS
-CTAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
-		$(TAGS_FILES) $(LISP)
-	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
-	unique=`for i in $$list; do \
-	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-	  done | \
-	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
-	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
 	test -z "$(CTAGS_ARGS)$$unique" \
 	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
 	     $$unique
@@ -667,18 +711,16 @@ GTAGS:
 	here=`$(am__cd) $(top_builddir) && pwd` \
 	  && $(am__cd) $(top_srcdir) \
 	  && gtags -i $(GTAGS_ARGS) "$$here"
-
 cscope: cscope.files
 	test ! -s cscope.files \
 	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
-
 clean-cscope:
 	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-am
 
-cscope.files: clean-cscope  cscopelist
-
-cscopelist:  $(HEADERS) $(SOURCES) $(LISP)
-	list='$(SOURCES) $(HEADERS) $(LISP)'; \
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
 	case "$(srcdir)" in \
 	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
 	  *) sdir=$(subdir)/$(srcdir) ;; \
@@ -787,9 +829,9 @@ distcheck: dist
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
-	chmod -R a-w $(distdir); chmod u+w $(distdir)
-	mkdir $(distdir)/_build
-	mkdir $(distdir)/_inst
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_inst
 	chmod a-w $(distdir)
 	test -d $(distdir)/_build || exit 0; \
 	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
@@ -884,8 +926,8 @@ clean-generic:
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-	-rm -f mmdb/$(DEPDIR)/$(am__dirstamp)
-	-rm -f mmdb/$(am__dirstamp)
+	-rm -f mmdb2/$(DEPDIR)/$(am__dirstamp)
+	-rm -f mmdb2/$(am__dirstamp)
 
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
@@ -897,7 +939,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
 
 distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf mmdb/$(DEPDIR)
+	-rm -rf mmdb2/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-libtool distclean-tags
@@ -945,7 +987,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf mmdb/$(DEPDIR)
+	-rm -rf mmdb2/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
@@ -967,22 +1009,22 @@ uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgconfigDATA \
 
 .MAKE: all install-am install-strip
 
-.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
 	clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \
-	cscope cscopelist ctags dist dist-all dist-bzip2 dist-gzip \
-	dist-lzip dist-shar dist-tarZ dist-xz dist-zip distcheck \
-	distclean distclean-compile distclean-generic distclean-hdr \
-	distclean-libtool distclean-tags distcleancheck distdir \
-	distuninstallcheck dvi dvi-am html html-am info info-am \
-	install install-am install-data install-data-am install-dvi \
-	install-dvi-am install-exec install-exec-am install-html \
-	install-html-am install-info install-info-am \
+	cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+	dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+	distcheck distclean distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags distcleancheck \
+	distdir distuninstallcheck dvi dvi-am html html-am info \
+	info-am install install-am install-data install-data-am \
+	install-dvi install-dvi-am install-exec install-exec-am \
+	install-html install-html-am install-info install-info-am \
 	install-libLTLIBRARIES install-man install-pdf install-pdf-am \
 	install-pkgconfigDATA install-pkgincludeHEADERS install-ps \
 	install-ps-am install-strip installcheck installcheck-am \
 	installdirs maintainer-clean maintainer-clean-generic \
 	mostlyclean mostlyclean-compile mostlyclean-generic \
-	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
 	uninstall-am uninstall-libLTLIBRARIES uninstall-pkgconfigDATA \
 	uninstall-pkgincludeHEADERS
 
diff --git a/README b/README
index 22a8101..703606e 100755
--- a/README
+++ b/README
@@ -1,33 +1,94 @@
+
+           CCP4 Coordinate Library: support of coordinate-related
+           functionality in protein crystallography applications.
+
+                        Version 1.05 from 26.03.2004
+
+                    Copyright (C) Eugene Krissinel 2004.
+
+============================================================================
+
+This file contains:
+
+   1. License agreement
+   2. List of incompatibilities with earlier versions. Please read
+      this carefully if you update your version of the Library.
+
+
+=======================
+1. LICENSE AGREEMENT.
+=======================
+
+     This library is free software and is distributed under the terms
+   and conditions of the CCP4 licence agreement as `Part 0' (Annex 2)
+   software, which is version 2.1 of the GNU Lesser General Public
+   Licence (LGPL) with the following additional clause:
+
+      `You may also combine or link a "work that uses the Library"
+      to produce a work containing portions of the Library, and
+      distribute that work under terms of your choice, provided that
+      you give prominent notice with each copy of the work that the
+      specified version of the Library is used in it, and that you
+      include or provide public access to the complete corresponding
+      machine-readable source code for the Library including whatever
+      changes were used in the work. (i.e. If you make changes to the
+      Library you must distribute those, but you do not need to
+      distribute source or object code to those portions of the work
+      not covered by this licence.)'
+
+   Note that this clause grants an additional right and does not
+   impose any additional restriction, and so does not affect
+   compatibility with the GNU General Public Licence (GPL). If you
+   wish to negotiate other terms, please contact the maintainer.
+
+   You can redistribute it and/or modify the library 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.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY 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 CCP4 licence and/or GNU
+   Lesser General Public License along with this library; if not,
+   write to the CCP4 Secretary, Daresbury Laboratory, Warrington
+   WA4 4AD, UK. The GNU Lesser General Public can also be obtained
+   by writing to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
 ====================================================
-   KNOWN INCOMPATIBILITIES WITH PREVIOUS VERSIONS
+2. KNOWN INCOMPATIBILITIES WITH PREVIOUS VERSIONS
 ====================================================
 
 --------------------------
-Version 1.05 (26.03.2004)
+Version 2.0.1 (03.02.2014)
 --------------------------
 
-1. CAtom::GetBonds ( RPSAtomBond AtomBond, int & nAtomBonds );
+1. Namespacing
 
-now returns a pointer to internal list of bonded atoms. Therefore
-application MUST NEITHER attempt to deallocate AtomBond obtained from
-this function NOR modify it (doing so will cause crash). This is in
-difference of previous versions where deallocation of AtomBond was
-explicitely required.
+Versions 2.x is namespaced throughout. The following namespaces are introduced:
 
-2. CAtom::GetBonds ( RPSAtomBondI AtomBondI, int & nAtomBonds );
+mmdb
+mmdb::io
+mmdb::math
+mmdb::mmcif
+mmdb::xml
+mmdb::machine
 
-on contrary, now returns an allocated instance of the atom's bond list.
-If AtomBondI is not NULL on input, the function attempts to deallocate
-it (which will cause crash if you feed uninitialized non-NULL AtomBondI
-into the function). Application is responsible for deallocation of
-AtomBondI when appropriate.
+2. Object renaming
 
-3. CAtom::GetBonds ( PSAtomBondI AtomBondI, int & nAtomBonds, int maxlength );
+As a general rule, prefixes  'CMMDB' and 'C' from object names in MMDB versions 1.x
+have been removed, so that, e.g.,
 
-is a new function for pre-allocated AtomBondI[0..maxlength]. Application
-is responsible for allocation and deallocation of AtomBondI.
+CMMDBManager    is now      mmdb::Manager
+CAtom           is now      mmdb::Atom
+CFile           is now      mmdb::io::File
 
-4. CAtom::GetBonds ( RPSAtomBond AtomBond, int & nAtomBonds, int maxlength );
+and so forth.
 
-removed as there is no need in it in view of change #1 above.
 
diff --git a/aclocal.m4 b/aclocal.m4
index c15146a..1efe2e1 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.12.2 -*- Autoconf -*-
+# generated automatically by aclocal 1.13.4 -*- Autoconf -*-
 
-# Copyright (C) 1996-2012 Free Software Foundation, Inc.
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -11,6 +11,7 @@
 # even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 # PARTICULAR PURPOSE.
 
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
@@ -19,24 +20,22 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
-# Copyright (C) 2002-2012 Free Software Foundation, Inc.
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 8
-
 # AM_AUTOMAKE_VERSION(VERSION)
 # ----------------------------
 # Automake X.Y traces this macro to ensure aclocal.m4 has been
 # generated from the m4 files accompanying Automake X.Y.
 # (This private macro should not be called outside this file.)
 AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.12'
+[am__api_version='1.13'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.12.2], [],
+m4_if([$1], [1.13.4], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -52,19 +51,17 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.12.2])dnl
+[AM_AUTOMAKE_VERSION([1.13.4])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
-# Copyright (C) 2011-2012 Free Software Foundation, Inc.
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 1
-
 # AM_PROG_AR([ACT-IF-FAIL])
 # -------------------------
 # Try to determine the archiver interface, and trigger the ar-lib wrapper
@@ -120,14 +117,12 @@ AC_SUBST([AR])dnl
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2012 Free Software Foundation, Inc.
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 2
-
 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
 # $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
 # '$srcdir', '$srcdir/..', or '$srcdir/../..'.
@@ -175,14 +170,12 @@ am_aux_dir=`cd $ac_aux_dir && pwd`
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2012 Free Software Foundation, Inc.
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 10
-
 # AM_CONDITIONAL(NAME, SHELL-CONDITION)
 # -------------------------------------
 # Define a conditional.
@@ -208,13 +201,12 @@ AC_CONFIG_COMMANDS_PRE(
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2012 Free Software Foundation, Inc.
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 17
 
 # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
 # written in clear, in which case automake, when reading aclocal.m4,
@@ -400,19 +392,18 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2012 Free Software Foundation, Inc.
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 6
 
 # _AM_OUTPUT_DEPENDENCY_COMMANDS
 # ------------------------------
 AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
 [{
-  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # Older Autoconf quotes --file arguments for eval, but not when files
   # are listed without --file.  Let's play safe and only enable the eval
   # if we detect the quoting.
   case $CONFIG_FILES in
@@ -441,7 +432,7 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
     DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
     test -z "$DEPDIR" && continue
     am__include=`sed -n 's/^am__include = //p' < "$mf"`
-    test -z "am__include" && continue
+    test -z "$am__include" && continue
     am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
     # Find all dependency output files, they are included files with
     # $(DEPDIR) in their names.  We invoke sed twice because it is the
@@ -477,14 +468,12 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2012 Free Software Foundation, Inc.
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 19
-
 # This macro actually does too much.  Some checks are only needed if
 # your package does certain things.  But this isn't really a big deal.
 
@@ -500,7 +489,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 # arguments mandatory, and then we can depend on a new Autoconf
 # release and drop the old call support.
 AC_DEFUN([AM_INIT_AUTOMAKE],
-[AC_PREREQ([2.62])dnl
+[AC_PREREQ([2.65])dnl
 dnl Autoconf wants to disallow AM_ names.  We explicitly allow
 dnl the ones we care about.
 m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
@@ -530,8 +519,7 @@ AC_SUBST([CYGPATH_W])
 dnl Distinguish between old-style and new-style calls.
 m4_ifval([$2],
 [AC_DIAGNOSE([obsolete],
-[$0: two- and three-arguments forms are deprecated.  For more info, see:
-http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_INIT_AUTOMAKE-invocation])
+             [$0: two- and three-arguments forms are deprecated.])
 m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
  AC_SUBST([PACKAGE], [$1])dnl
  AC_SUBST([VERSION], [$2])],
@@ -585,18 +573,15 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJC],
 		  [_AM_DEPENDENCIES([OBJC])],
 		  [m4_define([AC_PROG_OBJC],
 			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
-dnl Support for Objective C++ was only introduced in Autoconf 2.65,
-dnl but we still cater to Autoconf 2.62.
-m4_ifdef([AC_PROG_OBJCXX],
-[AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
 		  [_AM_DEPENDENCIES([OBJCXX])],
 		  [m4_define([AC_PROG_OBJCXX],
-			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])])dnl
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
 ])
-_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
-dnl The 'parallel-tests' driver may need to know about EXEEXT, so add the
-dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This macro
-dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
 AC_CONFIG_COMMANDS_PRE(dnl
 [m4_provide_if([_AM_COMPILER_EXEEXT],
   [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
@@ -630,14 +615,12 @@ for _am_header in $config_headers :; do
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2012 Free Software Foundation, Inc.
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 8
-
 # AM_PROG_INSTALL_SH
 # ------------------
 # Define $install_sh.
@@ -653,14 +636,12 @@ if test x"${install_sh}" != xset; then
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2012 Free Software Foundation, Inc.
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 2
-
 # Check whether the underlying file-system supports filenames
 # with a leading dot.  For instance MS-DOS doesn't.
 AC_DEFUN([AM_SET_LEADING_DOT],
@@ -677,14 +658,12 @@ AC_SUBST([am__leading_dot])])
 # Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
 # From Jim Meyering
 
-# Copyright (C) 1996-2012 Free Software Foundation, Inc.
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 7
-
 # AM_MAINTAINER_MODE([DEFAULT-MODE])
 # ----------------------------------
 # Control maintainer-specific portions of Makefiles.
@@ -712,18 +691,14 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
 ]
 )
 
-AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
-
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2012 Free Software Foundation, Inc.
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 5
-
 # AM_MAKE_INCLUDE()
 # -----------------
 # Check to see how make treats includes.
@@ -768,14 +743,12 @@ rm -f confinc confmf
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2012 Free Software Foundation, Inc.
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 7
-
 # AM_MISSING_PROG(NAME, PROGRAM)
 # ------------------------------
 AC_DEFUN([AM_MISSING_PROG],
@@ -783,11 +756,10 @@ AC_DEFUN([AM_MISSING_PROG],
 $1=${$1-"${am_missing_run}$2"}
 AC_SUBST($1)])
 
-
 # AM_MISSING_HAS_RUN
 # ------------------
-# Define MISSING if not defined so far and test if it supports --run.
-# If it does, set am_missing_run to use it, otherwise, to nothing.
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
 AC_DEFUN([AM_MISSING_HAS_RUN],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
 AC_REQUIRE_AUX_FILE([missing])dnl
@@ -800,8 +772,8 @@ if test x"${MISSING+set}" != xset; then
   esac
 fi
 # Use eval to expand $SHELL
-if eval "$MISSING --run true"; then
-  am_missing_run="$MISSING --run "
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
 else
   am_missing_run=
   AC_MSG_WARN(['missing' script is too old or missing])
@@ -810,14 +782,12 @@ fi
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2012 Free Software Foundation, Inc.
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 6
-
 # _AM_MANGLE_OPTION(NAME)
 # -----------------------
 AC_DEFUN([_AM_MANGLE_OPTION],
@@ -843,14 +813,12 @@ AC_DEFUN([_AM_IF_OPTION],
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2012 Free Software Foundation, Inc.
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 9
-
 # AM_SANITY_CHECK
 # ---------------
 AC_DEFUN([AM_SANITY_CHECK],
@@ -926,14 +894,12 @@ AC_CONFIG_COMMANDS_PRE(
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2012 Free Software Foundation, Inc.
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 3
-
 # AM_SILENT_RULES([DEFAULT])
 # --------------------------
 # Enable less verbose build rules; with the default set to DEFAULT
@@ -988,14 +954,12 @@ AC_SUBST([AM_BACKSLASH])dnl
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2012 Free Software Foundation, Inc.
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 2
-
 # AM_PROG_INSTALL_STRIP
 # ---------------------
 # One issue with vendor 'install' (even GNU) is that you can't
@@ -1018,14 +982,12 @@ fi
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2012 Free Software Foundation, Inc.
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 3
-
 # _AM_SUBST_NOTMAKE(VARIABLE)
 # ---------------------------
 # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
@@ -1039,14 +1001,12 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2012 Free Software Foundation, Inc.
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 3
-
 # _AM_PROG_TAR(FORMAT)
 # --------------------
 # Check how to create a tarball in format FORMAT.
@@ -1060,76 +1020,114 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 # Substitute a variable $(am__untar) that extract such
 # a tarball read from stdin.
 #     $(am__untar) < result.tar
+#
 AC_DEFUN([_AM_PROG_TAR],
 [# Always define AMTAR for backward compatibility.  Yes, it's still used
 # in the wild :-(  We should find a proper way to deprecate it ...
 AC_SUBST([AMTAR], ['$${TAR-tar}'])
-m4_if([$1], [v7],
-     [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
-     [m4_case([$1], [ustar],, [pax],,
-              [m4_fatal([Unknown tar format])])
-AC_MSG_CHECKING([how to create a $1 tar archive])
-# Loop over all known methods to create a tar archive until one works.
+
+# We'll loop over all known methods to create a tar archive until one works.
 _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
-_am_tools=${am_cv_prog_tar_$1-$_am_tools}
-# Do not fold the above two line into one, because Tru64 sh and
-# Solaris sh will not grok spaces in the rhs of '-'.
-for _am_tool in $_am_tools
-do
-  case $_am_tool in
-  gnutar)
-    for _am_tar in tar gnutar gtar;
-    do
-      AM_RUN_LOG([$_am_tar --version]) && break
-    done
-    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
-    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
-    am__untar="$_am_tar -xf -"
-    ;;
-  plaintar)
-    # Must skip GNU tar: if it does not support --format= it doesn't create
-    # ustar tarball either.
-    (tar --version) >/dev/null 2>&1 && continue
-    am__tar='tar chf - "$$tardir"'
-    am__tar_='tar chf - "$tardir"'
-    am__untar='tar xf -'
-    ;;
-  pax)
-    am__tar='pax -L -x $1 -w "$$tardir"'
-    am__tar_='pax -L -x $1 -w "$tardir"'
-    am__untar='pax -r'
-    ;;
-  cpio)
-    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
-    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
-    am__untar='cpio -i -H $1 -d'
-    ;;
-  none)
-    am__tar=false
-    am__tar_=false
-    am__untar=false
-    ;;
-  esac
 
-  # If the value was cached, stop now.  We just wanted to have am__tar
-  # and am__untar set.
-  test -n "${am_cv_prog_tar_$1}" && break
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
 
-  # tar/untar a dummy directory, and stop if the command works
-  rm -rf conftest.dir
-  mkdir conftest.dir
-  echo GrepMe > conftest.dir/file
-  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
   rm -rf conftest.dir
-  if test -s conftest.tar; then
-    AM_RUN_LOG([$am__untar <conftest.tar])
-    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
-  fi
-done
-rm -rf conftest.dir
 
-AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
-AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
 AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
diff --git a/configure b/configure
index 46aa5d7..7f513a1 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for mmdb 1.25.5.
+# Generated by GNU Autoconf 2.69 for mmdb2 2.0.1.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -585,14 +585,14 @@ MFLAGS=
 MAKEFLAGS=
 
 # Identity of this package.
-PACKAGE_NAME='mmdb'
-PACKAGE_TARNAME='mmdb'
-PACKAGE_VERSION='1.25.5'
-PACKAGE_STRING='mmdb 1.25.5'
+PACKAGE_NAME='mmdb2'
+PACKAGE_TARNAME='mmdb2'
+PACKAGE_VERSION='2.0.1'
+PACKAGE_STRING='mmdb2 2.0.1'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
-ac_unique_file="mmdb/mmdb_align.cpp"
+ac_unique_file="mmdb2/mmdb_math_align.cpp"
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
@@ -1323,7 +1323,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures mmdb 1.25.5 to adapt to many kinds of systems.
+\`configure' configures mmdb2 2.0.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1371,7 +1371,7 @@ Fine tuning of the installation directories:
   --infodir=DIR           info documentation [DATAROOTDIR/info]
   --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
   --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/mmdb]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/mmdb2]
   --htmldir=DIR           html documentation [DOCDIR]
   --dvidir=DIR            dvi documentation [DOCDIR]
   --pdfdir=DIR            pdf documentation [DOCDIR]
@@ -1393,7 +1393,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of mmdb 1.25.5:";;
+     short | recursive ) echo "Configuration of mmdb2 2.0.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1504,7 +1504,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-mmdb configure 1.25.5
+mmdb2 configure 2.0.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1903,7 +1903,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by mmdb $as_me 1.25.5, which was
+It was created by mmdb2 $as_me 2.0.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2250,7 +2250,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
- # keep in sync with mmdb/mmdb_defs.h
+ # keep in sync with mmdb2/mmdb_defs.h
 
 ac_aux_dir=
 for ac_dir in build-aux "$srcdir"/build-aux; do
@@ -2285,7 +2285,7 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 ac_config_headers="$ac_config_headers config.h"
 
-am__api_version='1.12'
+am__api_version='1.13'
 
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
@@ -2469,8 +2469,8 @@ if test x"${MISSING+set}" != xset; then
   esac
 fi
 # Use eval to expand $SHELL
-if eval "$MISSING --run true"; then
-  am_missing_run="$MISSING --run "
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
 else
   am_missing_run=
   { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
@@ -2770,8 +2770,8 @@ fi
 
 
 # Define the identity of the package.
- PACKAGE='mmdb'
- VERSION='1.25.5'
+ PACKAGE='mmdb2'
+ VERSION='2.0.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2811,12 +2811,17 @@ mkdir_p='$(MKDIR_P)'
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
 
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
 am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
 
 
 
 
 
+
 DEPDIR="${am__leading_dot}deps"
 
 ac_config_commands="$ac_config_commands depfiles"
@@ -15483,7 +15488,7 @@ else
   as_fn_error $? "need math library" "$LINENO" 5
 fi
 
-ac_config_files="$ac_config_files Makefile mmdb.pc"
+ac_config_files="$ac_config_files Makefile mmdb2.pc"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -16023,7 +16028,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mmdb $as_me 1.25.5, which was
+This file was extended by mmdb2 $as_me 2.0.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -16089,7 +16094,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mmdb config.status 1.25.5
+mmdb2 config.status 2.0.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -16601,7 +16606,7 @@ do
     "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
     "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "mmdb.pc") CONFIG_FILES="$CONFIG_FILES mmdb.pc" ;;
+    "mmdb2.pc") CONFIG_FILES="$CONFIG_FILES mmdb2.pc" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
@@ -17198,7 +17203,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
 
   case $ac_file$ac_mode in
     "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
-  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # Older Autoconf quotes --file arguments for eval, but not when files
   # are listed without --file.  Let's play safe and only enable the eval
   # if we detect the quoting.
   case $CONFIG_FILES in
@@ -17249,7 +17254,7 @@ $as_echo X"$mf" |
     DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
     test -z "$DEPDIR" && continue
     am__include=`sed -n 's/^am__include = //p' < "$mf"`
-    test -z "am__include" && continue
+    test -z "$am__include" && continue
     am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
     # Find all dependency output files, they are included files with
     # $(DEPDIR) in their names.  We invoke sed twice because it is the
diff --git a/configure.ac b/configure.ac
index 92ff8d6..f685b56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
 
-AC_INIT(mmdb, 1.25.5) # keep in sync with mmdb/mmdb_defs.h
+AC_INIT(mmdb2, 2.0.1) # keep in sync with mmdb2/mmdb_defs.h
 
 AC_CONFIG_AUX_DIR(build-aux)
 AC_CONFIG_MACRO_DIR(m4)
-AC_CONFIG_SRCDIR(mmdb/mmdb_align.cpp)
+AC_CONFIG_SRCDIR(mmdb2/mmdb_math_align.cpp)
 AC_CONFIG_HEADERS(config.h)
 AM_INIT_AUTOMAKE([1.11 foreign subdir-objects silent-rules -Wall])
 AM_PROG_AR
@@ -18,4 +18,4 @@ AC_LANG_POP(C++)
 AM_MAINTAINER_MODE dnl disable (by default) maintainer mode
 
 AC_SEARCH_LIBS([cos], [m], [], [AC_MSG_ERROR([need math library])])
-AC_OUTPUT(Makefile mmdb.pc)
+AC_OUTPUT(Makefile mmdb2.pc)
diff --git a/mmdb/bfgs_min.cpp b/mmdb/bfgs_min.cpp
deleted file mode 100755
index 9b3a95e..0000000
--- a/mmdb/bfgs_min.cpp
+++ /dev/null
@@ -1,936 +0,0 @@
-//  $Id: bfgs_min.cpp,v 1.19 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-
-//  =================================================================
-//
-//    27.06.01   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  bfgs_min  <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CBFGSMin  ( minimization driver )
-//       ~~~~~~~~~  
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __BFGS_Min__
-#include "bfgs_min.h"
-#endif
-
-
-//  ==============================================================
-
-CBFGSMin::CBFGSMin()  {
-
-  MFunc       = NULL;
-  MFuncData   = NULL;
-  PFunc       = NULL;
-  PFuncData   = NULL;
-
-  N           = 0;
-  NAlloc      = 0;
-
-  Hsn         = NULL;
-  TL          = NULL;
-  LL          = NULL;
-  XOpt        = NULL;
-  XPlus       = NULL;
-  Sx          = NULL;
-  SN          = NULL;
-  HDiag       = NULL;
-  GradX       = NULL;
-  GPlus       = NULL;
-  StepSize    = NULL;
-  FNeighbor   = NULL;
-  us          = NULL;
-  uy          = NULL;
-  ut          = NULL;
-  Freese      = NULL;
-  Func        = 0.0;
-  FPlus       = 0.0;
-  FOpt        = 0.0;
-  TakenLambda = 0.0;
-  ForDiff     = False;
-  CalcHess    = False;
-
-  Etha        = 0.0;
-  SqrtEtha    = 0.0;
-  CubertEtha  = 0.0;
-  TpF         = 1.0;
-  GrdEps      = 0.0;
-  StpEps      = 0.0;
-  MxStep      = MaxReal;
-  CnsMax      = 0;
-  MaxItn      = 100;
-  TermCode    = BFGS_NoTermination;
-  ModF        = False;
-
-}
-
-CBFGSMin::~CBFGSMin()  {
-  FreeMemory();
-}
-
-void  CBFGSMin::MinFunc ( rvector X, realtype & F )  {
-  if (MFunc)  (*MFunc)(MFuncData,N,X,F);
-        else  F = 0.0;
-}
-
-void  CBFGSMin::MinFunc1 ( rvector X, realtype & F )  {
-int i;
-  MinFunc ( X,F );
-  if (ModF && (F<FOpt))  {
-    for (i=1;i<=N;i++)
-      XOpt[i] = X[i];
-    FOpt = F;
-  }
-}
-
-void  CBFGSMin::Print ( int Itn, rvector X, rvector G, realtype F )  {
-  if (PFunc)  (*PFunc)(PFuncData,N,Itn,X,G,F);
-}
-
-void  CBFGSMin::SetMinFunction ( void * UserData, PBFGSMinFunc Fnc )  {
-  MFuncData = UserData;
-  MFunc     = Fnc;
-}
-
-void  CBFGSMin::SetPrintFunction ( void * UserData, PBFGSPrintFunc Fnc )  {
-  PFuncData = UserData;
-  PFunc     = Fnc;
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::UMInCk ( rvector  x0,      rvector  TypX,
-                         int      Digits,  realtype TypF,
-                         realtype GrdTol,  realtype StpTol,
-                         realtype MaxStp,  int      ItnLmt )  {
-int      i;
-realtype S0,S1,S2;
-
-  SqrtEps = sqrt(MachEps);
-
-  if (N<1)  {
-    TermCode = BFGS_WrongSpaceDim;
-    return;
-  }
-
-  for (i=1;i<=N;i++)
-    if (fabs(TypX[i])!=0.0)  Sx[i] = 1.0/fabs(TypX[i]);
-                       else  Sx[i] = 1.0;
-
-  if (Digits<=0)  Etha = MachEps;
-  else  {
-    Etha = Exp((-Digits)*log(10.0));
-    if (MachEps>Etha)  Etha = MachEps;
-  }
-  SqrtEtha   = sqrt(Etha);
-  CubertEtha = Exp ( log(Etha)/3.0 );
-
-  if (Etha>0.01)  {
-    TermCode = BFGS_TooFewDigits;
-    return;
-  }
-
-  if (TypF<=0.0)  TpF = 1.0;
-            else  TpF = TypF;
-
-  S1 = Exp(log(MachEps)/3.0);
-  if (GrdTol>0.0)  GrdEps = GrdTol;
-  else  {
-    GrdEps = sqrt(Etha);
-    if (S1>GrdEps)  GrdEps = S1;
-  }
-
-  if (StpTol>0.0)  StpEps = StpTol;
-             else  StpEps = Exp ( log(MachEps)*2.0/3.0 );
-
-  if (MaxStp>0.0)  MxStep = MaxStp;
-  else  {
-    S1 = 0.0;
-    S2 = 0.0;
-    for (i=1;i<=N;i++)  {
-      S0  = Sx[i];
-      S0 *= Sx[i];
-      S2 += S0;
-      S0 *= x0[i];
-      S1 += S0*x0[i];
-    }
-    S1 = sqrt(S1);
-    S2 = sqrt(S2);
-    if (S2>S1)  MxStep = S2;
-          else  MxStep = S1;
-    MxStep *= 1000.0;
-  }
-
-  if (ItnLmt>0)  MaxItn = ItnLmt;
-           else  MaxItn = 100;
-
-  TermCode = BFGS_NoTermination;
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::UMStop0 ( rvector x0, rvector Grad )  {
-int      i;
-realtype S,Fmax,St;
-
-  CnsMax = 0;
-  if (TpF>fabs(Func))  Fmax = TpF;
-                 else  Fmax = fabs(Func);
-  S = 0.0;
-  for (i=1;i<=N;i++)  {
-    St = fabs(x0[i]);
-    if (1.0/Sx[i]>St)  St = 1.0/Sx[i];
-    St = fabs(Grad[i])*St/Fmax;
-    if (St>S)  S = St;
-  }
-  if (S>=0.001*GrdEps)  TermCode = BFGS_NoTermination;
-                  else  TermCode = BFGS_SmallGradient;
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::UMStop ( rvector  x0, rvector Grad,
-                         int RetCode, int  ItnCnt,
-                         Boolean MaxTkn )  {
-
-//  A7.2.1   :  Checking the Stop Conditions
-
-int      i;
-realtype Max1,Max2,MaxGrad,MaxStep, BB1,BB2;
-
-  TermCode = BFGS_NoTermination;
-  if (RetCode==1)  TermCode = BFGS_LineSearchComplete;
-  else  {
-    if (fabs(FPlus)>TpF)  Max2 = fabs(FPlus);
-                    else  Max2 = TpF;
-    MaxGrad = 0.0;
-    MaxStep = 0.0;
-    for (i=1;i<=N;i++)  {
-      BB1 = fabs(XPlus[i]);
-      BB2 = 1.0/Sx[i];
-      if (BB1>BB2)  Max1 = BB1;
-              else  Max1 = BB2;
-      BB1 = fabs(Grad[i])*Max1/Max2;
-      if (BB1>MaxGrad) MaxGrad = BB1;
-      BB2 = fabs(XPlus[i]-x0[i])/Max1;
-      if (BB2>MaxStep)  MaxStep = BB2;
-    }
-    if      (MaxGrad<GrdEps)  TermCode = BFGS_SmallGradient;
-    else if (MaxStep<StpEps)  TermCode = BFGS_SmallStep;
-    else if (ItnCnt>MaxItn)   TermCode = BFGS_IterationLimit;
-    else if (MaxTkn)  {
-      CnsMax++;
-      if (CnsMax==5)  TermCode = BFGS_LargeSteps;
-    } else
-      CnsMax = 0;
-  }
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::MdHess ( rmatrix H, rvector HDg )  {
-
-//  A5.5.1   :  Setting up the hessian of model
-
-int       i,j;
-realtype  MaxDiag,MaxOff, MinEv,Mue,MaxPosDiag;
-realtype  MaxOffl,MinDiag,MaxEv,MaxAdd,Sdd,OffRow;
-realtype  BB;
-
-  //  Scaling
-  for (i=1;i<=N;i++)
-    for (j=i;j<=N;j++)
-      H[i][j] /= (Sx[i]*Sx[j]);
-
-  MaxDiag = H[1][1];
-  MinDiag = H[1][1];
-  MaxOff  = 0.0;
-  for (i=1;i<=N;i++)  {
-    if (H[i][i]>MaxDiag)  MaxDiag = H[i][i];
-    if (H[i][i]<MinDiag)  MinDiag = H[i][i];
-    if (i<N)
-      for (j=i+1;j<=N;j++)  {
-        BB = fabs(H[i][j]);
-        if (BB>MaxOff)  MaxOff = BB;
-      }
-  }
-  MaxPosDiag = 0.0;
-  if (MaxDiag>MaxPosDiag)  MaxPosDiag = MaxDiag;
-
-  //  Computing the shift of the spectra (the  Mue)
-  if (MinDiag>SqrtEps*MaxPosDiag)  Mue = 0.0;
-  else  {
-    Mue      = 2.0*(MaxPosDiag-MinDiag)*SqrtEps-MinDiag;
-    MaxDiag += Mue;
-  }
-  BB = MaxOff*(1.0+2.0*SqrtEps);
-  if (BB>MaxDiag)  {
-    Mue     = Mue+(MaxOff-MaxDiag)+2.0*SqrtEps*MaxOff;
-    MaxDiag = BB;
-  }
-  if (MaxDiag==0.0)  {  //  H = 0
-    Mue     = 1.0;
-    MaxDiag = 1.0;
-  }
-  if (Mue>0.0)
-    for (i=1;i<=N;i++)
-      Hsn[i][i] += Mue;
-
-  MaxOffl = MaxOff/N;
-  if (MaxDiag>MaxOffl)  MaxOffl = MaxDiag;
-  MaxOffl = sqrt(MaxOffl);
-  for (i=1;i<=N;i++)
-    HDg[i] = H[i][i];
-
-  PbCholDecomp ( N,HDg,MaxOffl,MachEps,H,MaxAdd );
-
-  if (MaxAdd>0.0)  {
-    MaxEv = HDg[1];
-    MinEv = HDg[1];
-    for (i=1;i<=N;i++)  {
-      OffRow = 0.0;
-      if (i>1)
-        for (j=1;j<i;j++)
-          OffRow += fabs(H[j][i]);
-      if (i<N)
-        for (j=i+1;j<=N;j++)
-          OffRow += fabs(H[i][j]);
-      BB = HDg[i]+OffRow;
-      if (BB>MaxEv)  MaxEv = BB;
-      BB = HDg[i]-OffRow;
-      if (BB<MinEv)  MinEv = BB;
-    }
-    Sdd = (MaxEv-MinEv)*SqrtEps-MinEv;
-    if (Sdd<0.0)  Sdd = 0.0;
-    if (MaxAdd<Sdd)  Mue = MaxAdd;
-               else  Mue = Sdd;
-    for (i=1;i<=N;i++)
-      HDg[i] += Mue;
-
-    PbCholDecomp ( N,HDg,0.0,MachEps,H,MaxAdd );
-
-  }
-
-  //  Scaling back
-  for (i=1;i<=N;i++)  {
-    if (i<N)
-      for (j=i+1;j<=N;j++)
-        H[i][j] *= (Sx[i]*Sx[j]);
-    HDg[i] *= Sx[i]*Sx[i];
-    for (j=1;j<=i;j++)
-      H[i][j] *= Sx[i];
-  }
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::FDGrad ( rvector X, rvector G, realtype Fc )  {
-
-//  A5.6.4  :  Forward Finite-Differencies Approximation of
-//             the Gradient
-
-realtype StepSizeJ,TempJ,Fj, BB1,BB2;
-int      j;
-
-  for (j=1;j<=N;j++)  {
-    BB1 = fabs(X[j]);
-    BB2 = 1.0/Sx[j];
-    if (BB1>BB2)  StepSizeJ = BB1;
-            else  StepSizeJ = BB2;
-    if (X[j]<0.0) StepSizeJ = -StepSizeJ;
-    StepSizeJ *= SqrtEtha;
-    TempJ      = X[j];
-    X[j]      += StepSizeJ;
-    StepSizeJ  = X[j]-TempJ;
-    MinFunc1 ( X,Fj );
-    if (TermCode!=BFGS_NoTermination)  return;
-    G[j]       = (Fj-Fc)/StepSizeJ;
-    X[j]       = TempJ;
-    Freese[j]  = False;
-    if (TL)  {
-      if ((fabs(X[j]-TL[j])<=StepSizeJ) && (G[j]<0.0))  {
-        G[j] = 0.0;   Freese[j] = True;
-      }
-    }
-    if (LL)  {
-      if ((fabs(X[j]-LL[j])<=StepSizeJ) && (G[j]>0.0))  {
-        G[j] = 0.0;   Freese[j] = True;
-      }
-    }
-  }
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::CDGrad ( rvector X, rvector G  )  {
-
-//  A5.6.4  :  Central Differencies Approximation of
-//             Gradient
-
-realtype  StepSizeJ,TempJ,Fp,Fm, BB1,BB2;
-int       j;
-
-  for (j=1;j<=N;j++)  {
-    BB1 = fabs(X[j]);
-    BB2 = 1.0/Sx[j];
-    if (BB1>BB2)  StepSizeJ = BB1;
-            else  StepSizeJ = BB2;
-    if (X[j]<0.0) StepSizeJ = -StepSizeJ;
-    StepSizeJ *= CubertEtha;
-    TempJ      = X[j];
-    X[j]      += StepSizeJ;
-    StepSizeJ  = X[j]-TempJ;
-    MinFunc1 ( X,Fp );
-    if (TermCode!=BFGS_NoTermination)  return;
-    X[j]       = TempJ-StepSizeJ;
-    MinFunc1 ( X,Fm );
-    if (TermCode!=BFGS_NoTermination)  return;
-    G[j]       = (Fp-Fm)/(2.0*StepSizeJ);
-    X[j]       = TempJ;
-  }
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::Gradient ( rvector X, rvector G, realtype Fc )  {
-  if (ForDiff)  FDGrad ( X,G,Fc );
-          else  CDGrad ( X,G );
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::FDHessF ( realtype Fc, rvector X )  {
-
-//   A5.6.2   :  Finite-Difference Approximation of
-//               the Hessian employing only the
-//               function's  values
-
-int       i,j;
-realtype  S,TempI,Fii,TempJ,Fij, BB1,BB2;
-
-
-  for (i=1;i<=N;i++)
-    if (!Freese[i])  {
-      BB1 = fabs(X[i]);
-      BB2 = 1.0/Sx[i];
-      if (BB1>BB2)  S = BB1;
-              else  S = BB2;
-      if (X[i]<0.0) S = -S;
-      StepSize[i] = S*CubertEtha;
-      TempI       = X[i];
-      X[i]       += StepSize[i];
-      StepSize[i] = X[i]-TempI;
-      MinFunc1 ( X,FNeighbor[i] );
-      X[i]        = TempI;
-      if (TermCode!=BFGS_NoTermination)  return;
-    }
-  for (i=1;i<=N;i++)
-    if (!Freese[i])  {
-      TempI = X[i];
-      X[i] += 2.0*StepSize[i];
-      MinFunc1 ( X,Fii );
-      if (TermCode!=BFGS_NoTermination)  return;
-      Hsn[i][i] = (( Fc -FNeighbor[i] ) +
-                   ( Fii-FNeighbor[i] )) /
-                  (StepSize[i]*StepSize[i]);
-      X[i]      = TempI+StepSize[i];
-      if (i<N)
-        for (j=i+1;j<=N;j++)
-          if (!Freese[j])  {
-            TempJ = X[j];
-            X[j] += StepSize[j];
-            MinFunc1 ( X,Fij );
-            if (TermCode!=BFGS_NoTermination)  return;
-            Hsn[i][j] = (( Fc -FNeighbor[i] ) +
-                         ( Fij-FNeighbor[j] )) /
-                        (StepSize[i]*StepSize[j]);
-            X[j]      = TempJ;
-          } else
-            Hsn[i][j] = 0.0;
-      X[i] = TempI;
-    } else
-      for (j=i;j<=N;j++)
-        Hsn[i][j] = 0.0;
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::InitHessUnFac ( realtype F, rmatrix H )  {
-
-//  A9.4.3  -  Initialization of the unfactorized BFGS
-
-realtype Temp;
-int      i,j;
-
-  Temp = fabs(F);
-  if (TpF>Temp)  Temp = TpF;
-  for (i=1;i<=N;i++)  {
-    H[i][i] = Temp*Sx[i]*Sx[i];
-    if (i<N)
-      for (j=i+1;j<=N;j++)
-        H[i][j] = 0.0;
-  }
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::BFGSUnFac (  rvector  Xc,       rvector  Xp,
-                             rvector  Gc,       rvector  Gp,
-                             Boolean  AnalGrad, rvector  HDg,
-                             rmatrix  H )  {
-
-//  A9.4.1  -  Calculation of the Hessian by the
-//             unfactorized BFGS
-
-int      i,j;
-realtype Temp1,Temp2, NormS,NormY,Tol,tt, BB;
-Boolean  SkipUpdate;
-
-  Temp1 = 0.0;
-  NormS = 0.0;
-  NormY = 0.0;
-  for (i=1;i<=N;i++)  {
-    H[i][i] = HDg[i];
-    us[i]   = Xp[i] - Xc[i];
-    uy[i]   = Gp[i] - Gc[i];
-    Temp1  += us[i]*uy[i];
-    NormS  += us[i]*us[i];
-    NormY  += uy[i]*uy[i];
-  }
-
-  if (Temp1>sqrt(MachEps*NormS*NormY))  {
-    if (AnalGrad)  Tol = Etha;
-             else  Tol = sqrt(Etha);
-    SkipUpdate = True;
-    for (i=1;i<=N;i++)  {
-      tt = 0.0;
-      for (j=1;j<=i;j++)
-        tt += H[j][i]*us[j];
-      if (i<N)
-        for (j=i+1;j<=N;j++)
-          tt += H[i][j]*us[j];
-      ut[i] = tt;
-      tt    = fabs(Gc[i]);
-      BB    = fabs(Gp[i]);
-      if (BB>tt)  tt = BB;
-      if (fabs(uy[i]-ut[i])>=Tol*tt)
-        SkipUpdate = False;
-    }
-
-    if (!SkipUpdate)  {
-      Temp2 = 0.0;
-      for (i=1;i<=N;i++)
-        Temp2 += us[i]*ut[i];
-      for (i=1;i<=N;i++)
-        for (j=i;j<=N;j++)
-          H[i][j] += uy[i]*uy[j]/Temp1 -
-                     ut[i]*ut[j]/Temp2;
-    }
-
-  }
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::Choose_Lambda ( rvector X, rvector S,
-                                realtype & Lambda0 )  {
-int      i;
-realtype SS;
-
-  for (i=1;i<=N;i++)
-    if  ((S[i]!=0.0) && (!Freese[i]))  {
-      SS = X[i] + Lambda0*S[i];
-      if (TL)  {
-        if (SS>TL[i])  Lambda0 = (TL[i]-X[i])/S[i]/(1.0+MachEps);
-      }
-      if (LL)  {
-        if (SS<LL[i])  Lambda0 = (LL[i]-X[i])/S[i]/(1.0+MachEps);
-      }
-    } else if (Freese[i])  S[i] = 0.0;
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::Stop()  {
-  TermCode = BFGS_Stopped;
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::LineSearch (  rvector   px0,   rvector   G,
-                              rvector   P,     realtype  pFunc,
-                              int  & RetCode,  Boolean & MaxTkn )  {
-
-//  A6.3.1   :   Linear  Search
-
-int      i;
-realtype Alpha, NewtLn, S, InitSp, RelLng, MinLam;
-realtype Lambda,LamTem, LamPre, FplPre, A, B;
-realtype Disc,  B1, B2, Lambda0;
-
-  LamPre = 1.0;  // only to keep compiler happy
-  FplPre = 1.0;  // only to keep compiler happy
-
-  MaxTkn  = False;
-  RetCode = 2;
-  Alpha   = 1.0e-4;
-  NewtLn  = 0.0;
-  for (i=1;i<=N;i++)  {   //  calculate Newtonian step along the -gradient
-    B1      = Sx[i]*P[i];
-    NewtLn += B1*B1;
-  }
-  NewtLn = sqrt(NewtLn);
-
-  if (NewtLn>MxStep)  {   //  restrict Newtonian step to MxStep
-    S = MxStep/NewtLn;
-    for (i=1;i<=N;i++)
-      P[i] *= S;
-    NewtLn = MxStep;
-  }
-
-  InitSp  = 0.0;
-  RelLng  = 0.0;
-  Lambda0 = 1.0;
-  Choose_Lambda ( px0,P,Lambda0 );
-  for (i=1;i<=N;i++)  {
-    InitSp += G[i]*P[i];
-    B1      = fabs(px0[i]);
-    B2      = 1.0/Sx[i];
-    if (B1>B2)  S = B1;
-          else  S = B2;
-    S       = fabs(P[i])/S;
-    if (S>RelLng)  RelLng = S;
-  }
-  InitSp *= Lambda0;
-
-  MinLam = StpEps/RelLng;
-  Lambda = Lambda0;
-  do {
-    for (i=1;i<=N;i++)
-      XPlus[i] = px0[i] + Lambda*P[i];
-
-    MinFunc1 ( XPlus,FPlus );
-    if (TermCode!=BFGS_NoTermination)  return;
-    if (FPlus<=pFunc+Alpha*Lambda*InitSp)  {
-      RetCode = 0;
-      MaxTkn  = (Lambda==Lambda0) && (NewtLn>0.99*MxStep);
-    } else if (Lambda<MinLam)  {
-      RetCode = 1;
-      for (i=1;i<=N;i++)
-        XPlus[i] = px0[i];
-    } else if (Lambda==Lambda0)  {
-      LamTem = -InitSp/(2.0*(FPlus-pFunc-InitSp));
-      LamTem = LamTem*Lambda;
-      LamPre = Lambda;
-      FplPre = FPlus;
-      if (LamTem>0.1*Lambda)  Lambda = LamTem;
-      else  {
-        Lambda *= 0.1;
-        Lambda0 = Lambda;
-      }
-      if (Lambda>Lambda0)  {
-        Lambda  = Lambda0;
-        RetCode = 0;
-        for (i=1;i<=N;i++)
-          XPlus[i] = px0[i] + Lambda*P[i];
-      }
-    } else  {
-      B1 = FPlus  - pFunc - Lambda*InitSp;
-      B2 = FplPre - pFunc - LamPre*InitSp;
-      A  = ( B1/(Lambda*Lambda) - B2/(LamPre*LamPre) ) /
-           ( Lambda - LamPre );
-      B  = ( -LamPre*B1/(Lambda*Lambda) +
-             Lambda*B2/(LamPre*LamPre) ) /
-           ( Lambda - LamPre );
-      Disc = B*B - 3.0*A*InitSp;
-      if (A==0.0)  LamTem = -InitSp/(2.0*B);
-             else  LamTem = (-B+sqrt(RMax(Disc,0.0)))/(3.0*A);
-      B1 = 0.5*Lambda;
-      if (B1<LamTem)  LamTem = B1;
-      LamPre = Lambda;
-      FplPre = FPlus;
-      if (LamTem>0.1*Lambda)  Lambda = LamTem;
-      else  {
-        Lambda *= 0.1;
-        Lambda0 = Lambda;
-      }
-      if (Lambda>Lambda0)  {
-        Lambda  = Lambda0;
-        RetCode = 0;
-        for (i=1;i<=N;i++)
-          XPlus[i] = px0[i] + Lambda*P[i];
-      }
-    }
-
-  } while (RetCode>=2);
-
-  TakenLambda = Lambda;
-
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::GetMemory()  {
-  if (N!=NAlloc)  {
-    FreeMemory();
-    GetMatrixMemory ( Hsn   , N,N, 1,1 );
-    GetVectorMemory ( GPlus , N, 1 );
-    GetVectorMemory ( GradX , N, 1 );
-    GetVectorMemory ( HDiag , N, 1 );
-    GetVectorMemory ( SN    , N, 1 );
-    GetVectorMemory ( Sx    , N, 1 );
-    GetVectorMemory ( XPlus , N, 1 );
-    GetVectorMemory ( XOpt  , N, 1 );
-    GetVectorMemory ( Freese, N, 1 );
-    if (CalcHess)  {
-      GetVectorMemory ( StepSize , N, 1 );
-      GetVectorMemory ( FNeighbor, N, 1 );
-    } else  {
-      GetVectorMemory ( us       , N, 1 );
-      GetVectorMemory ( uy       , N, 1 );
-      GetVectorMemory ( ut       , N, 1 );
-    }
-    NAlloc = N;
-  }
-}
-
-void  CBFGSMin::FreeMemory()  {
-  if (NAlloc>0)  {
-    FreeVectorMemory ( us       , 1 );
-    FreeVectorMemory ( uy       , 1 );
-    FreeVectorMemory ( ut       , 1 );
-    FreeVectorMemory ( Freese   , 1 );
-    FreeVectorMemory ( StepSize , 1 );
-    FreeVectorMemory ( FNeighbor, 1 );
-    FreeVectorMemory ( XOpt     , 1 );
-    FreeVectorMemory ( XPlus    , 1 );
-    FreeVectorMemory ( Sx       , 1 );
-    FreeVectorMemory ( SN       , 1 );
-    FreeVectorMemory ( HDiag    , 1 );
-    FreeVectorMemory ( GradX    , 1 );
-    FreeVectorMemory ( GPlus    , 1 );
-    FreeMatrixMemory ( Hsn      , NAlloc, 1,1 );
-  }
-  NAlloc = 0;
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::Relax()  {
-int i;
-  if (FPlus>FOpt)  {
-    for (i=1;i<=N;i++)
-      XPlus[i] = XOpt[i];
-    FPlus = FOpt;
-  } else  {
-    for (i=1;i<=N;i++)
-      XOpt[i] = XPlus[i];
-    FOpt = FPlus;
-  }
-}
-
-void  CBFGSMin::CopyPlus ( rvector x0 )  {
-int i;
-  for (i=1;i<=N;i++)  {
-    x0   [i] = XPlus[i];
-    GradX[i] = GPlus[i];
-  }
-  Func = FPlus;
-}
-
-
-//  -------------------------------------------------------------------
-
-void  CBFGSMin::BFGS_Driver (  int        MinN,
-                               rvector    x0,
-                               rvector    TypX,
-                               realtype & FuncValue,
-                               int      & TerminationCode,
-                               int        Digits,
-                               int        ItnLmt,
-                               realtype   TypF,
-                               realtype   GrdTol,
-                               realtype   StpTol,
-                               realtype   MaxStp,
-                               Boolean    Hess,
-                               rvector    LowLimit,
-                               rvector    TopLimit )  {
-
-//  D6.1.1   :  Unconstrained Minimization Driver
-
-int       i,RetCode;
-int       ItnCnt;
-Boolean   MaxTkn;
-
-  TL       = TopLimit;
-  LL       = LowLimit;
-  ForDiff  = True;
-  N        = MinN;
-  CalcHess = Hess;
-
-  ModF     = False;
-
-  GetMemory();
-
-  UMInCk ( x0,TypX,Digits,TypF,
-           GrdTol,StpTol,MaxStp,
-           ItnLmt );
-  if (TermCode!=BFGS_NoTermination)  {
-    FreeMemory();
-    FuncValue       = Func;
-    TerminationCode = TermCode;
-    return;
-  }
-
-  ItnCnt = 0;
-
-  MinFunc1 ( x0,Func );
-  if (TermCode!=BFGS_NoTermination)  {
-    FreeMemory();
-    FuncValue       = Func;
-    TerminationCode = TermCode;
-    return;
-  }
-  FOpt  = Func;
-  FPlus = Func;
-  for (i=1;i<=N;i++)  {
-    XOpt [i] = x0[i];
-    XPlus[i] = x0[i];
-  }
-  ModF = True;
-  Gradient ( x0,GradX,Func );
-  Print    ( ItnCnt,x0,GradX,Func );
-  for (i=1;i<=N;i++)
-    GPlus[i] = GradX[i];
-  if (TermCode!=BFGS_NoTermination)  {
-    Relax     ();
-    CopyPlus  ( x0 );
-    FreeMemory();
-    FuncValue       = Func;
-    TerminationCode = TermCode;
-    return;
-  }
-
-  UMStop0 ( x0,GradX );
-  if  (TermCode!=BFGS_NoTermination)  {
-    FreeMemory();
-    FuncValue       = Func;
-    TerminationCode = TermCode;
-    return;
-  }
-
-  if (!CalcHess)  InitHessUnFac ( Func,Hsn );
-
-  RetCode = 0;
-  while (TermCode==BFGS_NoTermination)  {
-    ItnCnt++;
-    if (RetCode>=0)  {
-      if (CalcHess)  {
-        FDHessF ( Func,x0 );
-        if (TermCode!=BFGS_NoTermination)  {
-          Relax     ();
-          CopyPlus  ( x0 );
-          FreeMemory();
-          FuncValue       = Func;
-          TerminationCode = TermCode;
-          return;
-        }
-      }
-      MdHess ( Hsn,HDiag );
-    }
-    ChSolve    ( N,Hsn,GradX,SN );
-    LineSearch ( x0,GradX,SN,Func,RetCode,MaxTkn );
-    if ((RetCode==1) && ForDiff)  {
-      RetCode = -1;
-      ForDiff = False;
-    } else
-      Relax();
-    if (TermCode!=BFGS_NoTermination)  {
-      Relax     ();
-      CopyPlus  ( x0 );
-      FreeMemory();
-      FuncValue       = Func;
-      TerminationCode = TermCode;
-      return;
-    } else
-      Gradient ( XPlus,GPlus,FPlus );
-    if (TermCode!=BFGS_NoTermination)  {
-      Relax     ();
-      CopyPlus  ( x0 );
-      FreeMemory();
-      FuncValue       = Func;
-      TerminationCode = TermCode;
-      return;
-    }
-    if (RetCode>=0)  {
-      UMStop ( x0,GPlus,RetCode,ItnCnt,MaxTkn );
-      if ((!CalcHess) && (TermCode==BFGS_NoTermination))
-        BFGSUnFac ( x0,XPlus,GradX,GPlus,False,HDiag,Hsn );
-    }
-    CopyPlus ( x0 );
-    Print    ( ItnCnt, x0,GradX,Func );
-  }
-
-  Relax     ();
-  FreeMemory();
-  FuncValue       = Func;
-  TerminationCode = TermCode;
-
-}
-
-
diff --git a/mmdb/bfgs_min.h b/mmdb/bfgs_min.h
deleted file mode 100755
index ec6741b..0000000
--- a/mmdb/bfgs_min.h
+++ /dev/null
@@ -1,257 +0,0 @@
-//  $Id: bfgs_min.h,v 1.20 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    27.06.01   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  bfgs_min  <interface>
-//       ~~~~~~~~~
-//  **** Classes :  CBFGSMin  ( minimization driver )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __BFGS_Min__
-#define  __BFGS_Min__
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-#ifndef  __LinAlg__
-#include "linalg_.h"
-#endif
-
-
-//  ==============================================================
-
-#define  BFGS_TooFewDigits       -2
-#define  BFGS_WrongSpaceDim      -1
-#define  BFGS_NoTermination       0
-#define  BFGS_SmallGradient       1
-#define  BFGS_SmallStep           2
-#define  BFGS_LineSearchComplete  3
-#define  BFGS_IterationLimit      4
-#define  BFGS_LargeSteps          5
-#define  BFGS_Stopped             6
-
-typedef void BFGSMinFunc ( void * UserData, int N, rvector X,
-                           realtype & F );
-typedef BFGSMinFunc * PBFGSMinFunc;
-
-typedef void BFGSPrintFunc ( void * UserData, int N, int Itn,
-                             rvector X, rvector G, realtype F );
-typedef BFGSPrintFunc * PBFGSPrintFunc;
-
-DefineClass(CBFGSMin);
-
-class CBFGSMin  {
-
-  public :
-
-    CBFGSMin ();
-    virtual ~CBFGSMin();
-
-    virtual void  MinFunc  ( rvector X, realtype & F );
-    virtual void  Print    ( int Itn, rvector X, rvector G,
-                             realtype F );
-
-    void  SetMinFunction   ( void * UserData, PBFGSMinFunc   Fnc );
-    void  SetPrintFunction ( void * UserData, PBFGSPrintFunc Fnc );
-
-
-    // ======================================================
-    //
-    //    .--------------------------------------------.
-    //    |                                            |
-    //    |     UNCONSTRAINED MINIMIZATION DRIVER      |
-    //    |                                            |
-    //    `--------------------------------------------'
-    //
-    //    Finds a minimum of function F(X), X is vector [1..N], defined
-    //  by virtual MinFunc. Virtual Print provides information on every
-    //  iteration step.
-    //
-    //
-    //               Input  parameters  :
-    //             -----------------------
-    //
-    //    N        is the dimension the minimization space
-    //
-    //    x0       [1..N] is the initial point for minimization
-    //
-    //    TypX     [1..N] is the array of the typical ranges of
-    //          X - components,  which are used for the scaling.
-    //          If  TypX<=0.0  then  1.0  will be substituted
-    //
-    //    Digits   is the number of valid decimal digits in
-    //          the calculated value of minimizing function ( F ).
-    //          If  Digits<=0  then the Driver will consider
-    //          that the  F  is computed with usual machine's
-    //          noise
-    //
-    //    ItnLmt   is the maximum available number of iterations.
-    //          If  ItnLmt=0  then  100  will be substituted
-    //
-    //    TypF     is the expected absolute value of  F  in the
-    //          minimum,  which is used in the stop criterion.
-    //          If  TypF<=0.0  then  1.0  will be substituted
-    //
-    //    GrdTol   is the desired absolute value of the gradient
-    //          vector in the minimum of  F .  If  GrdTol<=0.0
-    //          then the some value correlated with machine's
-    //          noise will be substituted
-    //
-    //    StpTol   is the minimum available step for the minimi-
-    //          zation.  The execution stops if the distance
-    //          between two consequential approximation will be
-    //          less then  StpTol .  If  StpTol<=0.0  then the
-    //          some value correlated with machine's  noise
-    //          will be substituted
-    //
-    //    MaxStp   is the maximum available step for then minimi-
-    //          zation.  This parameter only prevents the appea-
-    //          rance of the too large steps,  but the execution
-    //          stops if more than  5  steps with length of MaxStep
-    //          will consequently appear.
-    //
-    //
-    //
-    //               Outpute  parameters  :
-    //             --------------------------
-    //
-    //    x0        will be the point at which the minimisation
-    //          had stopped
-    //
-    //    Func      will be the function's value at  x0
-    //
-    //    TermCode  will be the reason of stopping :
-    //
-    //         1 <=>  the norm of gradient vector at  x0  is
-    //               less than  GrdTol ;  the  x0  is probable
-    //               point of the minimum
-    //         2 <=>  the distance between two last approxima-
-    //               tions was less than  StpTol ;  the  x0
-    //               may be the point of minimum
-    //         3 <=>  the gradient length is greater than
-    //               GrdTol ,  but future minimization fails ;
-    //               it may be the consequence of the errors
-    //               at the computing of gradient, but also
-    //               x0 could be the point of minimum
-    //         4 <=>  the iteration limit had been exchausted
-    //         5 <=>  more than  5  steps with length of
-    //               MaxStp  had been made
-    //         6 <=>  the termination key ( Esc or End )
-    //               had been pressed.
-    //
-    //
-    // ========================================================
-
-    void  BFGS_Driver      ( int        MinN,
-                             rvector    x0,
-                             rvector    TypX,
-                             realtype & FuncValue,
-                             int      & TerminationCode,
-                             int        Digits   = 0,
-                             int        ItnLmt   = 0,
-                             realtype   TypF     = 0.0,
-                             realtype   GrdTol   = 0.0,
-                             realtype   StpTol   = 0.0,
-                             realtype   MaxStp   = MaxReal,
-                             Boolean    Hess     = False,
-                             rvector    LowLimit = NULL,
-                             rvector    TopLimit = NULL );
-
-    void  Stop();  // generates stop signal to stop optimization
-
-
-  protected :
-
-    PBFGSMinFunc    MFunc;
-    void *          MFuncData;
-    PBFGSPrintFunc  PFunc;
-    void *          PFuncData;
-
-    int             N,NAlloc;
-    rmatrix         Hsn;
-    rvector         TL,LL,XOpt,XPlus,Sx,SN,HDiag,GradX,GPlus;
-    rvector         StepSize,FNeighbor;
-    rvector         us,uy,ut;
-    bvector         Freese;
-    realtype        Func,FPlus,FOpt;
-    realtype        TakenLambda;
-    Boolean         ForDiff;  // if True then forward differences are
-                              // used for the 1st estimation of the
-                              // Hessian (which is less expensive),
-                              // otherwise central differences will
-                              // be employed (which is more expensive).
-    Boolean         CalcHess;
-
-    realtype        Etha,SqrtEtha,CubertEtha,TpF,GrdEps,StpEps,MxStep;
-    realtype        SqrtEps;
-    int             CnsMax,MaxItn,TermCode;
-    Boolean         ModF;
-
-    void  MinFunc1      ( rvector X, realtype & F );
-    void  UMInCk        ( rvector  x0,     rvector  TypX,
-                          int      Digits, realtype TypF,
-                          realtype GrdTol, realtype StpTol,
-                          realtype MaxStp, int      ItnLmt );
-    void  UMStop0       ( rvector x0, rvector Grad );
-    void  UMStop        ( rvector x0, rvector Grad, int RetCode,
-                          int ItnCnt, Boolean MaxTkn );
-
-    virtual void Gradient ( rvector X, rvector G, realtype Fc );
-    virtual void FDHessF  ( realtype Fc, rvector X );
-
-    void  FDGrad        ( rvector X, rvector G, realtype Fc );
-    void  CDGrad        ( rvector X, rvector G );
-    void  MdHess        ( rmatrix H, rvector HDg );
-    void  InitHessUnFac ( realtype F,  rmatrix H );
-    void  BFGSUnFac     ( rvector  Xc,      rvector Xp,
-                          rvector  Gc,      rvector Gp,
-                          Boolean AnalGrad, rvector HDg,
-                          rmatrix  H );
-    void  Choose_Lambda ( rvector X, rvector S, realtype & Lambda0 );
-    void  LineSearch    ( rvector    px0,       rvector   G,
-                          rvector    P,         realtype pFunc,
-                          int     & RetCode, Boolean & MaxTkn );
-    void  GetMemory     ();
-    void  FreeMemory    ();
-    void  Relax         ();
-    void  CopyPlus      ( rvector x0 );
-
-};
-
-#endif
-
-
diff --git a/mmdb/file_.cpp b/mmdb/file_.cpp
deleted file mode 100755
index b85b697..0000000
--- a/mmdb/file_.cpp
+++ /dev/null
@@ -1,1857 +0,0 @@
-//  $Id: file_.cpp,v 1.29 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  file_  <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CFile  - file I/O Support.
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef  _WIN32
-# include <windows.h>
-# define sleep Sleep
-# endif
-
-#ifndef  __STDIO_H
-#include <stdio.h>
-#endif
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  _WIN32
-#ifndef  __UNISTD_H
-#include <unistd.h>
-#endif
-#endif
-
-#ifndef  __File__
-#include "file_.h"
-#endif
-
-
-// _WIN32_NEWLINE should be raised when compilinig on Windows in
-// order to enforce Windows' line endings when writing text in
-// files opened for *binary* output. Otherwise, writing text lines
-// in binary files will results in UNIX line endings. Line endings
-// in files, opened for output in text mode, will be always
-// platform-specific.
-
-#ifdef  _WIN32_NEWLINE
-//  for DOS/WINDOWS machines:
-#define  NEWLINE  "\r\n"
-#else
-//  for UNIX machines:
-#define  NEWLINE  "\n"
-#endif
-
-
-// ===================  Auxilary Functions  =========================
-
-cpstr GetFPath ( pstr FilePath, int syskey )  {
-pstr P;
-
-  if (syskey==syskey_unix)
-    P = strrchr(FilePath,'/');
-  else if (syskey==syskey_win)
-    P = strrchr(FilePath,'\\');
-  else if (syskey==syskey_all)  {
-    P = strrchr(FilePath,'/');
-    if (!P)  P = strrchr(FilePath,'\\');
-  } else
-    P = NULL;
-
-  if (P)  {
-    P = P + 1;
-    *P = char(0);
-  } else
-    FilePath[0] = char(0);
-
-  return FilePath;
-
-}
-
-cpstr GetFName ( cpstr FilePath, int syskey )  {
-pstr P;
-  if (syskey==syskey_unix)
-    P = strrchr(FilePath,'/');
-  else if (syskey==syskey_win)
-    P = strrchr(FilePath,'\\');
-  else if (syskey==syskey_all)  {
-    P = strrchr(FilePath,'/');
-    if (!P)  P = strrchr(FilePath,'\\');
-  } else
-    P = NULL;
-  if (!P)  return FilePath;
-     else  return P + 1;
-}
-
-cpstr GetFExt ( cpstr FilePath )  {
-pstr P;
-  P = strchr ( GetFName(FilePath),'.');
-  if (!P) return &(FilePath[strlen(FilePath)]);
-     else return P;
-}
-
-cpstr ChangeExt ( pstr FilePath, cpstr newExt, int syskey )  {
-int i;
-  i = strlen(FilePath)-1;
-  if (syskey==syskey_unix)
-    while ((i>0) && (FilePath[i]!='.') && (FilePath[i]!='/'))  i--;
-  else if (syskey==syskey_win)
-    while ((i>0) && (FilePath[i]!='.') && (FilePath[i]!='\\'))  i--;
-  else if (syskey==syskey_all)
-    while ((i>0) && (FilePath[i]!='.') &&
-           (FilePath[i]!='/') && (FilePath[i]!='\\'))  i--;
-  if (FilePath[i]=='.')  {
-    FilePath[i+1] = char(0);
-    strcat ( FilePath,newExt );
-  } else  {
-    strcat ( FilePath,"."    );
-    strcat ( FilePath,newExt );
-  }
-  return FilePath;
-}
-
-Boolean FileExists ( cpstr FileName, PCFile f )  {
-PCFile  g;
-Boolean B;
-  if (FileName)  {
-    if (!f)  g = new CFile();
-       else  g = f;
-    g->assign ( FileName );
-    B = g->exists();
-    if (!f)  delete g;
-    return B;
-  } else
-    return False;
-}
-
-
-//  ========================  CFile Class  ========================
-
-#define ARCH_NONE      0
-#define ARCH_GZIP      1
-#define ARCH_COMPRESS  2
-#define ARCH_ENFORCE   3
-
-CFile::CFile ( word BufSize )  {
-  Buf_Size  = BufSize;
-  BufLen    = 0;
-  BufInc    = 1;
-  EofFile   = False;
-  hFile     = NULL;
-  FName     = NULL;
-  BufCnt    = 0;
-  IOBuf     = NULL;
-  IOSuccess = True;
-  TextMode  = False;
-  UniBin    = False;
-  StdIO     = False;
-  gzipIO    = ARCH_NONE;
-  memIO     = False;
-}
-
-CFile::~CFile()  {
-  shut      ();
-  FreeBuffer();
-}
-
-void  CFile::FreeBuffer ()  {
-  if (IOBuf)  {
-    if (!memIO)  delete[] IOBuf;
-    IOBuf = NULL;
-  }
-  if (FName)  {
-    delete[] FName;
-    FName = NULL;
-  }
-}
-
-void  CFile::assign ( cpstr FileName, Boolean Text, Boolean UniB,
-                      byte gzMode )  {
-pstr p;
-
-  shut();
-
-  FreeBuffer();
-
-  CreateCopy ( FName,FileName );
-  StdIO = (!strcmp(FName,"stdin" )) ||
-          (!strcmp(FName,"stdout")) ||
-          (!strcmp(FName,"stderr"));
-
-  if (StdIO)  TextMode = True;
-        else  TextMode = Text;
-
-  UniBin = UniB;
-
-  gzipMode = gzMode;
-  gzipIO   = ARCH_NONE;
-  if ((gzipMode==GZM_ENFORCE) || (gzipMode==GZM_ENFORCE_GZIP))
-    gzipIO = ARCH_GZIP;
-  else if (gzipMode==GZM_ENFORCE_COMPRESS)
-    gzipIO = ARCH_COMPRESS;
-  else if (gzipMode==GZM_CHECK)  {
-    p = strrchr ( FName,'.' );
-    if (p)  {
-      if (!strcmp(p,".gz"))      gzipIO = ARCH_GZIP;
-      else if (!strcmp(p,".Z"))  gzipIO = ARCH_COMPRESS;
-    }
-  }
-
-  memIO = False;
-
-}
-
-
-void  CFile::assign ( word poolSize, word sizeInc, pstr filePool )  {
-
-  shut      ();
-  FreeBuffer();
-
-  IOBuf    = (pstr)filePool;
-  BufLen   = poolSize;
-  FLength  = poolSize;
-  BufInc   = sizeInc;
-  BufCnt   = 0;
-
-  memIO    = True;
-  gzipMode = GZM_NONE;
-  gzipIO   = ARCH_NONE;
-
-}
-
-void  CFile::GetFilePool ( pstr & filePool, word & fileSize )  {
-  if (memIO)  {
-    filePool = IOBuf;
-    fileSize = FLength;
-    IOBuf    = NULL;
-    BufLen   = 0;
-    BufCnt   = 0;
-    FLength  = 0;
-  } else  {
-    filePool = NULL;
-    fileSize = 0;
-  }
-}
-
-static pstr gzip_path       = pstr("gzip ");
-static pstr ungzip_path     = pstr("gzip -dc ");
-static pstr compress_path   = pstr("compress ");
-static pstr uncompress_path = pstr("uncompress -c ");
-
-void  SetGZIPPath ( pstr gzipPath, pstr ungzipPath )  {
-  if (!gzipPath)  gzip_path = pstr("gzip ");
-            else  gzip_path = gzipPath;
-  if (!ungzipPath)  ungzip_path = pstr("gzip -d ");
-              else  ungzip_path = ungzipPath;
-}
-
-void  SetCompressPath ( pstr compressPath, pstr uncompressPath )  {
-  if (!compressPath)  compress_path = pstr("compress ");
-                else  compress_path = compressPath;
-  if (!uncompressPath)  uncompress_path = pstr("uncompress -c ");
-                  else  uncompress_path = uncompressPath;
-}
-
-
-Boolean  CFile::reset ( Boolean ReadOnly, int retry )  {
-#ifndef _MSC_VER
-pstr p;
-int  i;
-#endif
-
-  if (memIO)  {
-
-    shut();
-    if (!IOBuf)  return False;
-    BufCnt    = 0;
-    IOSuccess = True;
-
-  } else  {
-
-    if (!FName)  return False;
-    shut();
-    BufLen = 0;
-    BufCnt = 0;
-
-    if (!strcmp(FName,"stdin"))  {
-
-      hFile     = stdin;
-      StdIO     = True;
-      TextMode  = True;
-      FLength   = 1;
-      EofFile   = False;
-      IOSuccess = True;
-
-    } else  {
-
-      StdIO = False;
-      if (gzipIO==ARCH_GZIP)  {
-#ifndef _MSC_VER
-        p = NULL;
-        CreateConcat  ( p,ungzip_path,FName );
-        for (i=0;(i<=retry) && (!hFile);i++)  {
-          if (i>0)  sleep ( 1 );
-          hFile = popen ( p,"r" );
-        }
-        if (p)  delete[] p;
-#endif
-
-      } else if (gzipIO==ARCH_COMPRESS)  {
-#ifndef _MSC_VER
-        p = NULL;
-        CreateConcat  ( p,uncompress_path,FName );
-        for (i=0;(i<=retry) && (!hFile);i++)  {
-          if (i>0)  sleep ( 1 );
-          hFile = popen ( p,"r" );
-        }
-        if (p)  delete[] p;
-#endif
-
-      } else  {
-
-#ifndef _MSC_VER
-        for (i=0;(i<=retry) && (!hFile);i++)  {
-          if (i>0)  sleep ( 1 );
-          if (TextMode)  {
-            if (ReadOnly)  hFile = fopen ( FName,"rt"  );
-                     else  hFile = fopen ( FName,"r+t" );
-          } else  {
-            if (ReadOnly)  hFile = fopen ( FName,"rb"  );
-                     else  hFile = fopen ( FName,"r+b" );
-          }
-        }
-#endif
-
-      }
-
-      if (hFile)  {
-        if (gzipIO==ARCH_NONE)  {
-          fseek ( hFile,0L,SEEK_END );
-          FLength = ftell ( hFile );
-          fseek ( hFile,0L,SEEK_SET );
-          EofFile = (FLength<=0);
-        } else  {
-          FLength = 1;
-          EofFile = False;
-        }
-        IOSuccess = True;
-      } else  {
-        EofFile   = True;
-        IOSuccess = False;
-      }
-
-    }
-
-  }
-
-  return  IOSuccess;
-
-}
-
-Boolean  CFile::rewrite()  {
-#ifndef _MSC_VER
-pstr p;
-#endif
-
-  if (memIO)  {
-
-    shut();
-    FreeBuffer();
-    IOBuf = new char[BufLen];
-    BufCnt    = 0;
-    FLength   = 0;
-    IOSuccess = True;;
-
-  } else  {
-
-    if (!FName)  return False;
-    shut();
-    BufLen = 0;
-    BufCnt = 0;
-
-    if (gzipIO==ARCH_GZIP)  {
-#ifndef _MSC_VER
-      p = NULL;
-      CreateConcat  ( p,gzip_path,pstr(" > "),FName );
-      hFile = popen ( p,"w" );
-      if (p)  delete[] p;
-#else
-      hFile = NULL;
-#endif
-      StdIO = False;
-    } else if (gzipIO==ARCH_COMPRESS)  {
-#ifndef _MSC_VER
-      p = NULL;
-      CreateConcat  ( p,compress_path,pstr(" > "),FName );
-      hFile = popen ( p,"w" );
-      if (p)  delete[] p;
-#else
-      hFile = NULL;
-#endif
-      StdIO = False;
-    } else if (!TextMode)  {
-      hFile = fopen ( FName,"w+b" );
-      StdIO = False;
-    } else if (!strcmp(FName,"stdout"))  {
-      hFile = stdout;
-      StdIO = True;
-    } else if (!strcmp(FName,"stderr")) {
-      hFile = stderr;
-      StdIO = True;
-    } else  {
-      hFile = fopen ( FName,"w+t" );
-      StdIO = False;
-    }
-
-    FLength   = 0;
-    IOSuccess = (hFile!=NULL);
-
-  }
-
-  return  IOSuccess;
-
-}
-
-
-Boolean  CFile::append()  {
-#ifndef _MSC_VER
-pstr p;
-#endif
-
-  if (memIO)  {
-
-    if (!IOBuf)  {
-      IOBuf  = new char[BufLen];
-      BufCnt = 0;
-    }
-    FLength   = BufCnt;
-    IOSuccess = True;
-
-  } else  {
-
-    if (!FName)  return False;
-
-    shut();
-    BufLen  = 0;
-    BufCnt  = 0;
-    if (gzipIO==ARCH_GZIP)  {
-#ifndef _MSC_VER
-      p = NULL;
-      CreateConcat  ( p,gzip_path,pstr(" >> "),FName );
-      hFile = popen ( p,"w" );
-      if (p)  delete[] p;
-#else
-      hFile = NULL;
-#endif
-      StdIO = False;
-    } else if (gzipIO==ARCH_COMPRESS)  {
-#ifndef _MSC_VER
-      p = NULL;
-      CreateConcat  ( p,compress_path,pstr(" >> "),FName );
-      hFile = popen ( p,"w" );
-      if (p)  delete[] p;
-#else
-      hFile = NULL;
-#endif
-      StdIO = False;
-    } else if (!TextMode)  {
-      hFile = fopen ( FName,"ab" );
-      StdIO = False;
-    } else if (!strcmp(FName,"stdout"))  {
-      hFile = stdout;
-      StdIO = True;
-    } else if (!strcmp(FName,"stderr")) {
-      hFile = stderr;
-      StdIO = True;
-    } else  {
-      hFile = fopen ( FName,"at" );
-      StdIO = False;
-    }
-
-    FLength = 0;
-    IOSuccess = hFile!=NULL;
-
-  }
-
-  return  IOSuccess;
-
-}
-
-Boolean  CFile::erase()  {
-  if (!FName)  return False;
-  shut();
-  if (!StdIO)  {
-    BufLen = 0;
-    BufCnt = 0;
-    if (FName)
-      IOSuccess = (remove(FName)==0);
-    FLength = 0;
-  } else
-    IOSuccess = True;
-  return  IOSuccess;
-}
-
-Boolean  CFile::exists()  {
-
-  if (memIO)  {
-
-    IOSuccess = (IOBuf!=NULL);
-
-  } else  {
-
-    if (!FName)  return False;
-    shut();
-    if (!StdIO)  {
-      hFile     = fopen ( FName,"r" );
-      IOSuccess = (hFile!=NULL);
-      BufLen    = 0;
-      BufCnt    = 0;
-      FLength   = 0;
-      if (hFile)  fclose ( hFile );
-    } else
-      IOSuccess = True;
-    hFile = NULL;
-  }
-
-  return  IOSuccess;
-
-}
-
-Boolean  CFile::parse ( cpstr FileName )  {
-UNUSED_ARGUMENT(FileName);
-  return True;
-}
-
-Boolean  CFile::rename ( cpstr NewFileName )  {
-  if (!FName)  return False;
-  shut();
-  if (!StdIO)
-    IOSuccess = (::rename(FName,NewFileName)==0);
-  if (IOSuccess)  assign ( NewFileName,TextMode,UniBin,gzipMode );
-  return  IOSuccess;
-}
-
-long  CFile::Position()  {
-// do not use on text files
-
-  if (memIO)  return BufCnt;
-
-  if (hFile==NULL)  return 0L;
-  return  ftell ( hFile );
-
-}
-
-Boolean  CFile::seek ( long Position )  {
-// do not use on text files
-  if (memIO)  {
-    if (Position<=(long)BufLen)  {
-      BufCnt    = Position;
-      IOSuccess = True;
-    } else
-      IOSuccess = False;
-    return IOSuccess;
-  } else if (hFile==NULL)
-    return False;
-  else if (!StdIO)  {
-    IOSuccess = fseek(hFile,Position,SEEK_SET)==0;
-    return IOSuccess;
-  } else
-    return True;
-}
-
-Boolean  CFile::FileEnd()  {
-
-  if (memIO)  return ((long)BufCnt>=FLength);
-
-  if (TextMode)  {
-    if (EofFile || ((!hFile) && (!StdIO)))
-       return True;
-    if (feof(hFile)==0)
-       return False;
-    return True;
-  }
-
-  return  EofFile && (BufLen==0);
-
-}
-
-void  CFile::shut ()  {
-
-  if (hFile!=NULL)  {
-    if (!StdIO)  {
-#ifndef _MSC_VER
-      if (gzipIO!=ARCH_NONE)  pclose ( hFile );
-                        else  fclose ( hFile );
-#else
-      fclose ( hFile );
-#endif
-    }
-    hFile = NULL;
-  }
-
-}
-
-Boolean CFile::isOpen()  {
-  if (memIO)  return (IOBuf!=NULL);
-  return (hFile!=NULL);
-}
-
-word  CFile::ReadLine ( pstr Line, word MaxLen )  {
-word     LCnt;
-int      Done;
-Boolean  HSuccess = IOSuccess;
-
-  if (memIO)  {
-
-    LCnt = 0;
-    while (((long)BufCnt<FLength) &&
-           (LCnt<MaxLen-1)        &&
-           (IOBuf[BufCnt]!='\r')  &&
-           (IOBuf[BufCnt]!='\n') )
-      Line[LCnt++] = IOBuf[BufCnt++];
-    Line[LCnt] = char(0);
-
-    while (((long)BufCnt<FLength) &&
-           (IOBuf[BufCnt]!='\r')  &&
-           (IOBuf[BufCnt]!='\n') )
-      BufCnt++;
-
-    if ((long)BufCnt<FLength)  {
-      if (IOBuf[BufCnt]=='\r')  {
-        BufCnt++;
-        if ((long)BufCnt<FLength)  {
-          if (IOBuf[BufCnt]=='\n')  BufCnt++;
-        }
-      } else if (IOBuf[BufCnt]=='\n')  {
-        BufCnt++;
-        if ((long)BufCnt<FLength)  {
-          if (IOBuf[BufCnt]=='\r')  BufCnt++;
-        }
-      }
-    }
-
-    return LCnt;
-
-  } else  {
-
-    if ((!hFile) && (!StdIO))  {
-      Line[0]   = char(0);
-      EofFile   = True;
-      BufLen    = 0;
-      IOSuccess = False;
-      return 0;
-    }
-    if (TextMode)  {
-      Line[0] = char(0);
-      if (fgets(Line,MaxLen,hFile))  {
-        LCnt = strlen(Line);
-        while (LCnt>0)  {
-          if ((Line[LCnt-1]!='\n') &&
-              (Line[LCnt-1]!='\r'))  break;
-          Line[LCnt-1] = char(0);
-          LCnt--;
-        }
-      } else
-        LCnt = 0;
-      return LCnt;
-    } else  {
-      if (IOBuf==NULL)  {
-        IOBuf     = new char[Buf_Size];
-        BufLen    = ReadFile ( IOBuf,Buf_Size );
-        IOSuccess = HSuccess;
-        BufCnt    = 0;
-      }
-      LCnt = 0;
-      do {
-        while ((BufCnt<BufLen)       &&
-               (LCnt<MaxLen-1)       &&
-               (IOBuf[BufCnt]!='\r') &&
-               (IOBuf[BufCnt]!='\n') )
-          Line[LCnt++] = IOBuf[BufCnt++];
-        if (BufCnt>=BufLen)  {
-          HSuccess  = IOSuccess;
-          BufLen    = ReadFile ( IOBuf,Buf_Size );
-          IOSuccess = HSuccess;
-          BufCnt    = 0;
-        }
-        if (IOBuf[BufCnt]=='\r')      Done = 1;
-        else if (IOBuf[BufCnt]=='\n') Done = 2;
-                                 else Done = 0;
-        if (Done)  BufCnt++;
-        if (BufCnt>=BufLen)  {
-          HSuccess  = IOSuccess;
-          BufLen    = ReadFile ( IOBuf,Buf_Size );
-          IOSuccess = HSuccess;
-          BufCnt    = 0;
-        }
-        if (BufLen>0)  {
-          if (((Done==2) && (IOBuf[BufCnt]=='\r')) ||
-              ((Done==1) && (IOBuf[BufCnt]=='\n')))
-            BufCnt++;
-        }
-      } while ((!Done) && (LCnt<MaxLen-1) && (BufLen>0));
-      Line[LCnt] = char(0);
-      return LCnt;
-    }
-
-  }
-
-}
-
-word  CFile::ReadNonBlankLine ( pstr S, word MaxLen )  {
-word  i,j;
-  do  {
-    j = ReadLine ( S,MaxLen );
-    i = 0;
-    while ((i<j) && (S[i]==' ')) i++;
-  } while ((i>=j) && (!FileEnd()));
-  if (i>=j)  {
-    S[0] = char(0);
-    j    = 0;
-  }
-  return  j;
-}
-
-
-Boolean  CFile::WriteLine ( cpstr Line )  {
-  if ((!memIO) && TextMode)  {
-    if (hFile==NULL)  return False;
-    fputs ( Line,hFile );
-//    return (fputs(NEWLINE,hFile)>=0);
-    return (fputs("\n",hFile)>=0);
-  } else  {
-    if (WriteFile(Line,strlen(Line)))
-          return  WriteFile ( (void *)NEWLINE,strlen(NEWLINE) );
-    else  return  False;
-  }
-}
-
-Boolean  CFile::Write ( cpstr Line )  {
-  if ((!memIO) && TextMode)  {
-    if (hFile==NULL)  return False;
-    return (fputs(Line,hFile)>=0);
-  } else
-    return WriteFile(Line,strlen(Line));
-}
-
-Boolean  CFile::Write ( realtype V, int length )  {
-char N[50];
-  sprintf ( N,"%-.*g",length,V );
-  if ((!memIO) && TextMode)  {
-    if (hFile==NULL)  return False;
-    return (fputs(N,hFile)>=0);
-  } else
-    return WriteFile(N,strlen(N));
-}
-
-Boolean  CFile::Write ( int iV, int length )  {
-char N[50];
-  sprintf ( N,"%*i",length,iV );
-  if ((!memIO) && TextMode)  {
-    if (hFile==NULL)  return False;
-    return (fputs(N,hFile)>=0);
-  } else
-    return WriteFile(N,strlen(N));
-}
-
-Boolean  CFile::LF()  {
-  if ((!memIO) && TextMode)  {
-    if (hFile==NULL)  return False;
-//    return (fputs(NEWLINE,hFile)>=0);
-    return (fputs("\n",hFile)>=0);
-  } else
-    return WriteFile ( (void *)NEWLINE,strlen(NEWLINE) );
-}
-
-Boolean  CFile::WriteDataLine ( realtype X, realtype Y, int length )  {
-  Write ( pstr("   ") );
-  Write ( X,length    );
-  Write ( pstr("   ") );
-  Write ( Y,length    );
-  return LF();
-}
-
-Boolean  CFile::WriteParameter ( cpstr S, realtype X,
-                                 int ParColumn, int length )  {
-int  l=strlen(S);
-  if ((!memIO) && TextMode)  {
-    fputs ( S,hFile );
-    while (l<ParColumn)  {
-      fputs ( " ",hFile );
-      l++;
-    }
-  } else  {
-    WriteFile ( S,l );
-    while (l<ParColumn)  {
-      WriteFile ( (void *)" ",1 );
-      l++;
-    }
-  }
-  Write ( X,length );
-  return LF();
-}
-
-Boolean  CFile::WriteParameters ( cpstr S, int n_X, rvector X,
-                                  int ParColumn, int length )  {
-int  i;
-int  l=strlen(S);
-  if ((!memIO) && TextMode)  {
-    fputs ( S,hFile );
-    while (l<ParColumn)  {
-      fputs ( " ",hFile );
-      l++;
-    }
-  } else  {
-    WriteFile ( S,l );
-    while (l<ParColumn)  {
-      WriteFile ( (void *)" ",1 );
-      l++;
-    }
-  }
-  for (i=0;i<n_X;i++)  {
-    Write ( X[i],length );
-    if (i!=n_X-1)  WriteFile ( (void *)", ",2 );
-  }
-  return LF();
-}
-
-Boolean  CFile::ReadParameter  ( pstr S, realtype & X,
-                                 int ParColumn )  {
-  ReadLine ( S );
-  if ((int)strlen(S)>ParColumn)  {
-//    X = atof ( &(S[ParColumn]) );
-    X = GetNumber ( &(S[ParColumn]) );
-    return True;
-  } else  {
-    X = 0.0;
-    return False;
-  }
-}
-
-Boolean  CFile::ReadParameters ( pstr S, int & n_X, rvector X,
-                                 int MaxLen, int ParColumn )  {
-pstr S1,S2;
-  ReadLine ( S,MaxLen );
-  if ((int)strlen(S)>ParColumn)  {
-    n_X = 0;
-    S2 = &(S[ParColumn]);
-    S1 = S2;
-    while (*S1!=char(0))  {
-      if (*S1==',')  *S1 = ' ';
-      S1++;
-    }
-    while (*S2!=char(0))  {
-      S1 = S2;
-      X[n_X] = strtod ( S1,&S2 );
-      n_X++;
-      while ((*S2!=char(0)) && (*S2==' '))  S2++;
-    }
-    return True;
-  } else  {
-    n_X  = 0;
-    X[0] = 0.0;
-    return False;
-  }
-}
-
-Boolean  CFile::ReadParameter  ( pstr S, int & X,
-                                 int ParColumn )  {
-realtype  V;
-  if (ReadParameter(S,V,ParColumn))  {
-    X = mround(V);
-    return True;
-  } else  {
-    X = 0;
-    return False;
-  }
-}
-
-Boolean  CFile::CreateWrite ( cpstr Line )  {
-wordUniBin wUB;
-word       i;
-  if (UniBin)  {
-    if (Line)  {
-      i = strlen(Line)+1;
-      word2UniBin ( i,wUB );
-      if (WriteFile(wUB,sizeof(wordUniBin)))
-             return WriteFile ( Line,i );
-      else   return False;
-    } else  {
-      i = 0;
-      word2UniBin ( i,wUB );
-      return WriteFile ( wUB,sizeof(wordUniBin) );
-    }
-  } else  {
-    if (Line)  {
-      i = strlen(Line)+1;
-      if (WriteFile(&i,sizeof(i)))
-             return WriteFile ( Line,i );
-      else   return False;
-    } else  {
-      i = 0;
-      return WriteFile ( &i,sizeof(i) );
-    }
-  }
-}
-
-#define _max_dyn_string_len  1073741824
-
-word  CFile::CreateRead ( pstr & Line )  {
-wordUniBin wUB;
-word       i;
-//unsigned short int i;
-  if (Line)  {
-    delete[] Line;
-    Line = NULL;
-  }
-  if (UniBin)  {
-    ReadFile    ( wUB,sizeof(wordUniBin) );
-    UniBin2word ( wUB,i );
-  } else
-    ReadFile ( &i,sizeof(i) );
-  if ((i>0) && (i<_max_dyn_string_len))  {
-    Line = new char[i];
-    ReadFile ( Line,i );
-  }
-  return i;
-}
-
-Boolean  CFile::WriteTerLine ( cpstr Line, Boolean longLine )  {
-wordUniBin wUB;
-word       ll;
-byte       sl;
-Boolean    B;
-  if (Line)  ll = strlen(Line);
-       else  ll = 0;
-  if (!longLine)  {
-    sl = byte(ll);
-    B = WriteFile ( &sl,sizeof(sl) );
-  } else if (UniBin)  {
-    word2UniBin ( ll,wUB );
-    B = WriteFile ( wUB,sizeof(wordUniBin) );
-  } else
-    B = WriteFile ( &ll,sizeof(ll) );
-  if (B && (ll>0))  B = WriteFile ( Line,ll );
-  return B;
-}
-
-word  CFile::ReadTerLine ( pstr Line, Boolean longLine )  {
-wordUniBin wUB;
-word       ll;
-byte       sl;
-  if (!longLine)  {
-    ReadFile ( &sl,sizeof(sl) );
-    ll = sl;
-  } else if (UniBin)  {
-    ReadFile    ( wUB,sizeof(wordUniBin) );
-    UniBin2word ( wUB,ll );
-  } else
-    ReadFile ( &ll,sizeof(ll) );
-  if (ll>0)  ReadFile ( Line,ll );
-  Line[ll] = char(0);
-  return ll+1;
-}
-
-word  CFile::ReadFile ( void * Buffer, word Count )  {
-word  Cnt;
-  if (memIO)  {
-    Cnt       = WMin(Count,FLength-BufCnt);
-    if (Cnt>0)  {
-      memcpy ( Buffer,&(IOBuf[BufCnt]),Cnt );
-      BufCnt += Cnt;
-    }
-    IOSuccess = (Cnt==Count);
-    EofFile   = ((Cnt<Count) || ((long)BufCnt>=FLength));
-    return  Cnt;
-  } else if (hFile)  {
-    Cnt       = (word)fread ( Buffer,1,Count,hFile );
-    EofFile   = (Cnt<Count) ||
-                 ((gzipIO==ARCH_NONE) && (Position()==FLength));
-    IOSuccess = (Cnt==Count);
-    return  Cnt;
-  } else
-    return  0;
-}
-
-Boolean  CFile::WriteFile ( const void * Buffer, word Count )  {
-pstr IOB;
-word Cnt;
-long Pos;
-
-  if (memIO)  {
-
-    Cnt = BufCnt + Count;
-    if (Cnt>BufLen)  {
-      Cnt += BufInc;
-      IOB = new char[Cnt];
-      if (IOBuf)  {
-        memcpy ( IOB,IOBuf,BufCnt );
-        delete[] IOBuf;
-      }
-      IOBuf = IOB;
-      BufLen = Cnt;
-    }
-    memcpy ( &(IOBuf[BufCnt]),Buffer,Count );
-    BufCnt += Count;
-    FLength = BufCnt;
-    IOSuccess = True;
-
-  } else  {
-
-    if (hFile==NULL)  return False;
-    Cnt = (word)fwrite ( Buffer,1,Count,hFile );
-    Pos = Position();
-    if (Pos>FLength)  FLength = Pos;
-    IOSuccess = Cnt==Count;
-
-  }
-
-  return IOSuccess;
-
-}
-
-Boolean  CFile::WriteReal ( realtype * V )  {
-realUniBin  rUB;
-  if (UniBin)  {
-    real2UniBin ( *V,rUB );
-    return WriteFile ( rUB,sizeof(realUniBin) );
-  } else
-    return WriteFile ( V,sizeof(realtype) );
-}
-
-Boolean  CFile::WriteFloat ( realtype * V )  {
-floatUniBin fUB;
-float       fV;
-  if (UniBin)  {
-    float2UniBin ( *V,fUB );
-    return WriteFile ( fUB,sizeof(floatUniBin) );
-  } else  {
-    fV = (float)*V;
-    return WriteFile ( &fV,sizeof(float) );
-  }
-}
-
-Boolean  CFile::WriteInt ( int * I )  {
-intUniBin  iUB;
-  if (UniBin)  {
-    int2UniBin ( *I,iUB );
-    return WriteFile ( iUB,sizeof(intUniBin) );
-  } else
-    return WriteFile ( I,sizeof(int) );
-}
-
-Boolean  CFile::WriteShort ( short * S )  {
-shortUniBin  sUB;
-  if (UniBin)  {
-    short2UniBin ( *S,sUB );
-    return WriteFile ( sUB,sizeof(shortUniBin) );
-  } else
-    return WriteFile ( S,sizeof(short) );
-}
-
-Boolean  CFile::WriteLong ( long * L )  {
-longUniBin  lUB;
-  if (UniBin)  {
-    long2UniBin ( *L,lUB );
-    return WriteFile ( lUB,sizeof(longUniBin) );
-  } else
-    return WriteFile ( L,sizeof(long) );
-}
-
-Boolean  CFile::WriteBool ( Boolean * B )  {
-intUniBin  iUB;
-int        k;
-  if (UniBin)  {
-    if (*B)  k = 1;
-       else  k = 0;
-    int2UniBin ( k,iUB );
-    return WriteFile ( iUB,sizeof(intUniBin) );
-  } else
-    return WriteFile ( B,sizeof(Boolean) );
-}
-
-Boolean  CFile::WriteByte ( byte * B )  {
-  return WriteFile ( B,sizeof(byte) );
-}
-
-Boolean  CFile::WriteWord ( word * W )  {
-wordUniBin  wUB;
-  if (UniBin)  {
-    word2UniBin ( *W,wUB );
-    return WriteFile ( wUB,sizeof(wordUniBin) );
-  } else
-    return WriteFile ( W,sizeof(word) );
-}
-
-Boolean  CFile::ReadReal ( realtype * V )  {
-realUniBin  rUB;
-  if (UniBin)  {
-    if (ReadFile(rUB,sizeof(realUniBin))==sizeof(realUniBin))  {
-      UniBin2real ( rUB,*V );
-      return True;
-    } else
-      return False;
-  } else
-    return ( ReadFile(V,sizeof(realtype))==sizeof(realtype) );
-}
-
-Boolean  CFile::ReadFloat ( realtype * V )  {
-floatUniBin  fUB;
-float        fV;
-  if (UniBin)  {
-    if (ReadFile(fUB,sizeof(floatUniBin))==sizeof(floatUniBin))  {
-      UniBin2float ( fUB,*V );
-      return True;
-    }
-  } else if (ReadFile(&fV,sizeof(float))==sizeof(float))  {
-    *V = fV;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::ReadInt ( int * I )  {
-intUniBin  iUB;
-  if (UniBin)  {
-    if (ReadFile(iUB,sizeof(intUniBin))==sizeof(intUniBin))  {
-      UniBin2int ( iUB,*I );
-      return True;
-    } else
-      return False;
-  } else
-    return ( ReadFile(I,sizeof(int))==sizeof(int) );
-}
-
-Boolean  CFile::ReadShort ( short * S )  {
-shortUniBin  sUB;
-  if (UniBin)  {
-    if (ReadFile(sUB,sizeof(shortUniBin))==sizeof(shortUniBin))  {
-      UniBin2short ( sUB,*S );
-      return True;
-    } else
-      return False;
-  } else
-    return ( ReadFile(S,sizeof(short))==sizeof(short) );
-}
-
-Boolean  CFile::ReadLong ( long * L )  {
-longUniBin  lUB;
-  if (UniBin)  {
-    if (ReadFile(lUB,sizeof(longUniBin))==sizeof(longUniBin))  {
-      UniBin2long ( lUB,*L );
-      return True;
-    } else
-      return False;
-  } else
-    return ( ReadFile(L,sizeof(long))==sizeof(long) );
-}
-
-Boolean  CFile::ReadBool ( Boolean * B )  {
-intUniBin  iUB;
-int        k;
-  if (UniBin)  {
-    if (ReadFile(iUB,sizeof(intUniBin))==sizeof(intUniBin))  {
-      UniBin2int ( iUB,k );
-      *B = (k!=0);
-      return True;
-    } else
-      return False;
-  } else
-    return ( ReadFile(B,sizeof(Boolean))==sizeof(Boolean) );
-}
-
-Boolean  CFile::ReadByte ( byte * B )  {
-  return ( ReadFile(B,sizeof(byte))==sizeof(byte) );
-}
-
-Boolean  CFile::ReadWord ( word * W )  {
-wordUniBin  wUB;
-  if (UniBin)  {
-    if (ReadFile(wUB,sizeof(wordUniBin))==sizeof(wordUniBin))  {
-      UniBin2word ( wUB,*W );
-      return True;
-    } else
-      return False;
-  } else
-    return ( ReadFile(W,sizeof(word))==sizeof(word) );
-}
-
-Boolean  CFile::AddReal ( realtype * V )  {
-realtype x;
-  if (ReadReal(&x))  {
-    *V += x;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::AddFloat ( realtype * V )  {
-realtype x;
-  if (ReadFloat(&x))  {
-    *V += x;
-    return True;
-  }
-  return False;
-}
-
-
-Boolean  CFile::AddInt ( int * I )  {
-int k;
-  if (ReadInt(&k))  {
-    *I += k;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::AddShort ( short * S )  {
-short k;
-  if (ReadShort(&k))  {
-    *S += k;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::AddLong ( long * L )  {
-long k;
-  if (ReadLong(&k))  {
-    *L += k;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::AddByte ( byte * B )  {
-byte k;
-  if (ReadByte(&k))  {
-    *B += k;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::AddWord ( word * W )  {
-word k;
-  if (ReadWord(&k))  {
-    *W += k;
-    return True;
-  }
-  return False;
-}
-
-Boolean  CFile::WriteVector ( rvector V, int len, int Shift )  {
-intUniBin  iUB;
-realUniBin rUB;
-int        i;
-int        l = len;
-  if (V==NULL)  l = 0;
-  if (UniBin)  {
-    int2UniBin ( l,iUB );
-    WriteFile ( iUB,sizeof(intUniBin) );
-    for (i=0;i<len;i++)  {
-      real2UniBin ( V[Shift+i],rUB );
-      WriteFile   ( rUB,sizeof(realUniBin) );
-    }
-  } else  {
-    WriteFile ( &l,sizeof(l) );
-    if (l>0)  WriteFile ( &(V[Shift]),sizeof(realtype)*l );
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::WriteVector ( ivector iV, int len, int Shift )  {
-intUniBin  iUB;
-int        i;
-int        l = len;
-  if (iV==NULL)  l = 0;
-  if (UniBin)  {
-    int2UniBin ( l,iUB );
-    WriteFile ( iUB,sizeof(intUniBin) );
-    for (i=0;i<len;i++)  {
-      int2UniBin ( iV[Shift+i],iUB );
-      WriteFile  ( iUB,sizeof(intUniBin) );
-    }
-  } else  {
-    WriteFile ( &l,sizeof(l) );
-    if (l>0)  WriteFile ( &(iV[Shift]),sizeof(int)*l );
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::WriteVector ( lvector lV, int len, int Shift )  {
-intUniBin  iUB;
-longUniBin lUB;
-int        i;
-int        l = len;
-  if (lV==NULL)  l = 0;
-  if (UniBin)  {
-    int2UniBin ( l,iUB );
-    WriteFile ( iUB,sizeof(intUniBin) );
-    for (i=0;i<len;i++)  {
-      long2UniBin ( lV[Shift+i],lUB );
-      WriteFile   ( lUB,sizeof(longUniBin) );
-    }
-  } else  {
-    WriteFile ( &l,sizeof(l) );
-    if (l>0)  WriteFile ( &(lV[Shift]),sizeof(long)*l );
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::WriteVector ( bvector B, int len, int Shift )  {
-intUniBin iUB;
-int       l = len;
-  if (B==NULL)  l = 0;
-  if (UniBin)  {
-    int2UniBin ( l,iUB );
-    WriteFile  ( iUB,sizeof(intUniBin) );
-  } else
-    WriteFile ( &l,sizeof(l) );
-  if (l>0)  WriteFile ( &(B[Shift]),sizeof(byte)*l );
-  return IOSuccess;
-}
-
-Boolean  CFile::ReadVector ( rvector V, int maxlen, int Shift )  {
-intUniBin  iUB;
-realUniBin rUB;
-int        i,l,ll;
-realtype   B;
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,l );
-    if (IOSuccess && (l>0))  {
-      ll = IMin(l,maxlen);
-      if (V)
-        for (i=0;i<=ll;i++)  {
-          ReadFile    ( rUB,sizeof(realUniBin) );
-          UniBin2real ( rUB,V[Shift+i] );
-        }
-      for (i=ll+1;i<=l;i++)
-        ReadFile ( rUB,sizeof(realUniBin) );
-    }
-  } else  {
-    ReadFile ( &l,sizeof(l) );
-    if (IOSuccess && (l>0))  {
-      ll = IMin(l,maxlen);
-      if (V)  ReadFile ( &(V[Shift]),sizeof(realtype)*ll );
-      for (i=ll+1;i<=l;i++)  ReadFile ( &B,sizeof(B) );
-    }
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::ReadVector ( ivector iV, int maxlen, int Shift )  {
-intUniBin  iUB;
-int        i,l,ll,iB;
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,l );
-    if (IOSuccess && (l>0))  {
-      ll = IMin(l,maxlen);
-      if (iV)
-        for (i=0;i<=ll;i++)  {
-          ReadFile   ( iUB,sizeof(intUniBin) );
-          UniBin2int ( iUB,iV[Shift+i]       );
-        }
-      for (i=ll+1;i<=l;i++)
-        ReadFile ( iUB,sizeof(intUniBin) );
-    }
-  } else  {
-    ReadFile ( &l,sizeof(l) );
-    if (IOSuccess && (l>0))  {
-      ll = IMin(l,maxlen);
-      if (iV)  ReadFile ( &(iV[Shift]),sizeof(int)*ll );
-      for (i=ll+1;i<=l;i++)  ReadFile ( &iB,sizeof(iB) );
-    }
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::ReadVector ( lvector lV, int maxlen, int Shift )  {
-intUniBin  iUB;
-longUniBin lUB;
-int        i,l,ll;
-long       lB;
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,l );
-    if (IOSuccess && (l>0))  {
-      ll = IMin(l,maxlen);
-      if (lV)
-        for (i=0;i<=ll;i++)  {
-          ReadFile    ( lUB,sizeof(longUniBin) );
-          UniBin2long ( lUB,lV[Shift+i]       );
-        }
-      for (i=ll+1;i<=l;i++)
-        ReadFile ( lUB,sizeof(longUniBin) );
-    }
-  } else  {
-    ReadFile ( &l,sizeof(l) );
-    if (IOSuccess && (l>0))  {
-      ll = IMin(l,maxlen);
-      if (lV)  ReadFile ( &(lV[Shift]),sizeof(long)*ll );
-      for (i=ll+1;i<=l;i++)  ReadFile ( &lB,sizeof(lB) );
-    }
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::ReadVector ( bvector B, int maxlen, int Shift )  {
-intUniBin  iUB;
-int        i,l,ll;
-byte       t;
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,l );
-  } else
-    ReadFile ( &l,sizeof(l) );
-  if (IOSuccess && (l>0))  {
-    ll = IMin(l,maxlen);
-    if (B)  ReadFile ( &(B[Shift]),sizeof(byte)*ll );
-    for (i=ll+1;i<=l;i++)  ReadFile ( &t,sizeof(t) );
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::CreateReadVector ( rvector & V, int & len,
-                                   int Shift )  {
-intUniBin  iUB;
-realUniBin rUB;
-int        i;
-realtype   B;
-  FreeVectorMemory ( V,Shift );
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,len );
-    if (IOSuccess && (len>0))  {
-      GetVectorMemory ( V,len,Shift );
-      if (V)
-        for (i=0;i<len;i++)  {
-          ReadFile    ( rUB,sizeof(realUniBin) );
-          UniBin2real ( rUB,V[Shift+i] );
-        }
-      else for (i=0;i<len;i++)
-        ReadFile ( rUB,sizeof(realUniBin) );
-    }
-  } else  {
-    ReadFile ( &len,sizeof(len) );
-    if (IOSuccess && (len>0))  {
-      GetVectorMemory ( V,len,Shift );
-      if (V)  ReadFile ( &(V[Shift]),sizeof(realtype)*len );
-        else for (i=0;i<len;i++)
-               ReadFile ( &B,sizeof(B) );
-    }
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::CreateReadVector ( rvector & V, int Shift )  {
-int len;
-  return CreateReadVector ( V,len,Shift );
-}
-
-Boolean  CFile::CreateReadVector ( ivector & iV, int & len,
-                                   int Shift )  {
-intUniBin  iUB;
-int        i,iB;
-  FreeVectorMemory ( iV,Shift );
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,len );
-    if (IOSuccess && (len>0))  {
-      GetVectorMemory ( iV,len,Shift );
-      if (iV)
-        for (i=0;i<len;i++)  {
-          ReadFile   ( iUB,sizeof(intUniBin) );
-          UniBin2int ( iUB,iV[Shift+i]       );
-        }
-      else for (i=0;i<len;i++)
-        ReadFile ( iUB,sizeof(intUniBin) );
-    }
-  } else  {
-    ReadFile ( &len,sizeof(len) );
-    if (IOSuccess && (len>0))  {
-      GetVectorMemory ( iV,len,Shift );
-      if (iV)  ReadFile ( &(iV[Shift]),sizeof(int)*len );
-         else for (i=0;i<len;i++)
-                ReadFile ( &iB,sizeof(iB) );
-    }
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::CreateReadVector ( ivector & iV, int Shift )  {
-int len;
-  return CreateReadVector ( iV,len,Shift );
-}
-
-Boolean  CFile::CreateReadVector ( lvector & lV, int & len,
-                                   int Shift )  {
-intUniBin  iUB;
-longUniBin lUB;
-int        i;
-long       lB;
-  FreeVectorMemory ( lV,Shift );
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,len );
-    if (IOSuccess && (len>0))  {
-      GetVectorMemory ( lV,len,Shift );
-      if (lV)
-        for (i=0;i<len;i++)  {
-          ReadFile    ( lUB,sizeof(intUniBin) );
-          UniBin2long ( lUB,lV[Shift+i]       );
-        }
-      else for (i=0;i<len;i++)
-        ReadFile ( lUB,sizeof(longUniBin) );
-    }
-  } else  {
-    ReadFile ( &len,sizeof(len) );
-    if (IOSuccess && (len>0))  {
-      GetVectorMemory ( lV,len,Shift );
-      if (lV) ReadFile ( &(lV[Shift]),sizeof(long)*len );
-         else for (i=0;i<len;i++)
-                ReadFile ( &lB,sizeof(lB) );
-    }
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::CreateReadVector ( lvector & lV, int Shift )  {
-int len;
-  return CreateReadVector ( lV,len,Shift );
-}
-
-
-Boolean  CFile::CreateReadVector ( bvector & B, int & len,
-                                   int Shift )  {
-intUniBin  iUB;
-int        i;
-byte       t;
-  FreeVectorMemory ( B,Shift );
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,len );
-  } else
-    ReadFile ( &len,sizeof(len) );
-  if (IOSuccess && (len>0))  {
-    GetVectorMemory ( B,len,Shift );
-    if (B)  ReadFile ( &(B[Shift]),sizeof(byte)*len );
-      else for (i=0;i<len;i++)
-             ReadFile ( &t,sizeof(t) );
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::CreateReadVector ( bvector & B, int Shift )  {
-int len;
-  return CreateReadVector ( B,len,Shift );
-}
-
-
-Boolean  CFile::WriteMatrix ( rmatrix & A, int N, int M,
-                              int ShiftN, int ShiftM )  {
-intUniBin  iUB;
-realUniBin rUB;
-int        i,j;
-  if (UniBin)  {
-    if (!A)  {
-      i = 0;
-      int2UniBin ( i,iUB );
-      WriteFile  ( iUB,sizeof(intUniBin) );
-    } else  {
-      int2UniBin ( N,iUB );
-      WriteFile  ( iUB,sizeof(intUniBin) );
-      int2UniBin ( M,iUB );
-      WriteFile  ( iUB,sizeof(intUniBin) );
-      for (i=0;i<N;i++)
-        for (j=0;j<M;j++)  {
-          real2UniBin ( A[ShiftN+i][ShiftM+j],rUB );
-          WriteFile   ( rUB,sizeof(realUniBin) );
-        }
-    }
-  } else if (!A) {
-    i = 0;
-    WriteFile ( &i,sizeof(i) );
-  } else  {
-    WriteFile ( &N,sizeof(N) );
-    WriteFile ( &M,sizeof(M) );
-    for (i=0;i<N;i++)
-      WriteFile ( &(A[ShiftN][ShiftM]),sizeof(realtype)*M );
-  }
-  return IOSuccess;
-}
-
-Boolean  CFile::CreateReadMatrix ( rmatrix & A, int ShiftN,
-                                   int ShiftM )  {
-int N,M;
-  return CreateReadMatrix ( A,N,M,ShiftN,ShiftM );
-}
-
-Boolean  CFile::CreateReadMatrix ( rmatrix & A, int & N, int & M,
-                                   int ShiftN, int ShiftM )  {
-intUniBin  iUB;
-realUniBin rUB;
-int        i,j;
-  FreeMatrixMemory ( A,N,ShiftN,ShiftM );
-  if (UniBin)  {
-    ReadFile   ( iUB,sizeof(intUniBin) );
-    UniBin2int ( iUB,N );
-    if (IOSuccess && (N>0))  {
-      ReadFile   ( iUB,sizeof(intUniBin) );
-      UniBin2int ( iUB,M );
-      if (IOSuccess && (M>0))  {
-        GetMatrixMemory ( A,N,M,ShiftN,ShiftM );
-        for (i=0;i<N;i++)
-          for (j=0;j<M;j++)  {
-            ReadFile    ( rUB,sizeof(realUniBin) );
-            UniBin2real ( rUB,A[ShiftN+i][ShiftM+j] );
-          }
-      }
-    }
-  } else  {
-    ReadFile ( &N,sizeof(N) );
-    if (N>0)  {
-      ReadFile ( &M,sizeof(M) );
-      if (M>0)  {
-        GetMatrixMemory ( A,N,M,ShiftN,ShiftM );
-        for (i=0;i<N;i++)
-          ReadFile ( &(A[ShiftN][ShiftM]),sizeof(realtype)*M );
-      }
-    }
-  }
-  return IOSuccess;
-}
-
-
-Boolean  CFile::WriteColumns ( rvector X, rvector Y, rvector Z,
-                               int len, int Shift, int MLength )  {
-//   WriteColumns writes data stored in X, Y and Z in the form
-// of columns, adding a blank line in the end. If Z (or Z and Y)
-// are set to NULL, then only X and Y (or only X) are written.
-//   Shift corresponds to the begining of arrays' enumeration
-// X[Shift..Shift+len-1].
-int  i,l;
-  l = Shift+len;
-  for (i=Shift;i<l;i++)  {
-    Write ( pstr("   ")  );
-    Write ( X[i],MLength );
-    if (Y)  {
-      Write ( pstr(",   ") );
-      Write ( Y[i],MLength );
-    }
-    if (Z)  {
-      Write ( pstr(",   ") );
-      Write ( Z[i],MLength );
-    }
-    LF();
-  }
-  return LF();
-}
-
-Boolean  CFile::WriteColumns ( rvector X, rvector Y,
-                               int len, int Shift, int MLength )  {
-  return WriteColumns ( X,Y,NULL,len,Shift,MLength );
-}
-
-int  CFile::ReadColumns ( int maxlen, rvector X, rvector Y, rvector Z,
-                          int xCol, int yCol, int zCol, int Shift )  {
-//   ReadColumns reads data stored by WriteColumns. X, Y, and Z must
-// be allocated prior to call.
-//   xCol, yCol and zCol specify the order number of columns
-// (starting from 0) to be read into X, Y and Z, correspondingly.
-// If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
-//   Shift corresponds to the begining of arrays' enumeration
-// X[Shift..Shift+len-1].
-//   Returns number of lines read.
-int   DataLen;
-char  S[1025];
-  DataLen = maxlen;
-  _ReadColumns ( DataLen,S,sizeof(S),X,Y,Z,xCol,yCol,zCol,Shift );
-  return DataLen;
-}
-
-int  CFile::ReadColumns ( int maxlen, rvector X, rvector Y,
-                          int xCol, int yCol, int Shift )  {
-  return  ReadColumns ( maxlen,X,Y,NULL,xCol,yCol,-1,Shift );
-}
-
-
-int  CFile::CreateReadColumns ( rvector & X, rvector & Y, rvector & Z,
-                                int xCol, int yCol, int zCol,
-                                int Shift )  {
-//   ReadColumns reads data stored by WriteColumns. X, Y, and Z
-// must be set to NULL prior to call. They will be allocated
-// within the procedure.
-//   xCol, yCol and zCol specify the order number of columns
-// (starting from 0) to be read into X, Y and Z, correspondingly.
-// If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
-//   Shift corresponds to the begining of arrays' enumeration
-// X[Shift..Shift+len-1].
-//   Returns number of lines read, errors are reported by ErrorCode().
-int      i,j,DataLen;
-char     S[1025];
-Boolean  Ok;
-  DataLen = 0;
-  ErrCode = 0;
-  if (!FileEnd())  {
-    i = 0;
-    j = 1;
-    // the loop terminates at first blank line
-    while ((i<j) && (!FileEnd()))  {
-      j = ReadLine ( S,sizeof(S) );
-      i = 0;
-      // check for blank line
-      while ((i<j) && (S[i]==' '))  i++;
-      DataLen++;
-    }
-    if (i>=j)  DataLen--;
-    if (DataLen>0)  {
-      Ok = GetVectorMemory(X,DataLen,Shift);
-      if (Ok && (yCol>=0))
-        Ok = Ok && GetVectorMemory(Y,DataLen,Shift);
-      if (Ok && (zCol>=0))
-        Ok = Ok && GetVectorMemory(Z,DataLen,Shift);
-      if (Ok)  {
-        reset();
-        _ReadColumns ( DataLen,S,sizeof(S),X,Y,Z,xCol,yCol,
-                       zCol,Shift );
-      } else  ErrCode = FileError_NoMemory;
-    } else  ErrCode = FileError_NoDataFound;
-  } else  ErrCode = FileError_NoDataFound;
-  return DataLen;
-}
-
-int  CFile::CreateReadColumns ( rvector & X, rvector & Y,
-                                int xCol, int yCol, int Shift )  {
-  return  CreateReadColumns ( X,Y,X,xCol,yCol,-1,Shift );
-}
-
-void  CFile::_ReadColumns ( int & DLen, pstr S, int SLen,
-                            rvector X, rvector Y, rvector Z,
-                            int xCol, int yCol, int zCol,
-                            int Shift )  {
-int      i,is,j,k,m,n,cmax;
-char     SV[256];
-realtype Res;
-  ErrCode = 0;
-  i       = 0;
-  cmax    = IMax(zCol,IMax(xCol,yCol));
-  while ((i<DLen) && (ErrCode==0))  {
-    k = ReadLine ( S,SLen );
-    RemoveDelimiters(S,k);
-    j = 0;
-    m = -1;
-    n = 0;
-    while ((m<cmax) && (ErrCode==0))  {
-      do {
-        PickOutNumber ( S,SV,k,j );
-        if ((m<0) && (SV[0]==char(0)) && (j>=k))  {
-          DLen = i;
-          return;
-        }
-        m++;
-      } while ((m!=xCol) && (m!=yCol) && (m!=zCol));
-      if (SV[0]==char(0))  {
-        if (n>0)  ErrCode = FileError_NoColumn;
-            else  ErrCode = FileError_ShortData;
-      } else  {
-        Res = GetNumber ( SV );
-        if (ErrCode==0)  {
-          is = i+Shift;
-          if      (m==xCol)  X[is] = Res;
-          else if (m==yCol)  Y[is] = Res;
-                       else  Z[is] = Res;
-          n++;
-        }
-      }
-    }
-    if ((ErrCode==0) && (n<2))  ErrCode = FileError_NoColumn;
-    i++;
-  }
-  if ((ErrCode==FileError_ShortData) && (i>1))  {
-    ErrCode = 0;
-    DLen    = i-1;
-  }
-  if (ErrCode!=0)  ErrCode = FileError_BadData;
-}
-
-void  RemoveDelimiters ( pstr S, int SLen )  {
-int j;
-  for (j=0;j<SLen;j++)
-    if ((S[j]==',') || (S[j]==';') ||
-        (S[j]==':') || (S[j]==char(9)))
-      S[j] = ' ';
-}
-
-void  PickOutNumber ( cpstr S, pstr SV, int SLen, int & j )  {
-int l;
-  l = 0;
-  while ((j<SLen) && (S[j]==' '))  j++;
-  if ((S[j]=='+') || (S[j]=='-'))  SV[l++] = S[j++];
-  if (S[j]=='.')                   SV[l++] = '0';
-  while ((j<SLen) && (S[j]!=' '))  SV[l++] = S[j++];
-  SV[l] = char(0);
-}
-
-realtype  CFile::GetNumber ( cpstr S )  {
-char *   endptr;
-realtype V;
-  V = strtod ( S,&endptr );
-  if ((*endptr!=' ') && (*endptr))
-    ErrCode = FileError_BadData;
-  return V;
-}
-
-cpstr FileError ( int ErrCode )  {
-  switch (ErrCode)  {
-    case 0                      : return "Ok";
-    case FileError_NoMemory     : return "Insufficient memory";
-    case FileError_NoDataFound  : return "No data found";
-    case FileError_NoColumn     : return "No column structure";
-    case FileError_BadData      : return "Incorrect data format";
-    case FileError_WrongMemoryAllocation
-                                : return "Wrong Memory Allocation";
-    default : return "Unknown I/O error";
-  }
-}
-
diff --git a/mmdb/file_.h b/mmdb/file_.h
deleted file mode 100755
index c0fe978..0000000
--- a/mmdb/file_.h
+++ /dev/null
@@ -1,302 +0,0 @@
-//  $Id: file_.h,v 1.23 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  file_  <interface>
-//       ~~~~~~~~~
-//  **** Classes :  CFile  - file I/O Support.
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef  __File__
-#define  __File__
-
-#ifndef  __STDIO_H
-#include <stdio.h>
-#endif
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-
-//  ========================  CFile Class  ========================
-
-#define  MaxFileNameLength                512
-
-#define  FM_Binary                        False
-#define  FM_Text                          True
-
-#define  GZM_NONE                         0
-#define  GZM_CHECK                        1
-#define  GZM_ENFORCE                      2
-#define  GZM_ENFORCE_GZIP                 2
-#define  GZM_ENFORCE_COMPRESS             3
-
-
-#define  FileError_NoMemory               110
-#define  FileError_ShortData              111
-#define  FileError_NoDataFound            112
-#define  FileError_NoColumn               113
-#define  FileError_BadData                114
-#define  FileError_WrongMemoryAllocation  115
-
-
-// ===================  Auxilary Functions  =========================
-
-#define syskey_unix  1
-#define syskey_win   2
-#define syskey_all   3
-
-extern cpstr GetFPath   ( pstr  FilePath, int syskey=syskey_unix );
-extern cpstr GetFName   ( cpstr FilePath, int syskey=syskey_unix );
-extern cpstr GetFExt    ( cpstr FilePath );
-extern cpstr ChangeExt  ( pstr  FilePath, cpstr newExt,
-                                          int syskey=syskey_unix );
-extern cpstr FileError        ( int   ErrCode     );
-extern void  RemoveDelimiters ( pstr  S, int SLen );
-extern void  PickOutNumber    ( cpstr S, pstr SV, int SLen, int & j );
-
-
-#ifdef _WIN32
-#define _dir_sep_c  '\\'
-#define _dir_sep    "\\"
-#else
-#define _dir_sep_c  '/'
-#define _dir_sep    "/"
-#endif
-
-
-// =========================  CFile  ================================
-
-DefineClass(CFile)
-
-class  CFile  {
-
-  public :
-
-    CFile ( word BufSize=4096 );
-    virtual  ~CFile();
-
-    // ---- control functions
-    //   FileName allows for "stdin", "stdout" and "stderr" as
-    // for standard UNIX streams.
-    void     assign      ( cpstr   FileName,
-                           Boolean Text=False,
-                           Boolean UniB=False,
-                           byte    gzMode=GZM_NONE );
-    //   assign for memory IO
-    void     assign     ( word poolSize, word sizeInc, pstr filePool );
-    void     GetFilePool ( pstr & filePool, word & fileSize );
-
-    pstr     FileName    () { return FName; }
-    Boolean  reset       ( Boolean ReadOnly=False, int retry=0 );
-                            // = true if opened, each retry 1 sec sleep
-    Boolean  erase       ();   // = true if erased
-    Boolean  exists      ();   // = true if exists
-    Boolean  parse       ( cpstr FileName ); // true if filled
-    Boolean  rename      ( cpstr NewFileName ); // true if renamed
-    Boolean  rewrite     ();    // = true if opened
-    Boolean  append      ();    // = true if opened
-    Boolean  isOpen      ();
-    long     Position    ();
-    long     FileLength  () { return FLength; }
-    Boolean  seek        ( long Position );
-    Boolean  FileEnd     ();
-    Boolean  Success     () { return IOSuccess; }
-    void     SetSuccess  () { IOSuccess = True; }
-    void     shut        ();
-
-    // ---- binary I/O
-    word     ReadFile     ( void * Buffer, word Count );
-    word     CreateRead   ( pstr & Line );
-    word     ReadTerLine  ( pstr Line, Boolean longLine=False );
-    Boolean  WriteFile    ( const void * Buffer, word Count );
-    Boolean  CreateWrite  ( cpstr Line );
-    Boolean  WriteTerLine ( cpstr Line, Boolean longLine=False );
-    //  machine-dependent binary I/O
-    Boolean  WriteReal   ( realtype * V );
-    Boolean  WriteFloat  ( realtype * V );
-    Boolean  WriteInt    ( int      * I );
-    Boolean  WriteShort  ( short    * S );
-    Boolean  WriteLong   ( long     * L );
-    Boolean  WriteBool   ( Boolean  * B );
-    Boolean  WriteByte   ( byte     * B );
-    Boolean  WriteWord   ( word     * W );
-    Boolean  ReadReal    ( realtype * V );
-    Boolean  ReadFloat   ( realtype * V );
-    Boolean  ReadInt     ( int      * I );
-    Boolean  ReadShort   ( short    * S );
-    Boolean  ReadLong    ( long     * L );
-    Boolean  ReadBool    ( Boolean  * B );
-    Boolean  ReadByte    ( byte     * B );
-    Boolean  ReadWord    ( word     * B );
-    Boolean  AddReal     ( realtype * V );
-    Boolean  AddFloat    ( realtype * V );
-    Boolean  AddInt      ( int      * I );
-    Boolean  AddShort    ( short    * S );
-    Boolean  AddLong     ( long     * L );
-    Boolean  AddByte     ( byte     * B );
-    Boolean  AddWord     ( word     * B );
-    //  complex data binary I/O
-    Boolean  WriteVector      ( rvector    V, int len,    int Shift );
-    Boolean  WriteVector      ( ivector   iV, int len,    int Shift );
-    Boolean  WriteVector      ( lvector   lV, int len,    int Shift );
-    Boolean  WriteVector      ( bvector    B, int len,    int Shift );
-    Boolean  ReadVector       ( rvector    V, int maxlen, int Shift );
-    Boolean  ReadVector       ( ivector   iV, int maxlen, int Shift );
-    Boolean  ReadVector       ( lvector   lV, int maxlen, int Shift );
-    Boolean  ReadVector       ( bvector    B, int maxlen, int Shift );
-    Boolean  CreateReadVector ( rvector &  V, int & len,  int Shift );
-    Boolean  CreateReadVector ( ivector & iV, int & len,  int Shift );
-    Boolean  CreateReadVector ( lvector & lV, int & len,  int Shift );
-    Boolean  CreateReadVector ( bvector &  B, int & len,  int Shift );
-    Boolean  CreateReadVector ( rvector &  V, int Shift );
-    Boolean  CreateReadVector ( ivector & iV, int Shift );
-    Boolean  CreateReadVector ( lvector & lV, int Shift );
-    Boolean  CreateReadVector ( bvector &  B, int Shift );
-    Boolean  WriteMatrix      ( rmatrix & A,  int N, int M,
-                                int  ShiftN,  int ShiftM );
-    Boolean  CreateReadMatrix ( rmatrix & A,  int ShiftN, int ShiftM );
-    Boolean  CreateReadMatrix ( rmatrix & A,  int & N, int & M,
-                                int ShiftN, int ShiftM );
-
-    /// ---- text I/O
-    Boolean  Write       ( cpstr  Line );     //!< writes without LF
-    Boolean  Write       ( realtype V, int length=10 ); //!< w/o LF
-    Boolean  Write       ( int     iV, int length=5  ); //!< w/o LF
-    Boolean  WriteLine   ( cpstr  Line );     //!< writes and adds LF
-    Boolean  LF          ();                      //!< just adds LF
-    word     ReadLine    ( pstr   Line, word MaxLen=255 );
-    word     ReadNonBlankLine ( pstr S, word MaxLen=255 );
-
-    ///  complex data text I/O
-
-    // writes with spaces and adds LF
-    Boolean  WriteDataLine  ( realtype X, realtype Y,
-                              int length=10 );
-
-    Boolean  WriteParameter ( cpstr S, realtype X, // writes parameter
-                              int ParColumn=40,   // name S and value X
-                              int length=10 );   // at column ParColumn
-                                                // and adds LF.
-
-    Boolean  WriteParameters ( cpstr S, int n_X, // writes parameter
-                               rvector X,      // name S and n_X values
-                               int ParColumn=40, // X[0..n_X-1] at col
-                               int length=10 );  // ParColumn, ads LF.
-
-    Boolean  ReadParameter  ( pstr S, realtype & X, // reads parameter
-                              int ParColumn=40 );   // name S and val X
-    Boolean  ReadParameter  ( pstr S, int & X,
-                              int ParColumn=40 );
-
-    Boolean  ReadParameters ( pstr S, int & n_X,  // reads parameter
-                              rvector X,          // name S, counts the
-                              int MaxLen=255,     // of values n_X and
-                              int ParColumn=40 ); // reads X[0..n_X-1].
-                                              // MaxLen gives sizeof(S)
-
-    //   WriteColumns writes data stored in X, Y and Z in the form
-    // of columns, adding a blank line in the end. If Z (or Z and Y)
-    // are set to NULL, then only X and Y (or only X) are written.
-    //   Shift corresponds to the begining of arrays' enumeration
-    // X[Shift..Shift+len-1].
-    Boolean  WriteColumns    ( rvector X, rvector Y, rvector Z,
-                               int len, int Shift, int MLength );
-    Boolean  WriteColumns    ( rvector X, rvector Y,
-                               int len, int Shift, int MLength );
-
-    //   ReadColumns reads data stored by WriteColumns. X, Y, and Z
-    // must be allocated prior to call.
-    //   xCol, yCol and zCol specify the order number of columns
-    // (starting from 0) to be read into X, Y and Z, correspondingly.
-    // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
-    //   Shift corresponds to the begining of arrays' enumeration
-    // X[Shift..Shift+len-1].
-    //   Returns number of lines read.
-    int      ReadColumns     ( int maxlen, rvector X, rvector Y, rvector Z,
-                               int xCol, int yCol, int zCol, int Shift );
-    int      ReadColumns     ( int maxlen, rvector X, rvector Y,
-                               int xCol, int yCol, int Shift );
-
-    //   CreateReadColumns reads data stored by WriteColumns. X, Y,
-    // and Z must be set to NULL prior to call. They will be allocated
-    // within the procedure.
-    //   xCol, yCol and zCol specify the order number of columns
-    // (starting from 0) to be read into X, Y and Z, correspondingly.
-    // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
-    //   Shift corresponds to the begining of arrays' enumeration
-    // X[Shift..Shift+len-1].
-    //   Returns number of lines read, errors are reported by
-    // ErrorCode().
-    int    CreateReadColumns ( rvector & X, rvector & Y, rvector & Z,
-                            int xCol, int yCol, int zCol, int Shift );
-    int    CreateReadColumns ( rvector & X, rvector & Y,
-                            int xCol, int yCol, int Shift );
-
-    // ---- miscellaneous
-    realtype GetNumber ( cpstr S );
-    FILE *   GetHandle () { return hFile; }
-
-  protected :
-    word     Buf_Size;
-    Boolean  TextMode,UniBin;
-    byte     gzipMode;
-    pstr     IOBuf;
-    word     BufCnt,BufLen,BufInc;
-    FILE   * hFile;
-    Boolean  EofFile;
-    pstr     FName;
-    long     FLength;
-    Boolean  IOSuccess;
-    int      ErrCode;
-
-    void  FreeBuffer   ();
-    void  _ReadColumns ( int & DLen, pstr S, int SLen,
-                         rvector X, rvector Y, rvector Z,
-                         int xCol, int yCol, int zCol, int Shift );
-
-  private :
-    int      gzipIO;
-    Boolean  StdIO,memIO;
-
-};
-
-
-extern void SetGZIPPath     ( pstr gzipPath,     pstr ungzipPath     );
-extern void SetCompressPath ( pstr compressPath, pstr uncompressPath );
-
-extern Boolean FileExists   ( cpstr FileName, PCFile f=NULL );
-
-
-#endif
-
diff --git a/mmdb/linalg_.cpp b/mmdb/linalg_.cpp
deleted file mode 100755
index 26012d1..0000000
--- a/mmdb/linalg_.cpp
+++ /dev/null
@@ -1,987 +0,0 @@
-//  $Id: linalg_.cpp,v 1.21 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    27.06.01   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  linalg_  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MMDB  ( MacroMolecular Data Base )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#include <stdio.h>
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __LinAlg__
-#include "linalg_.h"
-#endif
-
-
-//  ==========================  Jacobi  =============================
-
-
-void  Jacobi ( int     N,     // dimension of the matrix
-               rmatrix A,     // matrix to diagonalize; the lower
-                              // triangle, except the diagonal,
-                              // will remain unchanged
-               rmatrix T,     // eigenvectors placed as columns
-               rvector Eigen, // vector of eigenvalues, orderd
-                              // by increasing
-               rvector Aik,   // working array
-               int &   Signal // 0 <=> Ok, ItMax <=> iteration limit
-                              // exchausted.
-             )  {
-//  Diagonalization of symmetric matrices  by the method of Jacobi.
-//  Key  variables:
-//     ItMax  -  the maximum available number of iterations
-//     Eps1   -  is used in  SNA  and  CSA  calculations
-//     Eps2   -  is the level of the elimination of the
-//               non-diagonal matrix elements
-//     Eps3   -  the criterion to stop the iterations.
-//               The iterations stop if (1-Sigma1/Sigma2)<=Eps3
-//               where  Sigma1 is the dekart norm of the eigenvalues
-//               at the preceding iteration and  Sigma2 is
-//               the same for the current iteration.
-
-realtype Eps1,Eps2,Eps3;
-realtype Sigma1,Sigma2,OffDsq, SPQ,CSA,SNA,Q,P, HoldIK,HoldKI;
-int      ItMax;
-int      i,j,k,Iter;
-
-  Eps1  = 6.0e-9;
-  Eps2  = 9.0e-12;
-  Eps3  = 1.0e-8;
-  ItMax = 9999;
-
-  Signal = 0;
-
-  if (N<=1)  {
-    T[1][1]  = 1.0;
-    Eigen[1] = A[1][1];
-    return;
-  }
-
-  for (i=1;i<=N;i++)  {
-    for (j=1;j<=N;j++)
-      T[i][j] = 0.0;
-    T[i][i]  = 1.0;
-    Eigen[i] = A[i][i];
-  }
-
-  Sigma1 = 0.0;
-  OffDsq = 0.0;
-  
-  //  Sigma1  is the Dekart measure of the diagonal elements
-  //  OffDsq  is the Dekart measure of the non-diagonal elements
-
-  for (i=1;i<=N;i++)  {
-    Sigma1 += A[i][i]*A[i][i];
-    if (i<N)
-      for (j=i+1;j<=N;j++)
-        OffDsq += A[i][j]*A[i][j];
-  }
-
-  if (OffDsq<Eps2*Eps2)  return;
-
-  //  S      = OffDsq*2.0+Sigma1;
-  Iter   = 1;
-  HoldIK = 1.0;
-
-  while ((Iter<=ItMax) && (HoldIK>Eps3))  {
-
-    for (i=1;i<N;i++)
-      for (j=i+1;j<=N;j++)  {
-
-        Q = fabs(A[i][i]-A[j][j]);
-
-        if ((Q<=Eps1) || (fabs(A[i][j])>Eps2))  {
-          if (Q>Eps1)  {
-            P   = 2.0*A[i][j]*(Q/(A[i][i]-A[j][j]));
-            SPQ = sqrt(P*P+Q*Q);
-            CSA = sqrt((1.0+Q/SPQ)/2.0);
-            SNA = P/(SPQ*CSA*2.0);
-          } else  {
-            CSA = sqrt(0.5);
-            SNA = CSA;
-          }
-          for (k=1;k<=N;k++)  {
-            HoldKI  = T[k][i];
-            T[k][i] = HoldKI*CSA + T[k][j]*SNA;
-            T[k][j] = HoldKI*SNA - T[k][j]*CSA;
-          }
-
-          for (k=i;k<=N;k++)
-            if (k<=j)  {
-              Aik[k]  = A[i][k];
-              A[i][k] = CSA*Aik[k] + SNA*A[k][j];
-              if (k==j)  {
-                A[j][k] = SNA*Aik[k] - CSA*A[j][k];
-                Aik[j]  = SNA*Aik[i] - CSA*Aik[j];
-              }
-            } else  {
-              HoldIK  = A[i][k];
-              A[i][k] = CSA*HoldIK + SNA*A[j][k];
-              A[j][k] = SNA*HoldIK - CSA*A[j][k];
-            }
-
-          for (k=1;k<=j;k++)
-            if (k>i)
-              A[k][j] = SNA*Aik[k] - CSA*A[k][j];
-            else  {
-              HoldKI  = A[k][i];
-              A[k][i] = CSA*HoldKI + SNA*A[k][j];
-              A[k][j] = SNA*HoldKI - CSA*A[k][j];
-            }
-
-        }
-
-      }
-
-    Sigma2 = 0.0;
-    for (i=1;i<=N;i++)  {
-      Eigen[i] = A[i][i];
-      Sigma2  += Eigen[i]*Eigen[i];
-    }
-
-    HoldIK = fabs(1.0-Sigma1/Sigma2);
-    Sigma1 = Sigma2;
-    Iter++;
-
-  }
-
-  if (Iter>ItMax)  Signal = ItMax;
-
-  for (i=1;i<=N;i++)  {
-    k = i;
-    for (j=i;j<=N;j++)
-      if (Eigen[j]<Eigen[k])  k = j;
-    if (k!=i)  {
-      P = Eigen[k];
-      Eigen[k] = Eigen[i];
-      Eigen[i] = P;
-      for (j=1;j<=N;j++)  {
-        P = T[j][k];
-        T[j][k] = T[j][i];
-        T[j][i] = P;
-      }
-    }
-  }
-
-
-}
-
-
-// -----------------------------------------------------
-
-void  PbCholDecomp ( int        N,
-                     rvector    HDiag,
-                     realtype   MaxOff,
-                     realtype   MachEps,
-                     rmatrix    L,
-                     realtype & MaxAdd )  {
-
-//  A5.5.2  :  Perturbed Cholesky Decomposition
-// Part of the modular software system from
-// the appendix of the book "Numerical Methods for Unconstrained
-// Optimization and Nonlinear Equations" by Dennis & Schnabel 1983.
-
-int      i,j,k;
-realtype MinL,MinL2,S,MinLjj,MaxOffl, BB;
-
-  MaxOffl = MaxOff;
-  MinL    = sqrt(sqrt(MachEps))*MaxOffl;
-  if (MaxOffl==0.0)  {
-    for (i=1;i<=N;i++)  {
-      BB = fabs(HDiag[i]);
-      if (BB>MaxOffl)  MaxOffl = BB;
-    }
-    MaxOffl = sqrt(MaxOffl);
-  }
-
-  MinL2  = sqrt(MachEps)*MaxOffl;
-  MaxAdd = 0.0;
-  for (j=1;j<=N;j++)  {
-    S = 0.0;
-    if (j>1)
-      for (i=1;i<j;i++)
-        S += L[j][i]*L[j][i];
-    L[j][j] = HDiag[j] - S;
-    MinLjj  = 0.0;
-    if (j<N)
-      for (i=j+1;i<=N;i++)  {
-        S = 0.0;
-        if (j>1)
-          for (k=1;k<j;k++)
-            S += L[i][k]*L[j][k];
-        L[i][j] = L[j][i] - S;
-        BB = fabs(L[i][j]);
-        if (BB>MinLjj)  MinLjj = BB;
-      }
-    BB = MinLjj/MaxOffl;
-    if (BB>MinL)  MinLjj = BB;
-            else  MinLjj = MinL;
-    if (L[j][j]>MinLjj*MinLjj) L[j][j] = sqrt(L[j][j]);
-    else  {
-      if (MinL2>MinLjj)  MinLjj = MinL2;
-      BB = MinLjj*MinLjj-L[j][j];
-      if (BB>MaxAdd)  MaxAdd = BB;
-      L[j][j] = MinLjj;
-    }
-    if (j<N)
-      for (i=j+1;i<=N;i++)
-        L[i][j] /= L[j][j];
-  }
-
-}
-
-
-
-// -----------------------------------------------------
-
-void  LSolve ( int N, rmatrix L, rvector B, rvector Y )  {
-//  A3.2.3a  :  Cholesky's   L - Solution  of
-//              L*Y  =  B  ( given  B )
-int  i,j;
-  Y[1] = B[1]/L[1][1];
-  if (N>1)
-    for (i=2;i<=N;i++)  {
-      Y[i] = B[i];
-      for (j=1;j<i;j++)
-        Y[i] -= L[i][j]*Y[j];
-      Y[i] /= L[i][i];
-    }
-}
-
-
-// -----------------------------------------------------
-
-void  LTSolve ( int N, rmatrix L, rvector Y, rvector X )  {
-//  A3.2.3b  :   Cholesky's   LT - Solution  of
-//               LT*X  =  Y  ( given  Y )
-int  i,j;
-  X[N] = Y[N]/L[N][N];
-  if (N>1)
-    for (i=N-1;i>=1;i--)  {
-      X[i] = Y[i];
-      for (j=i+1;j<=N;j++)
-        X[i] -= L[j][i]*X[j];
-      X[i] /= L[i][i];
-    }
-}
-
-
-// -----------------------------------------------------
-
-void  ChSolve ( int N, rmatrix L, rvector G, rvector S )  {
-//  A3.2.3  :  Solution of the equation    L*LT*S = G
-//             by the  Cholesky's  method
-//int i;
-  LSolve  ( N,L,G,S );
-  LTSolve ( N,L,S,S );
-//  for (i=1;i<=N;i++)
-//    S[i] = -S[i];
-}
-
-
-
-//  ----------------------------------------------------
-
-void  FastInverse (  int N, rmatrix A, ivector J0,
-//#D                     realtype & Det,
-                     int & Signal )  {
-//
-//      17.01.91  <--  Last Date of Modification.
-//                    ----------------------------
-//
-// ================================================
-//
-//        Fast Inversion of the matrix  A
-//      by the method of  GAUSS - JOIRDAN  .
-//
-// ------------------------------------------------
-//
-//          Input  parameters  are  :
-//
-//     N   -   dimension of the matrix
-//     A   -   the matrix [1..N][1..N] to be inverted.
-//
-// ------------------------------------------------
-//
-//     J0  -   integer vector [1..N] for temporal storage
-//
-//
-// ------------------------------------------------
-//
-//          Output parameters  are  :
-//
-//     A   -   the inverted matrix
-//     Signal - the error key :
-//            = 0   <=>   O'K
-//              else
-//           degeneration was found, and
-//           the rang of matrix is  Signal-1.
-//
-//        Variable  Det  may return the determinant
-//     of matrix A.  To obtain it, remove all comments
-//     of form  //#D .
-//
-// ------------------------------------------------
-//
-//          Key  Variables  are  :
-//
-//     Eps   -  is the level for the degeneration
-//              detection.  Keep in mind,  that
-//              this routine does not norm the
-//              matrix given,  and thus Eps1
-//              is the  ABSOLUTE  value.
-//
-// ================================================
-//
-
-realtype  Eps = 1.0e-16;
-
-int       i,j,k,i0;
-realtype  A0,B;
-rvector   Ai,Ai0;
-
-  Signal = 0;
-  if  (N<=1)   {
-    if (fabs(A[1][1])<Eps)  {
-      Signal = 1;
-      return;
-    }
-    A[1][1] = 1.0/A[1][1];
-//#D   Det      = A[1][1];
-    return;
-  }
-
-  if (N==2)  {
-    A0 = A[1][1];
-    B  = A0*A[2][2] - A[1][2]*A[2][1];
-//#D   Det = B;
-    if (fabs(B)<Eps)  {
-      Signal = 1;
-      return;
-    }
-    A[1][1] = A[2][2]/B;
-    A[2][2] = A0/B;
-    B       = -B;
-    A[1][2] /= B;
-    A[2][1] /= B;
-    return;
-  }
-
-  for (i=1;i<=N;i++)  {
-    //  1. Finding of the leading element ( in A0 );
-    //     i0  is the number of the leading string
-    A0 = 0.0;
-    i0 = 0;
-    for (j=i;j<=N;j++)  {
-      if (fabs(A[j][i])>A0)  {
-        A0 = fabs(A[j][i]);
-        i0 = j;
-      }
-    }
-    if (A0<Eps)  {
-      Signal = i;   //  Degeneration is found here
-      return;
-    }
-
-    //  2. Swapping the string
-    J0[i] = i0;
-    B     = 1.0/A[i0][i];
-    Ai    = A[i0];
-    Ai0   = A[i];
-    A[i]  = Ai;
-    A[i0] = Ai0;
-    for (j=1;j<=N;j++)
-      Ai[j] = Ai[j]*B;
-    Ai[i] = B;
-
-    //  3. Substracting the strings
-    for (j=1;j<=N;j++)
-      if (i!=j)  {
-        Ai0 = A[j];
-        B   = Ai0[i];
-        Ai0[i] = 0.0;
-        for (k=1;k<=N;k++)
-          Ai0[k] = Ai0[k] - B*Ai[k];
-       }
-
-//#D   Det = Det/Ai[i];
-
-  }
-
-  //  4.  Back Swapping the columns
-  for (i=N;i>=1;i--)  {
-    j = J0[i];
-    if (j!=i)  {
-//#D     Det = -Det;
-      for (k=1;k<=N;k++)  {
-        B       = A[k][i];
-        A[k][i] = A[k][j];
-        A[k][j] = B;
-      }
-    }
-  }
-
-  return;
-
-}    //  End of the procedure  FastInverse
-
-
-
-
-//  ----------------------------------------------------
-
-realtype Sign ( realtype A, realtype B )  {
-  if (B>=0.0)  return  A;
-         else  return -A;
-}
-
-realtype SrX2Y2 ( realtype X, realtype Y )  {
-realtype Ax,Ay;
-  Ax = fabs(X);
-  Ay = fabs(Y);
-  if (Ay>Ax)   return  Ay*sqrt((X*X)/(Y*Y)+1.0);
-  if (Ay==Ax)  return  Ax*sqrt(2.0);
-  return  Ax*sqrt((Y*Y)/(X*X)+1.0);
-}
-
-
-//  ----------------------------------------------------
-
-void  SVD ( int    NA,    int     M,    int N,
-            rmatrix A,    rmatrix U,    rmatrix V,
-            rvector W,    rvector RV1,
-            Boolean MatU, Boolean MatV,
-            int & RetCode )  {
-//
-//      13.12.01  <--  Last Modification Date
-//                    ------------------------
-//
-// ================================================
-//
-//         The    Singular Value Decomposition
-//    of the matrix  A  by the algorithm from
-//      G.Forsait, M.Malkolm, K.Mouler.  Numerical
-//    methods of mathematical calculations
-//    M., Mir, 1980.
-//
-//         Matrix  A  is represented as
-//
-//         A  =  U * W * VT
-//
-// ------------------------------------------------
-//
-//  All dimensions are indexed from 1 on.
-//
-// ------------------------------------------------
-//
-//         Input  parameters:
-//
-//     NA  -   number of lines in A. NA may be
-//           equal to M or N  only.  If NA=M
-//           then usual SVD will be made. If MA=N
-//           then matrix A is transposed before
-//           the decomposition, and the meaning of
-//           output parameters  U  and  V  is
-//           swapped (U accepts VT and VT accepts U).
-//           In other words, matrix  A  has physical
-//           dimension of  M x N , same as U and V;
-//           however the logical dimension of it
-//           remains that of  N x M .
-//     M   -   number of lines in  U
-//     N   -   number of columns in  U,V and length
-//           of  W,RV1 .  Always provide  M >= N  !
-//     A   -   matrix [1..M][1..N] or [1..N][1..M]
-//           to be decomposed. The matrix does not
-//           change,  and it may coincide with  U  or
-//           V, if NA=M (in which case  A  does change)
-//     MatU -  compute  U , if set True
-//     MatV -  compute  V , if set True
-//     RV1  -  temporary array [1..N].
-//     U    - should be always supplied as an array of
-//            [1..M][1..N], M>=N .
-//     V    - should be suuplied as an array of
-//            [1..N][1..N] if MatV is True .
-//
-// ------------------------------------------------
-//
-//          Output parameters  are  :
-//
-//     W   -   N non-ordered singular values,
-//           if  RetCode=0. If RetCode<>0, the
-//           RetCode+1 ... N -th values are still
-//           valid
-//     U   -   matrix of right singular vectors
-//           (arranged in columns),  corresponding
-//           to the singular values in  W,  if
-//           RetCode=0 and MatU is True.  If MatU
-//           is False, U  is still used as a
-//           temporary array. If RetCode<>0 then
-//           the  RetCode+1 ... N -th vectors
-//           are  valid
-//     V   -   matrix of left singular vectors
-//           (arranged in columns),  corresponding
-//           to the singular values in  W,  if
-//           RetCode=0 and MatV is True. If MatV
-//           is False, V is not used and may be set
-//           to NULL. If RetCode<>0 then the
-//           RetCode+1 ... N -th vectors are valid
-//     RetCode - the error key :
-//            = 0   <=>   O'K
-//              else
-//            = k, if the k-th singular value
-//                 was not computed after 30 iterations.
-//
-// ------------------------------------------------
-//
-//          Key  Variables  are  :
-//
-//     ItnLimit  -  the limit for iterations
-//
-//     This routine does not use any machine-dependent
-//  constants.
-//
-// ================================================
-//
-//
-int       ItnLimit=300;
-int       i,j,k,l,i1,k1,l1,its,mn,ExitKey;
-realtype  C,G,F,X,S,H,Y,Z,Scale,ANorm,GG;
-
-  l1      = 0;  // this is to keep compiler happy
-  RetCode = 0;
-
-  if (U!=A)  {
-    if (NA==M)
-      for (i=1;i<=M;i++)
-        for (j=1;j<=N;j++)
-          U[i][j] = A[i][j];
-    else
-      for (i=1;i<=M;i++)
-        for (j=1;j<=N;j++)
-          U[i][j] = A[j][i];
-  }
-
-  G     = 0.0;
-  Scale = 0.0;
-  ANorm = 0.0;
-
-  for (i=1;i<=N;i++)  {
-    l      = i+1;
-    RV1[i] = Scale*G;
-    G      = 0.0;
-    S      = 0.0;
-    Scale  = 0.0;
-    if (i<=M)  {
-      for (k=i;k<=M;k++)
-        Scale += fabs(U[k][i]);
-      if (Scale!=0.0)  {
-        for (k=i;k<=M;k++)  {
-          U[k][i] /= Scale;
-          S       += U[k][i]*U[k][i];
-        }
-        F = U[i][i];
-        G = -Sign(sqrt(S),F);
-        H = F*G-S;
-        U[i][i] = F-G;
-        if (i!=N)
-          for (j=l;j<=N;j++)  {
-            S = 0.0;
-            for (k=i;k<=M;k++)
-              S += U[k][i]*U[k][j];
-            F = S/H;
-            for (k=i;k<=M;k++)
-              U[k][j] += F*U[k][i];
-          }
-        for (k=i;k<=M;k++)
-          U[k][i] *= Scale;
-      }
-    }
-
-    W[i]  = Scale*G;
-    G     = 0.0;
-    S     = 0.0;
-    Scale = 0.0;
-
-    if ((i<=M) && (i!=N))  {
-      for (k=l;k<=N;k++)
-        Scale += fabs(U[i][k]);
-      if (Scale!=0.0)  {
-        for (k=l;k<=N;k++)  {
-          U[i][k] /= Scale;
-          S       += U[i][k]*U[i][k];
-        }
-        F = U[i][l];
-        G = -Sign(sqrt(S),F);
-        H = F*G-S;
-        U[i][l] = F-G;
-        for (k=l;k<=N;k++)
-          RV1[k] = U[i][k]/H;
-        if (i!=M)
-          for (j=l;j<=M;j++)  {
-            S = 0.0;
-            for (k=l;k<=N;k++)
-              S += U[j][k]*U[i][k];
-            for (k=l;k<=N;k++)
-              U[j][k] += S*RV1[k];
-          }
-        for (k=l;k<=N;k++)
-          U[i][k] *= Scale;
-      }
-    }
-
-    ANorm = RMax( ANorm,fabs(W[i])+fabs(RV1[i]) );
-
-  }
-
-  //   Accumulation of the right-hand transformations
-
-  if  (MatV)
-    for (i=N;i>=1;i--)  {
-      if (i!=N)  {
-        if (G!=0.0)  {
-          for (j=l;j<=N;j++)
-            V[j][i] = (U[i][j]/U[i][l]) / G;
-          for (j=l;j<=N;j++)  {
-            S = 0.0;
-            for (k=l;k<=N;k++)
-              S += U[i][k]*V[k][j];
-            for (k=l;k<=N;k++)
-              V[k][j] += S*V[k][i];
-          }
-        }
-        for (j=l;j<=N;j++)  {
-          V[i][j] = 0.0;
-          V[j][i] = 0.0;
-        }
-      }
-
-      V[i][i] = 1.0;
-      G       = RV1[i];
-      l       = i;
-
-    }
-
-
-  //   Accumulation of the left-hand transformations
-
-  if (MatU)  {
-    mn = N;
-    if (M<N)  mn = M;
-
-    for (i=mn;i>=1;i--)  {
-      l = i+1;
-      G = W[i];
-      if (i!=N)
-        for (j=l;j<=N;j++)
-          U[i][j] = 0.0;
-      if (G!=0.0)  {
-        if (i!=mn)
-          for (j=l;j<=N;j++)  {
-            S = 0.0;
-            for (k=l;k<=M;k++)
-              S += U[k][i]*U[k][j];
-            F = (S/U[i][i]) / G;
-            for (k=i;k<=M;k++)
-              U[k][j] += F*U[k][i];
-          }
-        for (j=i;j<=M;j++)
-          U[j][i] /= G;
-      } else
-        for (j=i;j<=M;j++)
-          U[j][i] = 0.0;
-
-      U[i][i] += 1.0;
-
-    }
-  }
-
-  //   Diagonalization of the two-diagonal form.
-
-  for (k=N;k>=1;k--)  {
-    k1  = k-1;
-    its = 0;
-
-    do  {
-      ExitKey  = 0;
-      l        = k+1;
-      while ((ExitKey==0) && (l>1))  {
-        l--;
-        l1 = l-1;
-        if (fabs(RV1[l])+ANorm==ANorm)   ExitKey=1;
-        else if (l1>0)  {
-          if (fabs(W[l1])+ANorm==ANorm)  ExitKey=2;
-        }
-      }
-
-//      if (ExitKey!=1)  {  <-- this is original statement
-      if (ExitKey>1)  {  // <-- prevents from corruption due to l1<1.
-                         // This is a rare case as RV1[1] should be
-                         // always 0.0 . Apparently this logics is
-                         // on the edge of float-point arithmetic,
-                         // therefore extra precaution for the case
-                         // of l1<1 was found necessary.
-        C       = 0.0;
-        S       = 1.0;
-        ExitKey = 0;
-        i       = l;
-        while ((ExitKey==0) && (i<=k))  {
-          F       =  S*RV1[i];
-          RV1[i]  =  C*RV1[i];
-          if (fabs(F)+ANorm==ANorm)  ExitKey = 1;
-          else  {
-            G = W[i];
-            H = SrX2Y2(F,G);
-            W[i] = H;
-            C = G/H;
-            S = -F/H;
-            if (MatU)
-              for (j=1;j<=M;j++)  {
-                Y         =  U[j][l1];
-                Z         =  U[j][i];
-                U[j][l1]  =  Y*C+Z*S;
-                U[j][i]   =  -Y*S+Z*C;
-              }
-            i++;
-          }
-        }
-      }
-
-      //    Convergence  Checking
-
-      Z = W[k];
-      if (l!=k)  {
-        if (its>=ItnLimit)  {
-          RetCode = k;
-          return;
-        }
-        its++;
-        X  =  W[l];
-        Y  =  W[k1];
-        G  =  RV1[k1];
-        H  =  RV1[k];
-        F  =  ((Y-Z)*(Y+Z) + (G-H)*(G+H)) / ( 2.0*H*Y );
-        if (fabs(F)<=1.0)  GG = Sign(sqrt(F*F+1.0),F);
-                     else  GG = F*sqrt(1.0+1.0/F/F);
-        F  =  ((X-Z)*(X+Z) + H*(Y/(F+GG)-H)) / X;
-
-        //   Next  QR - Transformation
-
-        C  =  1.0;
-        S  =  1.0;
-        for (i1=l;i1<=k1;i1++)  {
-          i = i1+1;
-          G = RV1[i];
-          Y = W[i];
-          H = S*G;
-          G = C*G;
-          Z = SrX2Y2(F,H);
-          RV1[i1] = Z;
-          C = F/Z;
-          S = H/Z;
-          F = X*C+G*S;
-          G = -X*S+G*C;
-          H = Y*S;
-          Y = Y*C;
-          if (MatV)
-            for (j=1;j<=N;j++)  {
-              X        = V[j][i1];
-              Z        = V[j][i];
-              V[j][i1] = X*C+Z*S;
-              V[j][i]  = -X*S+Z*C;
-            }
-
-          Z = SrX2Y2(F,H);
-          W[i1] = Z;
-          if (Z!=0.0)  {
-            C = F/Z;
-            S = H/Z;
-          }
-          F = C*G+S*Y;
-          X = -S*G+C*Y;
-          if (MatU)
-            for (j=1;j<=M;j++)  {
-              Y        = U[j][i1];
-              Z        = U[j][i];
-              U[j][i1] = Y*C+Z*S;
-              U[j][i]  = -Y*S+Z*C;
-            }
-
-        }
-
-        RV1[l] = 0.0;
-        RV1[k] = F;
-        W[k]   = X;
-      
-      } else if (Z<0.0)  {
-
-        W[k] = -Z;
-        if (MatV)
-          for (j=1;j<=N;j++)
-            V[j][k] = -V[j][k];
-      }
-
-    } while (l!=k);
-
-  }
-
-}
-
-//  -----------------------------------------------------
-
-void  OrderSVD ( int M, int N, rmatrix U, rmatrix V,
-                 rvector W, Boolean MatU, Boolean MatV )  {
-
-int       i,k,j;
-realtype  P;
-
-  //  External loop of the re-ordering
-  for (i=1;i<N;i++)  {
-    k = i;
-    P = W[i];
-
-    //  Internal loop :  finding of the index of greatest
-    //  singular value over the remaining ones.
-    for (j=i+1;j<=N;j++)
-      if (W[j]>P)  {
-        k = j;
-        P = W[j];
-      }
-
-    if (k!=i)  {
-      //  Swapping the singular value
-      W[k] = W[i];
-      W[i] = P;
-      //  Swapping the U's columns (  if  needed  )
-      if (MatU)
-        for (j=1;j<=M;j++)  {
-          P       = U[j][i];
-          U[j][i] = U[j][k];
-          U[j][k] = P;
-        }
-      //  Swapping the V's columns ( if  needed )
-      if (MatV)
-        for (j=1;j<=N;j++)  {
-          P       = V[j][i];
-          V[j][i] = V[j][k];
-          V[j][k] = P;
-        }
-    }
- 
-  }
-
-}
-
-
-/*
-
-#ifndef  __STDIO_H
-#include <stdio.h>
-#endif
-
-int main ( int argc, char ** argv, char ** env )  {
-//  Test Jacobi
-matrix   A,T,A1;
-vector   Eigen,Aik;
-realtype SR;
-int      N,i,j,k,Signal;
-
-  N = 4;
-
-  GetMatrixMemory ( A,N,N,1,1 );
-  GetMatrixMemory ( T,N,N,1,1 );
-  GetMatrixMemory ( A1,N,N,1,1 );
-  GetVectorMemory ( Eigen,N,1 );
-  GetVectorMemory ( Aik  ,N,1 );
-
-  k = 1;
-  for (i=1;i<=N;i++)
-    for (j=i;j<=N;j++)  {
-      A[i][j]  = k++;
-      A[i][j] *= 1000.0;
-      A[j][i]  = A[i][j];
-    }
-
-  printf ( "  INITIAL MATRIX:\n" );
-  for (i=1;i<=N;i++)  {
-    for (j=1;j<=N;j++)
-      printf ( "  %10.4f",A[i][j] );
-    printf ( "\n" );
-  }
-
-  Jacobi (  N,A,T,Eigen,Aik,Signal );
-
-  printf ( "\n  EIGEN VALUES AND EIGEN VECTORS:\n" );
-  for (i=1;i<=N;i++)  {
-    printf ( "  %10.4f    ",Eigen[i] );
-    for (j=1;j<=N;j++)
-      printf ( "  %10.4f",T[j][i] );
-    printf ( "\n" );
-  }
-  printf ( "\n       measure: " );
-  for (i=1;i<=N;i++)  {
-    SR = 0.0;
-    for (j=1;j<=N;j++)
-      SR += T[j][i]*T[j][i];
-    printf ( "  %10.4f",sqrt(SR) );
-  }
-  printf ( "\n" );
-
-  for (i=1;i<=N;i++)
-    for (j=1;j<=N;j++)  {
-      A1[i][j] = 0.0;
-      for (k=1;k<=N;k++)
-        A1[i][j] += T[i][k]*Eigen[k]*T[j][k];
-    }
-
-  printf ( "\n  RESTORED INITIAL MATRIX:\n" );
-  for (i=1;i<=N;i++)  {
-    for (j=1;j<=N;j++)
-      printf ( "  %10.4f",A1[j][i] );
-    printf ( "\n" );
-  }
-
-  FreeMatrixMemory ( A,N,1,1 );
-  FreeMatrixMemory ( T,N,1,1 );
-  FreeMatrixMemory ( A1,N,1,1 );
-  FreeVectorMemory ( Eigen,1 );
-  FreeVectorMemory ( Aik  ,1 );
-
-
-}
-
-*/
-
diff --git a/mmdb/linalg_.h b/mmdb/linalg_.h
deleted file mode 100755
index 9813ee3..0000000
--- a/mmdb/linalg_.h
+++ /dev/null
@@ -1,233 +0,0 @@
-//  $Id: linalg_.h,v 1.21 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    27.06.01   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  linalg_  <interface>
-//       ~~~~~~~~~
-//  **** Project :  MMDB  ( MacroMolecular Data Base )
-//       ~~~~~~~~~
-//
-//  (C) E.Krissinel  2000-2008
-//
-//  =================================================================
-//
-//
-
-#ifndef __LinAlg__
-#define __LinAlg__
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-
-//  ==========================  Jacobi  =============================
-
-
-///  Diagonalization of symmetric matrices A[1..N][1..N]
-/// by the method of Jacobi.
-extern void  Jacobi ( int     N,     //!< dimension of the matrix
-                      rmatrix A,     //!< matrix to diagonalize; the
-                                     /// lower triangle, except the
-                                     /// diagonal, will remain unchanged
-                      rmatrix T,     //!< eigenvectors placed as columns
-                      rvector Eigen, //!< vector of eigenvalues, orderd
-                                     /// by increasing
-                      rvector Aik,   //!< working array
-                      int &  Signal  //!< 0 <=> Ok, ItMax <=> iteration
-                                     /// limit exchausted.
-                    );
-
-
-//  A5.5.2  :  Perturbed Cholesky Decomposition
-extern void  PbCholDecomp ( int        N,
-                            rvector    HDiag,
-                            realtype   MaxOff,
-                            realtype   MachEps,
-                            rmatrix    L,
-                            realtype & MaxAdd );
-
-//  A3.2.3a  :  Cholesky's   L - Solution  of
-//              L*Y  =  B  ( given  B )
-extern void  LSolve ( int N, rmatrix L, rvector B, rvector Y );
-
-//  A3.2.3b  :  Cholesky's   LT - Solution  of
-//              LT*X  =  Y  ( given  Y )
-extern void  LTSolve ( int N, rmatrix L, rvector Y, rvector X );
-
-//  A3.2.3   :  Solution of the equation    L*LT*S = G
-//              by the  Cholesky's  method
-extern void  ChSolve ( int N, rmatrix L, rvector G, rvector S );
-
-
-//  ----------------------------------------------------
-  
-extern void  FastInverse (  int N, rmatrix A, ivector J0,
-//#D                          realtype &  Det,
-                            int & Signal );
-//
-//      13.09.90  <--  Last Modification Date
-//                    ------------------------
-//
-// ================================================
-//
-//        Fast Inversion of the matrix  A
-//      by the method of  GAUSS - JORDAN  .
-//
-// ------------------------------------------------
-//
-//          Input  parameters  are  :
-//
-//     N   -   dimension of the matrix
-//     A   -   the matrix [1..N][1..N] to be inverted.
-// ------------------------------------------------
-//
-//     J0  -   integer vector [1..N] for temporal storage
-//
-// ------------------------------------------------
-//
-//          Output parameters  are  :
-//
-//     A   -   the inverted matrix
-//     Signal - the error key :
-//            = 0   <=>   O'K
-//             else
-//            degeneration was found, and
-//            the rang of matrix is  Signal-1.
-//
-//        Variable  Det  may return the determinant
-//     of matrix A.  To obtain it, remove all comments
-//     of form  //#D.
-//
-// ================================================
-
-
-//  ----------------------------------------------------
-
-
-void  SVD ( int    NA,    int     M,    int N,
-            rmatrix A,    rmatrix U,    rmatrix V,
-            rvector W,    rvector RV1,
-            Boolean MatU, Boolean MatV,
-            int & RetCode );
-//
-//      13.12.01  <--  Last Modification Date
-//                    ------------------------
-//
-// ================================================
-//
-//         The    Singular Value Decomposition
-//    of the matrix  A  by the algorithm from
-//      G.Forsait, M.Malkolm, K.Mouler.  Numerical
-//    methods of mathematical calculations //
-//    M., Mir, 1980.
-//
-//         Matrix  A  is represented as
-//
-//         A  =  U * W * VT
-//
-// ------------------------------------------------
-//
-//  All dimensions are indexed from 1 on.
-//
-// ------------------------------------------------
-//
-//         Input  parameters:
-//
-//     NA  -   number of lines in A. NA may be
-//           equal to M or N  only.  If NA=M
-//           then usual SVD will be made. If MA=N
-//           then matrix A is transposed before
-//           the decomposition, and the meaning of
-//           output parameters  U  and  V  is
-//           swapped (U accepts VT and VT accepts U).
-//           In other words, matrix  A  has physical
-//           dimension of  M x N , same as U and V;
-//           however the logical dimension of it
-//           remains that of  N x M .
-//     M   -   number of lines in  U
-//     N   -   number of columns in  U,V and length
-//           of  W,RV1 .  Always provide  M >= N  !
-//     A   -   matrix [1..M][1..N] or [1..N][1..M]
-//           to be decomposed. The matrix does not
-//           change,  and it may coincide with  U  or
-//           V, if NA=M (in which case  A  does change)
-//     MatU -  compute  U , if set True
-//     MatV -  compute  V , if set True
-//     RV1  -  temporary array [1..N].
-//     U    - should be always supplied as an array of
-//            [1..M][1..N], M>=N .
-//     V    - should be suuplied as an array of
-//            [1..N][1..N] if MatV is True .
-//
-// ------------------------------------------------
-//
-//          Output parameters  are  :
-//
-//     W   -   N non-ordered singular values,
-//           if  RetCode=0. If RetCode<>0, the
-//           RetCode+1 ... N -th values are still
-//           valid
-//     U   -   matrix of right singular vectors
-//           (arranged in columns),  corresponding
-//           to the singular values in  W,  if
-//           RetCode=0 and MatU is True.  If MatU
-//           is False, U  is still used as a
-//           temporary array. If RetCode<>0 then
-//           the  RetCode+1 ... N -th vectors
-//           are  valid
-//     V   -   matrix of left singular vectors
-//           (arranged in columns),  corresponding
-//           to the singular values in  W,  if
-//           RetCode=0 and MatV is True. If MatV
-//           is False, V is not used and may be set
-//           to NULL. If RetCode<>0 then the
-//           RetCode+1 ... N -th vectors are valid
-//     RetCode - the error key :
-//            = 0   <=>   O'K
-//              else
-//            = k, if the k-th singular value
-//                 was not computed after 30 iterations.
-//
-// ------------------------------------------------
-//
-//          Key  Variables  are  :
-//
-//     ItnLimit  -  the limit for iterations
-//
-//     This routine does not use any machine-dependent
-//  constants.
-//
-// ================================================
-//
-//
-
-void  OrderSVD ( int M, int N, rmatrix U, rmatrix V,
-                 rvector W, Boolean MatU, Boolean MatV );
-
-
-#endif
diff --git a/mmdb/machine_.cpp b/mmdb/machine_.cpp
deleted file mode 100755
index 0e3e55b..0000000
--- a/mmdb/machine_.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-//  $Id: machine_.cpp,v 1.21 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   machine_  <implementation>
-//       ~~~~~~~~~
-//  **** Functions : GetMachineID   - returns ID code for the machine
-//       ~~~~~~~~~~~ GetMachineName - returns name of a machine
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __Machine__
-#include "machine_.h"
-#endif
-
-
-#ifdef CALL_LIKE_SUN
-
-int GetMachineID()  {
-int k = CALL_LIKE_SUN;
-  switch (k)  {
-    case 1  : return MACHINE_ALLIANT;
-    case 2  : return MACHINE_CONVEX;
-    case 3  : return MACHINE_ESV;
-    case 4  : return MACHINE_SGI;
-    case 5  : return MACHINE_SOLBOURNE;
-    case 6  : return MACHINE_SOLARIS;
-    case 7  : return MACHINE_ALPHA;
-    case 8  : return MACHINE_F2C_G77;
-    case 9  : return MACHINE_LINUX;
-    default : return MACHINE_UNKNOWN;
-  }
-}
-
-#elif defined(CALL_LIKE_HPUX)
-
-int GetMachineID()  {
-int k = CALL_LIKE_HPUX;
-  switch (k)  {
-    case 1  : return MACHINE_RS6000;
-    case 2  : return MACHINE_HP9000;
-    default : return MACHINE_UNKNOWN;
-  }
-}
-
-#elif defined(CALL_LIKE_STARDENT)
-
-int GetMachineID()  {
-int k = CALL_LIKE_STARDENT;
-  switch (k)  {
-    case 1  : return MACHINE_ARDENT;
-    case 2  : return MACHINE_TITAN;
-    case 3  : return MACHINE_STARDENT;
-    default : return MACHINE_UNKNOWN;
-  }
-}
-
-#elif defined(CALL_LIKE_VMS)
-
-int GetMachineID()  {
-  return MACHINE_VMS;
-}
-
-#elif defined(CALL_LIKE_MVS)
-
-int GetMachineID()  {
-  return MACHINE_MVS;
-}
-
-#else
-
-int GetMachineID()  {
-  return MACHINE_UNKNOWN;
-}
-
-#endif
-
-static cpstr MCH_SGI       = cpstr("Silicon Graphics");
-static cpstr MCH_RS6000    = cpstr("IBM RS/6000");
-static cpstr MCH_ALLIANT   = cpstr("Alliant");
-static cpstr MCH_ARDENT    = cpstr("Ardent");
-static cpstr MCH_TITAN     = cpstr("Titan");
-static cpstr MCH_STARDENT  = cpstr("Stardent");
-static cpstr MCH_CONVEX    = cpstr("Convex");
-static cpstr MCH_ESV       = cpstr("Evans or Sutherland");
-static cpstr MCH_HP9000    = cpstr("Hewlett Packard 9000");
-static cpstr MCH_SOLBOURNE = cpstr("Solbourne");
-static cpstr MCH_SOLARIS   = cpstr("Solaris");
-static cpstr MCH_ALPHA     = cpstr("DEC Alpha");
-static cpstr MCH_VMS       = cpstr("A VMS machine");
-static cpstr MCH_MVS       = cpstr("MS Windows");
-static cpstr MCH_F2C_G77   = cpstr("SUN compatible");
-static cpstr MCH_LINUX     = cpstr("Linux");
-
-cpstr GetMachineName ( int MachineID )  {
-  switch (MachineID)  {
-    case MACHINE_SGI       : return MCH_SGI;
-    case MACHINE_RS6000    : return MCH_RS6000;
-    case MACHINE_ALLIANT   : return MCH_ALLIANT;
-    case MACHINE_ARDENT    : return MCH_ARDENT;
-    case MACHINE_TITAN     : return MCH_TITAN;
-    case MACHINE_STARDENT  : return MCH_STARDENT;
-    case MACHINE_CONVEX    : return MCH_CONVEX;
-    case MACHINE_ESV       : return MCH_ESV;
-    case MACHINE_HP9000    : return MCH_HP9000;
-    case MACHINE_SOLBOURNE : return MCH_SOLBOURNE;
-    case MACHINE_SOLARIS   : return MCH_SOLARIS;
-    case MACHINE_ALPHA     : return MCH_ALPHA;
-    case MACHINE_VMS       : return MCH_VMS;
-    case MACHINE_MVS       : return MCH_MVS;
-    case MACHINE_F2C_G77   : return MCH_F2C_G77;
-    case MACHINE_LINUX     : return MCH_LINUX;
-    default                :
-    case MACHINE_UNKNOWN   : return pstr("Unidentified machine");
-  }
-}
-
-cpstr GetMachineName()  {
-  return GetMachineName ( GetMachineID() );
-}
-
diff --git a/mmdb/math_.cpp b/mmdb/math_.cpp
deleted file mode 100755
index 35e7fa2..0000000
--- a/mmdb/math_.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-//  $Id: math_.cpp,v 1.20 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    10.04.03   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  Math_ <implementation>
-//       ~~~~~~~~~
-//  **** Functions :   GetTorsion
-//       ~~~~~~~~~~~   GetAngle
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __Math__
-#include "math_.h"
-#endif
-
-// ------------------------------------------------------------------
-
-realtype  GetTorsion ( rvector U, rvector W, rvector V )  {
-//      U     W      V
-//   o<----o----->o----->o
-//
-realtype A[3],B[3],C[3],Wmag,S,T;
-
-  A[0] = U[1]*W[2] - W[1]*U[2];
-  A[1] = U[2]*W[0] - W[2]*U[0];
-  A[2] = U[0]*W[1] - W[0]*U[1];
-
-  B[0] = V[1]*W[2] - W[1]*V[2];
-  B[1] = V[2]*W[0] - W[2]*V[0];
-  B[2] = V[0]*W[1] - W[0]*V[1];
-
-  C[0] = A[1]*B[2] - B[1]*A[2];
-  C[1] = A[2]*B[0] - B[2]*A[0];
-  C[2] = A[0]*B[1] - B[0]*A[1];
-
-  Wmag = sqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]);
-
-  S    = C[0]*W[0] + C[1]*W[1] + C[2]*W[2];
-  T    = A[0]*B[0] + A[1]*B[1] + A[2]*B[2];
-  T   *= Wmag;
-
-  if ((S==0.0) && (T==0.0))  return NO_TORSION;
-                       else  return atan2(S,T);
-
-}
-
-
-realtype GetAngle ( rvector v1, rvector v2 )  {
-realtype l1,l2;
-
-  l1 = v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2];
-  if (l1==0.0)  l1 = 1.0;
-  l2 = v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2];
-  if (l2==0.0)  l2 = 1.0;
-
-  return  acos((v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])/sqrt(l1*l2));
-
-}
-
-
-#define  nCombMax  500
-
-realtype Combinations ( int n, int m )  {
-//  0<=n<=nCombMax,  0<=m<=n
-realtype P[nCombMax+1];
-int      i,j;
-  if ((m<0)  || (m>n))    return 0.0;
-  if ((m==0) || (m==n))   return 1.0;
-  if ((m==1) || (m==n-1)) return realtype(n);
-  P[0] = 1.0;
-  P[1] = 3.0;
-  P[2] = 3.0;
-  P[3] = 1.0;
-  for (i=4;i<=n;i++)  {
-    P[i] = 1.0;
-    for (j=i-1;j>0;j--)
-      P[j] += P[j-1];
-  }
-  return P[m];
-}
-
-realtype log1mx ( realtype x )  {
-//  Calculates precisely log(1-x) for x<1, including
-//  very small x
-realtype z,z1,z2,n;
-
-  if (x>=1.0-10.0*MachEps)  z = -MaxReal;
-  else if (fabs(x)>1.0e-8)  z = log(1.0-x);
-  else  {
-    z1 = x; 
-    z  = 0.0;
-    n  = 1.0;
-    do  {
-      z2  = z;
-      z  -= z1/n;
-      z1 *= x;
-      n  += 1.0;
-    } while (z!=z2);
-  }
-
-  return z;
-
-}
-
-realtype expc ( realtype x )  {
-//  Calculates precisely 1 - exp(x) for any x including
-//  very small values
-realtype z,z1,z2,n;
-
-  if (x>LnMaxReal)         z = -MaxReal;
-  else if (x<-LnMaxReal)   z = 1.0;
-  else if (fabs(x)>1.0e-8) z = 1.0 - Exp(x);
-  else  {
-    z1 = x;
-    z  = x;
-    n  = 1.0;
-    do  {
-      z2  = z;
-      n  += 1.0;
-      z1 *= x/n;
-      z  += z1;
-    } while (z!=z2);
-    z = -z;
-  }
-
-  return z;
-
-}
-
-
-realtype expc1mx ( realtype x, realtype y )  {
-//  Calculates precisely 1-(1-x)**y including very small x and
-//  very large y
-realtype z,z1,z2,n,s;
-
-  //  Calculate (1-x)**y as exp(y*log(1-x)).  Get log(1-x) first:
-  if (x>1.0e-8)  z = log(1.0-x);
-  else  {
-    z1 = x; 
-    z  = 0.0;
-    n  = 1.0;
-    do  {
-      z2  = z;
-      z  -= z1/n;
-      z1 *= x;
-      n  += 1.0;
-    } while (z!=z2);
-  }
-
-  //  Now calculate 1 - exp(y*log(1-x)) :
-  z *= y;
-  if (fabs(z)>1.0e-8)  s = 1.0 - exp(z);
-  else  {
-    z1 = z;
-    s  = z;
-    n  = 1.0;
-    do  {
-      z2  = s;
-      n  += 1.0;
-      z1 *= z/n;
-      s  += z1;
-    } while (s!=z2);
-    s = -s;
-  }
-
-  return s;
-
-}
diff --git a/mmdb/math_.h b/mmdb/math_.h
deleted file mode 100755
index 9c68241..0000000
--- a/mmdb/math_.h
+++ /dev/null
@@ -1,73 +0,0 @@
-//  $Id: math_.h,v 1.20 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    09.04.03   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  Math_ <interface>
-//       ~~~~~~~~~
-//  **** Functions :   GetTorsion
-//       ~~~~~~~~~~~   GetAngle
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-
-#ifndef  __Math__
-#define  __Math__
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-
-// ------------------------------------------------------------------
-
-#define  NO_TORSION  (-MaxReal)
-//  U[0,1,2] = x,y,z
-extern realtype GetTorsion   ( rvector U, rvector W, rvector V );
-extern realtype GetAngle     ( rvector U, rvector V );
-
-//  Calculates the binomial coefficient n choose m, 0<=n<=500, 0<=m<=n
-extern realtype Combinations ( int n, int m );
-
-//  Calculates precisely log(1-x) for x<1, including very small x
-extern realtype log1mx  ( realtype x );
-
-//  Calculates precisely 1 - exp(x) for any x including very small values
-extern realtype expc    ( realtype x );
-
-inline double exp10  ( double x ) { return exp(x*ln10);   }
-
-//  Calculates precisely 1-(1-x)**y including very small x and very large y
-extern realtype expc1mx ( realtype x, realtype y );
-
-
-
-#endif
-
-
diff --git a/mmdb/mattype_.cpp b/mmdb/mattype_.cpp
deleted file mode 100755
index c3fb873..0000000
--- a/mmdb/mattype_.cpp
+++ /dev/null
@@ -1,2116 +0,0 @@
-//  $Id: mattype_.cpp,v 1.30 2012/01/26 17:52:19 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MatType_ <implementation>
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-
-#ifndef __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef __STRING_H
-#include <string.h>
-#endif
-
-#ifndef __CTYPE_H
-#include <ctype.h>
-#endif
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-#include <limits>
-#include <stdio.h>
-
-// -------------------------------------------------------
-
-realtype  MachEps;
-realtype  floatMachEps;
-realtype  LnMaxReal;
-realtype  LnMinReal;
-static realtype LnMaxRealExp;
-static realtype LnMinRealExp;
-
-//  Initialization. Some C++ enviroments do not do the
-// following statements automatically, therefore it is
-// always advisable to call InitMatType() explicitely
-// from the top of main(). See body of InitMatType()
-// in the very end of this file. It is completely
-// harmless and cheap to call InitMatType() multiple
-// times.
-
-static Boolean MatTypeInit = InitMatType();
-
-
-// -------------------------------------------------------
-
-/*
-int  mround ( realtype X )  {
-  return  (int)floor(X+0.5);
-}
-
-int  ifloor ( realtype X )  {
-  return  (int)floor(X);
-}
-
-int  Abs ( int x )  {
-  return ( x >= 0 ? x : -x );
-}
-*/
-
-#ifdef _WIN32
-pstr strcasestr ( pstr s1, cpstr s2 )  {
-pstr l1,l2,l;
-  l1 = NULL;
-  l2 = NULL;
-  CreateCopy ( l1,s1 );
-  CreateCopy ( l2,s2 );
-  LowerCase  ( l1 );
-  LowerCase  ( l2 );
-  l = strstr ( l1,l2 );
-  if (l)
-    l = s1 + (l-l1);
-  delete[] l1;
-  delete[] l2;
-  return l;
-}
-#endif
-
-// -------------------------------------------------------
-
-/*
-void  ISwap ( int & x, int & y )  {
-int  b;
- b = x;  x = y;  y = b;
-}
-void  WSwap ( word & x, word & y )  {
-word  b;
-  b = x;  x = y;  y = b;
-}
-void  BSwap ( byte & x, byte & y )  {
-byte  b;
-  b = x;  x = y;  y = b;
-}
-void  LSwap ( long & x, long & y )  {
-long  b;
-  b = x;  x = y;  y = b;
-}
-void  RSwap ( realtype & x, realtype & y )  {
-realtype  b;
-  b = x;  x = y;  y = b;
-}
-*/
-
-// -------------------------------------------------------
-/*
-realtype  RMax ( const realtype x1, const realtype x2 )
-{  return ( x1 > x2 ? x1 : x2 );  }
-
-long      LMax ( const long x1, const long x2 )
-{  return ( x1 > x2 ? x1 : x2 );  }
-
-word      WMax ( const word x1, const word x2 )
-{  return ( x1 > x2 ? x1 : x2 );  }
-
-int       IMax ( const int x1,  const int x2  )
-{  return ( x1 > x2 ? x1 : x2 );  }
-
-realtype  RMin ( const realtype x1, const realtype x2 )
-{  return ( x1 < x2 ? x1 : x2 );  }
-
-long      LMin ( const long x1, const long x2 )
-{  return ( x1 < x2 ? x1 : x2 );  }
-
-word      WMin ( const word x1, const word x2 )
-{  return ( x1 < x2 ? x1 : x2 );  }
-
-int       IMin ( const int x1,  const int x2  )
-{  return ( x1 < x2 ? x1 : x2 );  }
-*/
-
-// -------------------------------------------------------
-/*
-realtype  fsign ( const realtype x1,  const realtype x2 )  {
-realtype  ax;
-  if (x1>=0.0)  ax = x1;
-          else  ax = -x1;
-  return ( x2 >= 0.0 ? ax : -ax );
-}
-*/
-
-// -------------------------------------------------------
-Boolean  GetVectorMemory  ( rvector & V, word N, word Shift )  {
-  V = new realtype[N];
-  if (V!=NULL)  V = V - Shift;  // shift for abovementioned enumeration
-  return  (V!=NULL);
-}
-
-Boolean  GetVectorMemory ( ivector & I, word N, word Shift )  {
-  I = new int[N];
-  if (I!=NULL)  I = I - Shift;   // shift for abovementioned enumeration
-  return  (I!=NULL);
-}
-
-Boolean  GetVectorMemory ( wvector & W, word N, word Shift )  {
-  W = new word[N];
-  if (W!=NULL)  W = W - Shift;   // shift for abovementioned enumeration
-  return  (W!=NULL);
-}
-
-Boolean  GetVectorMemory ( bvector & B, word N, word Shift )  {
-  B = new byte[N];
-  if (B!=NULL)  B = B - Shift;   // shift for abovementioned enumeration
-  return  (B!=NULL);
-}
-
-Boolean  GetVectorMemory ( lvector & L, word N, word Shift )  {
-  L = new long[N];
-  if (L!=NULL)  L = L - Shift;   // shift for abovementioned enumeration
-  return  (L!=NULL);
-}
-
-Boolean  GetVectorMemory ( lwvector & L, word N, word Shift )  {
-  L = new lword[N];
-  if (L!=NULL)  L = L - Shift;   // shift for abovementioned enumeration
-  return  (L!=NULL);
-}
-
-Boolean  GetVectorMemory ( psvector & P, word N, word Shift )  {
-  P = new pstr[N];
-  if (P!=NULL)  P = P - Shift;   // shift for abovementioned enumeration
-  return  (P!=NULL);
-}
-
-void FreeVectorMemory  ( rvector & V, word Shift ) {
-  if (V!=NULL)  {
-    V = V + Shift;  //  back shift for the work of heap system
-    delete[] V;
-    V = NULL;
-  }
-}
-
-void FreeVectorMemory ( ivector & I, word Shift )  {
-  if (I!=NULL)  {
-    I = I + Shift;  //  back shift for the work of heap system
-    delete[] I;
-    I = NULL;
-  }
-}
-
-void FreeVectorMemory ( wvector & W, word Shift )  {
-  if (W!=NULL)  {
-    W = W + Shift;  //  back shift for the work of heap system
-    delete[] W;
-    W = NULL;
-  }
-}
-
-void FreeVectorMemory ( bvector & B, word Shift )  {
-  if (B!=NULL)  {
-    B = B + Shift;  //  back shift for the work of heap system
-    delete[] B;
-    B = NULL;
-  }
-}
-
-void FreeVectorMemory ( lvector & L, word Shift )  {
-  if (L!=NULL)  {
-    L = L + Shift;  //  back shift for the work of heap system
-    delete[] L;
-    L = NULL;
-  }
-}
-
-void FreeVectorMemory ( lwvector & L, word Shift )  {
-  if (L!=NULL)  {
-    L = L + Shift;  //  back shift for the work of heap system
-    delete[] L;
-    L = NULL;
-  }
-}
-
-void FreeVectorMemory ( psvector & P, word Shift )  {
-  if (P!=NULL)  {
-    P = P + Shift;  //  back shift for the work of heap system
-    delete[] P;
-    P = NULL;
-  }
-}
-
-Boolean GetMatrixMemory  ( rmatrix & A, word N, word M,
-                           word ShiftN, word ShiftM ) {
-  A = new rvector[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( A[i],M,ShiftM );
-    if (A[N-1]==NULL)
-          FreeMatrixMemory ( A,N,0,ShiftM );
-    else  A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean  GetMatrixMemory  ( imatrix & A, word N, word M,
-                            word ShiftN, word ShiftM ) {
-  A = new ivector[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( A[i],M,ShiftM );
-    if (A[N-1]==NULL)
-          FreeMatrixMemory ( A,N,0,ShiftM );
-    else  A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean  GetMatrixMemory  ( wmatrix & W, word N, word M,
-                            word ShiftN, word ShiftM ) {
-  W = new wvector[N];
-  if (W!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( W[i],M,ShiftM );
-    if (W[N-1]==NULL)
-          FreeMatrixMemory ( W,N,0,ShiftM );
-    else  W = W - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (W!=NULL);
-}
-
-Boolean  GetMatrixMemory  ( bmatrix & B, word N, word M,
-                            word ShiftN, word ShiftM ) {
-  B = new bvector[N];
-  if (B!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( B[i],M,ShiftM );
-    if (B[N-1]==NULL)
-          FreeMatrixMemory ( B,N,0,ShiftM );
-    else  B = B - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (B!=NULL);
-}
-
-Boolean  GetMatrixMemory  ( lmatrix & L, word N, word M,
-                            word ShiftN, word ShiftM ) {
-  L = new lvector[N];
-  if (L!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( L[i],M,ShiftM );
-    if (L[N-1]==NULL)
-          FreeMatrixMemory ( L,N,0,ShiftM );
-    else  L = L - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (L!=NULL);
-}
-
-Boolean  GetMatrixMemory  ( lwmatrix & L, word N, word M,
-                            word ShiftN, word ShiftM ) {
-  L = new lwvector[N];
-  if (L!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( L[i],M,ShiftM );
-    if (L[N-1]==NULL)
-          FreeMatrixMemory ( L,N,0,ShiftM );
-    else  L = L - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (L!=NULL);
-}
-
-Boolean  GetMatrixMemory  ( psmatrix & P, word N, word M,
-                            word ShiftN, word ShiftM ) {
-  P = new psvector[N];
-  if (P!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetVectorMemory ( P[i],M,ShiftM );
-    if (P[N-1]==NULL)
-          FreeMatrixMemory ( P,N,0,ShiftM );
-    else  P = P - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (P!=NULL);
-}
-
-void FreeMatrixMemory  ( rmatrix & A, word N,
-                         word ShiftN, word ShiftM ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( A[i],ShiftM );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrixMemory  ( imatrix & A,  word N,
-                         word ShiftN, word ShiftM ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( A[i],ShiftM );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrixMemory  ( wmatrix & W,  word N,
-                         word ShiftN, word ShiftM ) {
-  if (W!=NULL)  {
-    W = W + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( W[i],ShiftM );
-    delete[] W;
-    W = NULL;
-  }
-}
-
-void FreeMatrixMemory  ( bmatrix & B,  word N,
-                         word ShiftN, word ShiftM ) {
-  if (B!=NULL)  {
-    B = B + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( B[i],ShiftM );
-    delete[] B;
-    B = NULL;
-  }
-}
-
-void FreeMatrixMemory  ( lmatrix & L,  word N,
-                         word ShiftN, word ShiftM ) {
-  if (L!=NULL)  {
-    L = L + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( L[i],ShiftM );
-    delete[] L;
-    L = NULL;
-  }
-}
-
-void FreeMatrixMemory  ( lwmatrix & L,  word N,
-                         word ShiftN, word ShiftM ) {
-  if (L!=NULL)  {
-    L = L + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( L[i],ShiftM );
-    delete[] L;
-    L = NULL;
-  }
-}
-
-void FreeMatrixMemory  ( psmatrix & P,  word N,
-                         word ShiftN, word ShiftM ) {
-  if (P!=NULL)  {
-    P = P + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeVectorMemory ( P[i],ShiftM );
-    delete[] P;
-    P = NULL;
-  }
-}
-
-Boolean GetMatrix3Memory ( rmatrix3 & A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new rmatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean GetMatrix3Memory ( imatrix3 & A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new imatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean GetMatrix3Memory ( wmatrix3 & A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new wmatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean GetMatrix3Memory ( bmatrix3 &A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new bmatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean GetMatrix3Memory ( lmatrix3 & A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new lmatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean GetMatrix3Memory ( lwmatrix3 & A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new lwmatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-Boolean GetMatrix3Memory ( psmatrix3 & A, word N, word M, word K,
-                           word ShiftN, word ShiftM, word ShiftK ) {
-  A = new psmatrix[N];
-  if (A!=NULL)  {
-    for (word i=0;i<N;i++)
-      GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
-    if (A[N-1]==NULL)
-      FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
-    else
-      A = A - ShiftN;  //  shift for the enumeration with 1
-  }
-  return  (A!=NULL);
-}
-
-void FreeMatrix3Memory  ( rmatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrix3Memory  ( imatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrix3Memory  ( wmatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrix3Memory  ( bmatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrix3Memory  ( lmatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrix3Memory  ( lwmatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-void FreeMatrix3Memory  ( psmatrix3 & A, word N,      word M,
-                          word ShiftN, word ShiftM, word ShiftK ) {
-  if (A!=NULL)  {
-    A = A + ShiftN;  //  back shift for the work of heap system
-    for (word i=0;i<N;i++)
-      FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
-    delete[] A;
-    A = NULL;
-  }
-}
-
-realtype  MachinEps ()  {
-//  A1.3.1   :  Calculation of the machine's epsilon
-/*
-realtype  rMachEps = 1.0;
-  do
-    rMachEps /= 2.0;
-  while ((1.0+rMachEps)!=1.0);
-  return  2.0*rMachEps;
-*/
-  return std::numeric_limits<realtype>::epsilon();
-}
-
-realtype  floatMachinEps()  {
-//  A1.3.1   :  Calculation of the machine's epsilon
-/*
-float fMachEps = 1.0;
-  do
-    fMachEps /= 2.0;
-  while (float(1.0+fMachEps)!=1.0);
-  return  2.0*fMachEps;
-*/
-  return std::numeric_limits<float>::epsilon();
-}
-
-realtype  frac ( realtype R )  {
-realtype  i;
-  return  modf ( R,&i );
-}
-
-long  mod ( long x, long y )  {
-long k=x/y;
-long f=x-k*y;
-  while (f<0)  f += y;
-  return f;
-}
-
-realtype  Pow ( realtype X, int y )  {
-int       m,l;
-realtype  B;
-  if (y==0)  return  1.0;
-  else if (X!=0.0)  {
-    B = X;
-    m = 1;
-    if (y>=0)  l = y;
-         else  l = -y;
-    while (m++<l)  B = B*X;
-    if (y>=0)  return  B;
-         else  return  1.0/B;
-  } else  return  0.0;
-}
-
-realtype  Pow1 ( realtype X, realtype Y )  {
-int  k = mround(Y);
-  if (fabs(k-Y)<=100.0*MachEps)  return Pow(X,k);
-  if (X==0.0)  return 0.0;
-         else  return pow(X,Y);
-}
-
-realtype  Exp ( realtype X )  {
-//realtype  X1 = X;
-//realtype  B  = 1.0;
-  if   (X>=LnMaxRealExp)     return  MaxReal;
-  else if (X<=LnMinRealExp)  return  0.0;
-  else  {
-    return  exp(X);
-    /*
-    while (X1>LnMaxReal)  {
-      X1 -= LnMaxReal;
-      B  *= MaxExponent;
-    }
-    while (X1<-LnMaxReal)  {
-      X1 += LnMaxReal;
-      B  /= MaxExponent;
-    }
-    return B*exp(X1);
-    */
-  }
-}
-
-Boolean Odd ( int i )  {
-  return  (i & 1);
-}
-
-
-//  ----------------------------------------------------
-
-long  HexValL ( cpstr S )  {
-char  C;
-int   i;
-long  z=0;
-  for (i=0;S[i];i++)  {
-    z <<= 4;
-    C = (char)toupper(S[i]);
-    if (isdigit(C))  z += S[i]-'0';
-               else  z += C-'A'+10;
-  }
-  return  z;
-}
-
-
-//  ----------------------------------------------------
-
-long  OctValL ( cpstr S )  {
-int   i;
-long  z=0;
-  for (i=0;S[i];i++)  {
-    z <<= 3;
-    z += S[i]-'0';
-  }
-  return  z;
-}
-
-
-//  ----------------------------------------------------
-
-long  BinValL ( cpstr S )  {
-int   i;
-long  z=0;
-  for (i=0;S[i];i++)  {
-    z <<= 1;
-    z += S[i]-'0';
-  }
-  return  z;
-}
-
-pstr  BinValS ( long L, pstr S )  {
-int   i;
-long  z;
-  z = long(1) << (8*sizeof(long)-1);
-  for (i=0;i<8*(int)sizeof(long);i++)  {
-    if (L & z)  S[i] = '1';
-          else  S[i] = '0';
-    z >>= 1;
-  }
-  S[8*sizeof(long)] = char(0);
-  return  S;
-}
-
-
-
-//  ----------------------------------------------------
-
-pstr ParamStr ( pstr D, cpstr S, realtype V, int M, cpstr S1 )  {
-char  VS[30];
-  strcat  ( D,S );
-  sprintf ( VS,"%-.*g",M,V );
-  strcat  ( D,VS );
-  return strcat(D,S1);
-}
-
-
-pstr ParamStr ( pstr D,  cpstr S, realtype V, int M,
-                cpstr S1, realtype V2, int M2, cpstr S2 )  {
-char  VS[30];
-  ParamStr ( D,S,V,M,S1 );
-  sprintf  ( VS,"%-.*g",M2,V2 );
-  strcat   ( D,VS );
-  return strcat(D,S2);
-}
-
-
-pstr CreateCopy ( pstr & Dest, cpstr Source )  {
-  if (Dest)  delete[] Dest;
-  if (Source)   {
-    Dest = new char[strlen(Source)+1];
-    strcpy ( Dest,Source );
-  } else
-    Dest = NULL;
-  return Dest;
-}
-
-pstr CreateCopy_n ( pstr & Dest, cpstr Source, int n )  {
-int l;
-  if (Dest)  delete[] Dest;
-  if (Source)   {
-    l    = IMin ( strlen(Source),n );
-    Dest = new char[l+1];
-    strncpy ( Dest,Source,l );
-    Dest[l] = char(0);
-  } else
-    Dest = NULL;
-  return Dest;
-}
-
-pstr CreateCopCat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2,
-                    cpstr Source3, cpstr Source4,
-                    cpstr Source5 )  {
-  if (Dest) {
-    delete[] Dest;
-    Dest = NULL;
-  }
-  return CreateConcat ( Dest,Source1,Source2,Source3,Source4,Source5 );
-}
-
-pstr CreateCopCat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2,
-                    cpstr Source3, cpstr Source4 )  {
-  if (Dest) {
-    delete[] Dest;
-    Dest = NULL;
-  }
-  return CreateConcat ( Dest,Source1,Source2,Source3,Source4 );
-}
-
-pstr CreateCopCat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2,
-                    cpstr Source3 )  {
-  if (Dest) {
-    delete[] Dest;
-    Dest = NULL;
-  }
-  return CreateConcat ( Dest,Source1,Source2,Source3 );
-}
-
-pstr CreateCopCat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2 )  {
-  if (Dest) {
-    delete[] Dest;
-    Dest = NULL;
-  }
-  return CreateConcat ( Dest,Source1,Source2 );
-}
-
-
-pstr CreateConcat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2,
-                    cpstr Source3, cpstr Source4,
-                    cpstr Source5 )  {
-pstr S;
-int  ld,ls;
-  if (Dest) ld = strlen(Dest);
-       else ld = 0;
-  ls = 0;
-  if (Source1)  ls += strlen(Source1);
-  if (Source2)  ls += strlen(Source2);
-  if (Source3)  ls += strlen(Source3);
-  if (Source4)  ls += strlen(Source4);
-  if (Source5)  ls += strlen(Source5);
-  if (ls>0)  {
-    S = new char[ls+ld+1];
-    if (Dest)  {
-      strcpy ( S,Dest );
-      delete[] Dest;
-    } else
-      S[0] = char(0);
-    if (Source1) strcat ( S,Source1 );
-    if (Source2) strcat ( S,Source2 );
-    if (Source3) strcat ( S,Source3 );
-    if (Source4) strcat ( S,Source4 );
-    if (Source5) strcat ( S,Source5 );
-    Dest = S;
-  }
-  return Dest;
-}
-
-
-pstr CreateConcat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2,
-                    cpstr Source3, cpstr Source4 )  {
-pstr S;
-int  ld,ls;
-  if (Dest) ld = strlen(Dest);
-       else ld = 0;
-  ls = 0;
-  if (Source1)  ls += strlen(Source1);
-  if (Source2)  ls += strlen(Source2);
-  if (Source3)  ls += strlen(Source3);
-  if (Source4)  ls += strlen(Source4);
-  if (ls>0)  {
-    S = new char[ls+ld+1];
-    if (Dest)  {
-      strcpy ( S,Dest );
-      delete[] Dest;
-    } else
-      S[0] = char(0);
-    if (Source1) strcat ( S,Source1 );
-    if (Source2) strcat ( S,Source2 );
-    if (Source3) strcat ( S,Source3 );
-    if (Source4) strcat ( S,Source4 );
-    Dest = S;
-  }
-  return Dest;
-}
-
-
-pstr CreateConcat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2,
-                    cpstr Source3 )  {
-pstr S;
-int  ld,ls;
-  if (Dest) ld = strlen(Dest);
-       else ld = 0;
-  ls = 0;
-  if (Source1)  ls += strlen(Source1);
-  if (Source2)  ls += strlen(Source2);
-  if (Source3)  ls += strlen(Source3);
-  if (ls>0)  {
-    S = new char[ls+ld+1];
-    if (Dest)  {
-      strcpy ( S,Dest );
-      delete[] Dest;
-    } else
-      S[0] = char(0);
-    if (Source1) strcat ( S,Source1 );
-    if (Source2) strcat ( S,Source2 );
-    if (Source3) strcat ( S,Source3 );
-    Dest = S;
-  }
-  return Dest;
-}
-
-pstr CreateConcat ( pstr & Dest,
-                    cpstr Source1, cpstr Source2 )  {
-pstr S;
-int  ld,ls;
-  if (Dest) ld = strlen(Dest);
-       else ld = 0;
-  ls = 0;
-  if (Source1)  ls += strlen(Source1);
-  if (Source2)  ls += strlen(Source2);
-  if (ls>0)  {
-    S = new char[ls+ld+1];
-    if (Dest)  {
-      strcpy ( S,Dest );
-      delete[] Dest;
-    } else
-      S[0] = char(0);
-    if (Source1) strcat ( S,Source1 );
-    if (Source2) strcat ( S,Source2 );
-    Dest = S;
-  }
-  return Dest;
-}
-
-pstr CreateConcat ( pstr & Dest, cpstr Source )  {
-pstr S;
-int  ld,ls;
-  if (Dest)   ld = strlen(Dest);
-       else   ld = 0;
-  if (Source) ls = strlen(Source);
-         else ls = 0;
-  if (ls>0)  {
-    S = new char[ls+ld+1];
-    if (Dest)  {
-      strcpy ( S,Dest );
-      delete[] Dest;
-    } else
-      S[0] = char(0);
-    strcat ( S,Source );
-    Dest = S;
-  }
-  return Dest;
-}
-
-
-pstr LastOccurence ( cpstr S, char c )  {
-pstr P=(pstr)S;
-pstr R=NULL;
-  while (*P)  {
-    if (*P==c)  R = P;
-    P++;
-  }
-  return R;
-}
-
-
-pstr FirstOccurence ( cpstr S, char c )  {
-pstr P=(pstr)S;
-  while (*P)  {
-    if (*P==c)  return P;
-    P++;
-  }
-  return NULL;
-}
-
-int indexOf ( cpstr S, char c )  {
-int i=0;
-  while (S[i])  {
-    if (S[i]==c)  return i;
-    i++;
-  }
-  return -1;
-}
-
-pstr FirstOccurence ( cpstr S, int Slen, cpstr Q, int Qlen )  {
-int i,j,k,l;
-  l = Slen-Qlen;
-  for (i=0;i<=l;i++)  {
-    j = 0;
-    k = i;
-    while (j<Qlen)
-      if (S[k++]!=Q[j]) break;
-                   else j++;
-    if (j>=Qlen)  return  pstr(&(S[i]));
-  }
-  return NULL;
-}
-
-int indexOf ( cpstr S, int Slen, cpstr Q, int Qlen )  {
-int i,j,k,l;
-  l = Slen-Qlen;
-  for (i=0;i<=l;i++)  {
-    j = 0;
-    k = i;
-    while (j<Qlen)
-      if (S[k++]!=Q[j]) break;
-                   else j++;
-    if (j>=Qlen)  return  i;
-  }
-  return -1;
-}
-
-
-pstr LowerCase ( pstr s )  {
-pstr p=s;
-  while (*p)  {
-    *p = char(tolower(int(*p)));
-    p++;
-  }
-  return s;
-}
-
-pstr UpperCase ( pstr s )  {
-pstr p=s;
-  while (*p)  {
-    *p = char(toupper(int(*p)));
-    p++;
-  }
-  return s;
-}
-
-
-void GetString ( pstr L, cpstr S, int M )  {
-//  Copies first M characters of string S into string L,
-// appending the terminating null. If S contains less
-// then M characters, L will be padded with spaces.
-int i,j;
-  i = 0;
-  j = 0;
-  while (S[i] && (i<M))
-    L[j++] = S[i++];
-  while (j<M)
-    L[j++] = ' ';
-  L[j] = char(0);
-}
-
-
-void GetStrTer ( pstr L, cpstr S, int n, int LMax, int SMax )  {
-//   Copies at least n (or LMax if LMax<n) first symbols of
-// string S into string L, then continues copying until first
-// space or terminating null is found. If the terminating null
-// is met among the first n characters or if SMax<n, the string
-// L will be padded with spaces till the length of minimum of
-// n and LMax and then terminated with the null.
-//   SMax are buffer lengths of L and S, respectively. Even if
-// no space is found, the last character in L will be the
-// terminating null.
-int i,k,lm1,msl,mnsl;
-  lm1  = LMax-1;
-  msl  = IMin(lm1,SMax);
-  mnsl = IMin(n,msl);
-  k    = 0;
-  for (i=0;i<mnsl;i++)
-    if (S[i])  L[k++] = S[i];
-         else  break;
-  if ((k>=SMax) || (!S[k]))  {
-    lm1 = IMin(n,lm1);
-    while (k<lm1)
-      L[k++] = ' ';
-  } else  {
-    lm1 = k;
-    for (i=lm1;i<msl;i++)
-      if (S[i] && (S[i]!=' '))  L[k++] = S[i];
-                          else  break;
-  }
-  L[k] = char(0);
-}
-
-
-void GetStrTerWin32File ( pstr L, cpstr S, int n, int LMax,
-                          int SMax )  {
-//
-// Version of GetStrTer(..) allowing for spaces in the string.
-//
-//   Copies at least n (or LMax if LMax<n) first symbols of
-// string S into string L, then continues copying until first
-// terminating null is found. If the terminating null
-// is met among the first n characters or if SMax<n, the string
-// L will be padded with spaces till the length of minimum of
-// n and LMax and then terminated with the null.
-//   SMax are buffer lengths of L and S, respectively. The last
-// character in L will be the terminating null.
-//
-int i,k,lm1,msl,mnsl;
-  lm1  = LMax-1;
-  msl  = IMin(lm1,SMax);
-  mnsl = IMin(n,msl);
-  k    = 0;
-  for (i=0;i<mnsl;i++)
-    if (S[i])  L[k++] = S[i];
-         else  break;
-  if ((!S[k]) || (k>=SMax))  {
-    lm1 = IMin(n,lm1);
-    while (k<lm1)
-      L[k++] = ' ';
-  } else  {
-    lm1 = k;
-    for (i=lm1;i<msl;i++)
-      if (S[i])  L[k++] = S[i];
-           else  break;
-  }
-  L[k] = char(0);
-}
-
-void  strcpy_n ( pstr d, cpstr s, int n )  {
-//   Copies at most n symbols from string s to d, but
-// no more than strlen(s) (s must contain a terminating
-// null). The terminating null IS NEITHER appended NOR
-// copied to d.
-int i;
-  i = 0;
-  while ((i<n) && (s[i]))  {
-    d[i] = s[i];
-    i++;
-  }
-}
-
-
-void  strcpy_n1 ( pstr d, cpstr s, int n )  {
-//   Copies at most n last symbols from string s to d, but
-// no more than strlen(s) (s must contain a terminating null).
-// The string in d is aligned to the right and added with
-// spaces at the left, if necessary. The terminating null
-// IS NEITHER appended NOR copied to d.
-int i,k;
-  i = n-1;
-  k = strlen(s)-1;
-  while ((i>=0) && (k>=0))
-    d[i--] = s[k--];
-  while (i>=0)
-    d[i--] = ' ';
-}
-
-void  strcpy_nr ( pstr d, cpstr s, int n )  {
-//   Copies at most n symbols from string s to d, but
-// no more than strlen(s) (s must contain a terminating null).
-// The string in d is aligned to the right and added with
-// spaces at the left, if necessary. The terminating null
-// IS NEITHER appended NOR copied to d.
-int i,k;
-  i = n-1;
-  k = IMin(i,strlen(s)-1);
-  while ((i>=0) && (k>=0))
-    d[i--] = s[k--];
-  while (i>=0)
-    d[i--] = ' ';
-}
-
-
-void strcpy_ns ( pstr d, cpstr s, int n )  {
-//   Copies at most n symbols from string s to d, but
-// no more than strlen(s) (s must contain a terminating
-// null). The terminating null IS NEITHER appended NOR
-// copied to d; rather, d is padded with spaces if
-// strlen(s)<n.
-int i;
-  i = 0;
-  while ((i<n) && (s[i]))  {
-    d[i] = s[i];
-    i++;
-  }
-  while (i<n)
-    d[i++] = ' ';
-}
-
-
-pstr strcpy_cs ( pstr d, cpstr s )  {
-//   Copies string s to string d cutting all spaces at
-// at the end. Thus, " abcde   " will be copied like
-// " abcde" (terminating null appended).
-//   The function returns d.
-int i;
-  i = 0;
-  while (s[i])  {
-    d[i] = s[i];
-    i++;
-  }
-  i--;
-  while ((i>0) && (d[i]==' ')) i--;
-  if (d[i]==' ')  d[i]   = char(0);
-            else  d[i+1] = char(0);
-  return d;
-}
-
-
-pstr strcpy_ncs ( pstr d, cpstr s, int n )  {
-//   Copies at most n characters from string s to string d
-// cutting all spaces at at the end. Thus, " abcde   " will
-// be copied like " abc" at n=4 and like " abcde" at n>5
-// (terminating null appended).
-//   The function returns d.
-int i;
-  i = 0;
-  while (s[i] && (i<n))  {
-    d[i] = s[i];
-    i++;
-  }
-  i--;
-  while ((i>0) && (d[i]==' ')) i--;
-  if (d[i]==' ')  d[i]   = char(0);
-            else  d[i+1] = char(0);
-  return d;
-}
-
-pstr strcpy_css ( pstr d, cpstr s )  {
-//   Copies string s to string d cutting all spaces at
-// at the begining and at the end. Thus, " ab c de   "
-// will be copied like "ab c de" (terminating null
-// appended).
-//   The function returns d.
-int i,k;
-  i = 0;
-  while (s[i]==' ')  i++;
-  k = 0;
-  while (s[i])
-    d[k++] = s[i++];
-  if (k>0)  {
-    k--;
-    while ((k>0) && (d[k]==' '))  k--;
-    if (d[k]==' ')  d[k] = char(0);
-              else  d[k+1] = char(0);
-  } else
-    d[k] = char(0);
-  return d;
-}
-
-pstr strcpy_ncss ( pstr d, cpstr s, int n )  {
-//   Copies at most n characters from string s to string d cutting
-// all spaces at the begining and at the end. Thus, " ab c de  "
-// will be copied like "ab" at n=3 (terminating null appended).
-//   The function returns d.
-int i,k;
-  i = 0;
-  while ((s[i]==' ') && (i<n))  i++;
-  k = 0;
-  while (s[i] && (i<n))
-    d[k++] = s[i++];
-  if (k>0)  {
-    k--;
-    while ((k>0) && (d[k]==' '))  k--;
-    if (d[k]==' ')  d[k] = char(0);
-              else  d[k+1] = char(0);
-  } else
-    d[k] = char(0);
-  return d;
-}
-
-
-pstr strcpy_n0 ( pstr d, cpstr s, int n )  {
-//   Copies at most n symbols from string s to d, but
-// no more than strlen(s) (s must contain a terminating
-// null). The terminating null IS appended to d.
-//   The function returns d.
-int i;
-  i = 0;
-  while ((i<n) && (s[i]))  {
-    d[i] = s[i];
-    i++;
-  }
-  d[i] = char(0);
-  return d;
-}
-
-
-int strlen_des ( cpstr s )  {
-//  strlen_des returns the length of a string as if all extra
-//  spaces from the latter have been deleted. Extra spaces
-//  include all leading and tracing spaces and any sequential
-//  spaces when more than one. The string does not change.
-int i,l;
-  l = 0;
-  i = 0;
-  while (s[i]==' ')  i++;
-  while (s[i])  {
-    if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
-      l++;
-    i++;
-  }
-  return l;
-}
-
-pstr strcpy_des ( pstr d, cpstr s )  {
-//  strcpy_des copies string s into string d removing all extra
-//  spaces from the latter. Extra spaces include all leading and
-//  tracing spaces and any sequential spaces when more than one.
-int i,j;
-  j = 0;
-  i = 0;
-  while (s[i]==' ')  i++;
-  while (s[i])  {
-    if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
-      d[j++] = s[i];
-    i++;
-  }
-  d[j] = char(0);
-  return d;
-}
-
-pstr strcat_des ( pstr d, cpstr s )  {
-//  strcpy_des appends string s to string d removing all extra
-//  spaces from the latter. Extra spaces include all leading and
-//  tracing spaces and any sequential spaces when more than one.
-int i,j;
-  j = strlen(d);
-  i = 0;
-  while (s[i]==' ')  i++;
-  while (s[i])  {
-    if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
-      d[j++] = s[i];
-    i++;
-  }
-  d[j] = char(0);
-  return d;
-}
-
-
-void PadSpaces ( pstr S, int len )  {
-//  Pads string S with spaces making its length equal to len.
-//  The terminating zero is added, so that S should reserve
-// space of a minimum len+1 characters.
-int i=strlen(S);
-  while (i<len)  S[i++] = ' ';
-  S[i] = char(0);
-}
-
-
-pstr CutSpaces ( pstr S, int CutKey )  {
-//   Cuts spaces at the begining or end of string S
-// according to the value of CutKey. THe function
-// returns S;
-int i,k;
-  i = 0;
-  k = 0;
-  if (CutKey & SCUTKEY_BEGIN)
-    while (S[i]==' ')  i++;
-  if (k<i)
-    while (S[i])
-      S[k++] = S[i++];
-  else
-    k = strlen(S);
-  if ((CutKey & SCUTKEY_END) && (k>0))  {
-    k--;
-    while ((k>0) && (S[k]==' '))  k--;
-    if (S[k]!=' ')  k++;
-  }
-  S[k] = char(0);
-  return S;
-}
-
-
-pstr DelSpaces ( pstr S, char c )  {
-//   Removes all spaces (or other symbols as specified by 'c')
-// from the string. The string is then shrinked by the number
-// of removed characters. Thus, " as ttt  " becomes "asttt".
-int  i,j;
-  j = 0;
-  for (i=0;S[i];i++)
-    if (S[i]!=c)  {
-      if (j<i)  S[j] = S[i];
-      j++;
-    }
-  S[j] = char(0);
-  return S;
-}
-
-pstr EnforceSpaces ( pstr S )  {
-int i,k;
-  i = 0;
-  while (S[i])  {
-    k = int(S[i]);
-    if ((k<32) && (k!=9) && (k!=10) && (k!=13))  S[i] = ' ';
-    i++;
-  }
-  return S;
-}
-
-
-//  ----------------------------------------------------
-
-#define  _fbase  256
-#define  _rfbase 256.0
-#define  _fsign  0x80
-#define  _fsign1 0x7F
-
-#ifdef  UseDoubleFloat
-# define _nfPowers  255
-# define _nfPower0  127
-# define _nfPower8  135
-//# define _nfPower4  131
-# define _nfPower4  130
-#else
-# define _nfPowers  31
-# define _nfPower0  15
-# define _nfPower8  19
-# define _nfPower4  19
-#endif
-
-static realtype _fpower[_nfPowers+1];
-static realtype _fpower8;
-static realtype _fpower4;
-static Boolean  _old_float_unibin;
-
-Boolean InitFPowers()  {
-int i;
-  _fpower[_nfPower0] = 1.0;
-  for (i=1;i<=_nfPower0;i++)  {
-    _fpower[_nfPower0+i] = _fpower[_nfPower0+i-1]*_rfbase;
-    _fpower[_nfPower0-i] = _fpower[_nfPower0-i+1]/_rfbase;
-  }
-  _fpower[_nfPowers] = fMaxReal;
-  _fpower8 = _fpower[_nfPower8];
-  _fpower4 = _fpower[_nfPower4];
-  _old_float_unibin = False;
-  return True;
-}
-
-void __modify4()  {
-  _fpower4 = _fpower[_nfPower4-1];
-}
-
-void  set_new_float_unibin()  {
-  _old_float_unibin = False;
-}
-
-Boolean is_new_float_unibin()  {
-  return !_old_float_unibin;
-}
-
-void  set_old_float_unibin()  {
-  _old_float_unibin = True;
-}
-
-/*
-void  int2UniBin ( int I, intUniBin iUB )  {
-int j,n,sh;
-  sh = 8*(sizeof(intUniBin)-1);
-  for (j=sizeof(intUniBin)-1;j>=0;j--)  {
-    n = (I >> sh) & 0xFF;
-    iUB[j] = byte(n);
-    sh -= 8;
-  }
-}
-*/
-
-void  int2UniBin ( int I, intUniBin iUB )  {
-int  n;
-word j;
-  n = I;
-  for (j=0;j<sizeof(intUniBin);j++)  {
-    iUB[j] = byte(n & 0xFF);
-    n >>= 8;
-  }
-}
-
-void  short2UniBin ( short S, shortUniBin sUB )  {
-int   j,sh;
-short n;
-  sh = 8*(sizeof(shortUniBin)-1);
-  for (j=sizeof(shortUniBin)-1;j>=0;j--)  {
-    n = (S >> sh) & 0xFF;
-    sUB[j] = byte(n);
-    sh -= 8;
-  }
-}
-
-void  long2UniBin ( long L, longUniBin lUB )  {
-int  j,sh;
-long n;
-  sh = 8*(sizeof(longUniBin)-1);
-  for (j=sizeof(longUniBin)-1;j>=0;j--)  {
-    n = (L >> sh) & 0xFF;
-    lUB[j] = byte(n);
-    sh -= 8;
-  }
-}
-
-void  word2UniBin ( word W, wordUniBin wUB )  {
-int  j,sh;
-word n;
-  sh = 8*(sizeof(wordUniBin)-1);
-  for (j=sizeof(wordUniBin)-1;j>=0;j--)  {
-    n = (W >> sh) & 0xFF;
-    wUB[j] = byte(n);
-    sh -= 8;
-  }
-}
-
-
-void  real2UniBin ( realtype R, realUniBin rUB )  {
-int      k1,k2,k;
-realtype Q,L;
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  Q = (Q/_fpower[k2])*_fpower8;
-  rUB[0] = byte(k2);
-  for (k=sizeof(realUniBin)-1;k>0;k--)  {
-    L      = floor(Q/_rfbase);
-    rUB[k] = byte(int(Q-L*_rfbase));
-    Q      = L;
-  }
-  if (R<0)  rUB[1] |= _fsign;
-
-}
-
-void  shortreal2UniBin ( shortreal R, shortrealUniBin srUB )  {
-int      k1,k2,k;
-realtype Q,L;
-
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  Q = (Q/_fpower[k2])*_fpower4;
-  srUB[0] = byte(k2);
-  for (k=sizeof(shortrealUniBin)-1;k>0;k--)  {
-    L = floor(Q/_rfbase);
-    srUB[k] = byte(int(Q-L*_rfbase));
-    Q = L;
-  }
-  if (R<0)  srUB[1] |= _fsign;
-
-}
-
-/*
-#undef _new_float_unibin
-
-#ifdef _new_float_unibin
-
-void  float2UniBin ( realtype R, floatUniBin fUB )  {
-int      k1,k2,k;
-realtype Q,L;
-
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  Q = (Q/_fpower[k2])*_fpower4;
-  fUB[0] = byte(k2);
-  for (k=sizeof(floatUniBin)-1;k>0;k--)  {
-    L = floor(Q/_rfbase);
-    fUB[k] = byte(int(Q-L*_rfbase));
-    Q = L;
-  }
-  if (R<0)  fUB[1] |= _fsign;
-
-}
-
-#else
-
-void  float2UniBin ( realtype R, floatUniBin fUB )  {
-int      k1,k2,k;
-realtype Q,L;
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  Q = (Q/_fpower[k2])*_fpower8;
-  fUB[0] = byte(k2);
-  for (k=sizeof(realUniBin)-1;k>0;k--)  {
-    L = floor(Q/_rfbase);
-    if (k<=sizeof(floatUniBin))
-      fUB[k] = byte(int(Q-L*_rfbase));
-    Q = L;
-  }
-  if (R<0)  fUB[1] |= _fsign;
-
-}
-
-#endif
-*/
-
-void  float2UniBin ( realtype R, floatUniBin fUB )  {
-int      k1,k2,k;
-realtype Q,L;
-
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  fUB[0] = byte(k2);
-
-  if (_old_float_unibin)  {
-    // this is wrong but compatible with already existing files :(
-    // in the result, it gives errors in 6th digit at back conversion
-    Q = (Q/_fpower[k2])*_fpower8;
-    for (k=sizeof(realUniBin)-1;k>0;k--)  {
-      L = floor(Q/_rfbase);
-      if (k<=(int)sizeof(floatUniBin))
-        fUB[k] = byte(int(Q-L*_rfbase));
-      Q = L;
-    }
-  } else  {
-    // this is correct
-    Q = (Q/_fpower[k2])*_fpower4;
-    for (k=sizeof(floatUniBin)-1;k>0;k--)  {
-      L = floor(Q/_rfbase);
-      fUB[k] = byte(int(Q-L*_rfbase));
-      Q = L;
-    }
-  }
-
-//if (fUB[1] & _fsign)  printf ( " error!\n" );
-
-  if (R<0)  fUB[1] |= _fsign;
-
-}
-
-
-void  UniBin2float ( floatUniBin fUB, realtype & R )  {
-int j,s;
-
-  if (fUB[1] & _fsign)  {
-    s = 1;
-    fUB[1] &= _fsign1;
-  } else
-    s = 0;
-
-  R = int(fUB[1]);
-
-  if (_old_float_unibin)  {
-    // this is wrong and gives a conversion error in 6th digit :(
-    // we have to keep this for compatibility with already existing
-    // files
-    for (j=2;j<(int)sizeof(floatUniBin);j++)
-      R = R*_rfbase + int(fUB[j]);
-    for (j=sizeof(floatUniBin);j<(int)sizeof(realUniBin);j++)
-      R *= _rfbase;
-    R = (R/_fpower8)*_fpower[int(fUB[0])];
-  } else  {
-    // this is correct
-    for (j=2;j<(int)sizeof(floatUniBin);j++)
-      R = R*_rfbase + int(fUB[j]);
-    R = (R/_fpower4)*_fpower[int(fUB[0])];
-  }
-  if (s)  R = -R;
-}
-
-
-/* -------------------------------------------------------
-   This piece of code shows that float2Unibin - Unbin2float
-   pair does same-quality job as the native float - double
-   conversion:
-
-  InitMatType();
-  set_new_float_unibin();
-
-  floatUniBin      fUB;
-  realUniBin      rUB;
-  realtype         maxsh  = MaxShortReal/2.0; // max manageable /2!
-  float            maxshf = maxsh;
-  realtype         maxshr = maxshf;
-  realtype         maxsh1;
-
-  float2UniBin ( maxsh,fUB );
-  UniBin2float ( fUB,maxsh1 );
-
-  printf ( " float\n %10.3f\n %10.3f\n %10.3f\n %10.3f\n",
-           maxsh,maxsh1,maxshf,maxshr );
-
-  maxsh = MaxShortReal;
-  real2UniBin ( maxsh,rUB );
-  UniBin2real ( rUB,maxsh1 );
-
-  printf ( " real\n %10.3f\n %10.3f\n",maxsh,maxsh1 );
-
----- RESULTS:
-
- float
- 170099999999999990938343446679146987520.000
- 170099999948540854500627141228603899904.000
- 170100000027769017014891478822147850240.000
- 170100000027769017014891478822147850240.000
- real
- 340199999999999981876686893358293975040.000
- 340199999999999981876686893358293975040.000
-
--------------------------------------------------------------- */
-
-/*
-void  shortreal2UniBin ( shortreal R, shortrealUniBin srUB )  {
-int      k1,k2,k;
-realtype Q,L;
-
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  Q = (Q/_fpower[k2])*_fpower8;
-  srUB[0] = byte(k2);
-  for (k=sizeof(realUniBin)-1;k>0;k--)  {
-    L = floor(Q/_rfbase);
-    if (k<=(int)sizeof(shortrealUniBin))
-      srUB[k] = byte(int(Q-L*_rfbase));
-    Q = L;
-  }
-  if (R<0)  srUB[1] |= _fsign;
-
-}
-
-void  float2UniBin ( realtype R, floatUniBin fUB )  {
-int      k1,k2,k;
-realtype Q,L;
-
-  if (R>=0)  Q = R;
-       else  Q = -R;
-  k1 = 0;
-  k2 = _nfPowers;
-  do {
-    k = (k1+k2)/2;
-    if (Q>=_fpower[k])  k1 = k;
-                  else  k2 = k;
-  } while (k2>k1+1);
-  if (Q<=_fpower[0])  k2 = 0;
-  Q = (Q/_fpower[k2])*_fpower8;
-  fUB[0] = byte(k2);
-  for (k=sizeof(realUniBin)-1;k>0;k--)  {
-    L = floor(Q/_rfbase);
-    if (k<=(int)sizeof(floatUniBin))
-      fUB[k] = byte(int(Q-L*_rfbase));
-    Q = L;
-  }
-  if (R<0)  fUB[1] |= _fsign;
-
-}
-*/
-
-/*
-void  UniBin2int ( intUniBin iUB, int & I )  {
-int j,n,sh;
-  sh = 8*sizeof(intUniBin);
-  I  = 0x00;
-  for (j=sizeof(intUniBin)-1;j>=0;j--)  {
-    sh -= 8;
-    n   = byte(iUB[j]);
-    I   = I | (n << sh);
-  }
-}
-*/
-
-void  UniBin2int ( intUniBin iUB, int & I )  {
-int j;
-  I = 0x00;
-  for (j=sizeof(intUniBin)-1;j>=0;j--)  {
-    I <<= 8;
-    I |= int(iUB[j]);
-  }
-}
-
-void  UniBin2short ( shortUniBin sUB, short & S )  {
-int   j,sh;
-short n;
-  sh = 8*sizeof(shortUniBin);
-  S  = 0x00;
-  for (j=sizeof(shortUniBin)-1;j>=0;j--)  {
-    sh -= 8;
-    n   = byte(sUB[j]);
-    S   = S | (n << sh);
-  }
-}
-
-void  UniBin2long ( longUniBin lUB, long & L )  {
-int  j,sh;
-long n;
-  sh = 8*sizeof(longUniBin);
-  L  = 0x00;
-  for (j=sizeof(longUniBin)-1;j>=0;j--)  {
-    sh -= 8;
-    n   = byte(lUB[j]);
-    L   = L | (n << sh);
-  }
-}
-
-void  UniBin2word ( wordUniBin wUB, word & W )  {
-int  j,sh;
-word n;
-  sh = 8*sizeof(wordUniBin);
-  W  = 0x00;
-  for (j=sizeof(wordUniBin)-1;j>=0;j--)  {
-    sh -= 8;
-    n   = byte(wUB[j]);
-    W   = W | (n << sh);
-  }
-}
-
-void  UniBin2real ( realUniBin rUB, realtype & R )  {
-int j,s;
-  if (rUB[1] & _fsign)  {
-    s = 1;
-    rUB[1] &= _fsign1;
-  } else
-    s = 0;
-  R = int(rUB[1]);
-  for (j=2;j<(int)sizeof(realUniBin);j++)
-    R = R*_rfbase + int(rUB[j]);
-  R = (R/_fpower8)*_fpower[int(rUB[0])];
-  if (s)  R = -R;
-}
-
-void  UniBin2shortreal ( shortrealUniBin srUB, shortreal & R )  {
-int j,s;
-  if (srUB[1] & _fsign)  {
-    s = 1;
-    srUB[1] &= _fsign1;
-  } else
-    s = 0;
-  R = int(srUB[1]);
-  for (j=2;j<(int)sizeof(shortrealUniBin);j++)
-    R = R*_rfbase + int(srUB[j]);
-  R = (R/_fpower4)*_fpower[int(srUB[0])];
-  if (s)  R = -R;
-}
-
-/*
-#ifdef _new_float_unibin
-
-void  UniBin2float ( floatUniBin fUB, realtype & R )  {
-int j,s;
-  if (fUB[1] & _fsign)  {
-    s = 1;
-    fUB[1] &= _fsign1;
-  } else
-    s = 0;
-  R = int(fUB[1]);
-  for (j=2;j<(int)sizeof(floatUniBin);j++)
-    R = R*_rfbase + int(fUB[j]);
-  R = (R/_fpower4)*_fpower[int(fUB[0])];
-  if (s)  R = -R;
-}
-
-#else
-
-void  UniBin2float ( floatUniBin fUB, realtype & R )  {
-int j,s;
-  if (fUB[1] & _fsign)  {
-    s = 1;
-    fUB[1] &= _fsign1;
-  } else
-    s = 0;
-  R = int(fUB[1]);
-  for (j=2;j<sizeof(floatUniBin);j++)
-    R = R*_rfbase + int(fUB[j]);
-  for (j=sizeof(floatUniBin);j<sizeof(realUniBin);j++)
-    R *= _rfbase;
-  R = (R/_fpower8)*_fpower[int(fUB[0])];
-  if (s)  R = -R;
-}
-
-#endif
-*/
-
-
-
-
-
-/*
-void  UniBin2shortreal ( shortrealUniBin srUB, shortreal & R )  {
-int j,s;
-  if (srUB[1] & _fsign)  {
-    s = 1;
-    srUB[1] &= _fsign1;
-  } else
-    s = 0;
-  R = int(srUB[1]);
-  for (j=2;j<(int)sizeof(shortrealUniBin);j++)
-    R = R*_rfbase + int(srUB[j]);
-  for (j=sizeof(shortrealUniBin);j<(int)sizeof(realUniBin);j++)
-    R *= _rfbase;
-  R = (R/_fpower8)*_fpower[int(srUB[0])];
-  if (s)  R = -R;
-}
-
-void  UniBin2float ( floatUniBin fUB, realtype & R )  {
-int j,s;
-  if (fUB[1] & _fsign)  {
-    s = 1;
-    fUB[1] &= _fsign1;
-  } else
-    s = 0;
-  R = int(fUB[1]);
-  for (j=2;j<(int)sizeof(floatUniBin);j++)
-    R = R*_rfbase + int(fUB[j]);
-  for (j=sizeof(floatUniBin);j<(int)sizeof(realUniBin);j++)
-    R *= _rfbase;
-  R = (R/_fpower8)*_fpower[int(fUB[0])];
-  if (s)  R = -R;
-}
-*/
-
-
-void mem_write ( int I, pstr S, int & l )  {
-intUniBin iUB;
-  int2UniBin ( I,iUB );
-  memcpy ( &(S[l]),iUB,sizeof(intUniBin) );
-  l += sizeof(intUniBin);
-  S[l] = char(0);
-}
-
-void mem_write ( short I, pstr S, int & l )  {
-shortUniBin sUB;
-  short2UniBin ( I,sUB );
-  memcpy ( &(S[l]),sUB,sizeof(shortUniBin) );
-  l += sizeof(shortUniBin);
-  S[l] = char(0);
-}
-
-void mem_write ( long I, pstr S, int & l )  {
-longUniBin lUB;
-  long2UniBin ( I,lUB );
-  memcpy ( &(S[l]),lUB,sizeof(longUniBin) );
-  l += sizeof(longUniBin);
-  S[l] = char(0);
-}
-
-void mem_write ( word W, pstr S, int & l )  {
-wordUniBin wUB;
-  word2UniBin ( W,wUB );
-  memcpy ( &(S[l]),wUB,sizeof(wordUniBin) );
-  l += sizeof(wordUniBin);
-  S[l] = char(0);
-}
-
-void mem_write ( realtype R, pstr S, int & l )  {
-realUniBin rUB;
-  real2UniBin ( R,rUB );
-  memcpy ( &(S[l]),rUB,sizeof(realUniBin) );
-  l += sizeof(realUniBin);
-  S[l] = char(0);
-}
-
-void mem_write ( shortreal R, pstr S, int & l )  {
-shortrealUniBin srUB;
-  shortreal2UniBin ( R,srUB );
-  memcpy ( &(S[l]),srUB,sizeof(shortrealUniBin) );
-  l += sizeof(shortrealUniBin);
-  S[l] = char(0);
-}
-
-void mem_write ( pstr L, int len, pstr S, int & l )  {
-  memcpy ( &(S[l]),L,len );
-  l += len;
-  S[l] = char(0);
-}
-
-void mem_write ( pstr L, pstr S, int & l )  {
-int len;
-  if (L)  len = strlen(L);
-    else  len = 0;
-  mem_write ( len,S,l );
-  if (len>0)  {
-    memcpy ( &(S[l]),L,len );
-    l += len;
-    S[l] = char(0);
-  }
-}
-
-void mem_write ( Boolean B, pstr S, int & l )  {
-  if (B)  S[l++] = 'Y';
-    else  S[l++] = 'N';
-  S[l] = char(0);
-}
-
-void mem_write_byte ( byte B, pstr S, int & l )  {
-  S[l++] = char(B);
-  S[l]   = char(0);
-}
-
-
-void mem_read ( int & I, cpstr S, int & l )  {
-intUniBin iUB;
-  memcpy ( iUB,&(S[l]),sizeof(intUniBin) );
-  l += sizeof(intUniBin);
-  UniBin2int ( iUB,I );
-}
-
-void mem_read ( short & I, cpstr S, int & l )  {
-shortUniBin sUB;
-  memcpy ( sUB,&(S[l]),sizeof(shortUniBin) );
-  l += sizeof(shortUniBin);
-  UniBin2short ( sUB,I );
-}
-
-void mem_read ( long & I, cpstr S, int & l )  {
-longUniBin lUB;
-  memcpy ( lUB,&(S[l]),sizeof(longUniBin) );
-  l += sizeof(longUniBin);
-  UniBin2long ( lUB,I );
-}
-
-void mem_read ( word & W, cpstr S, int & l )  {
-wordUniBin wUB;
-  memcpy ( wUB,&(S[l]),sizeof(wordUniBin) );
-  l += sizeof(wordUniBin);
-  UniBin2word ( wUB,W );
-}
-
-void mem_read ( realtype & R, cpstr S, int & l )  {
-realUniBin rUB;
-  memcpy ( rUB,&(S[l]),sizeof(realUniBin) );
-  l += sizeof(realUniBin);
-  UniBin2real ( rUB,R );
-}
-
-void mem_read ( shortreal & R, cpstr S, int & l )  {
-shortrealUniBin srUB;
-  memcpy ( srUB,&(S[l]),sizeof(shortrealUniBin) );
-  l += sizeof(shortrealUniBin);
-  UniBin2shortreal ( srUB,R );
-}
-
-void mem_read ( pstr L, int len, cpstr S, int & l )  {
-  memcpy ( L,&(S[l]),len );
-  l += len;
-}
-
-void mem_read ( pstr & L, cpstr S, int & l )  {
-int len;
-  if (L)  {
-    delete[] L;
-    L = NULL;
-  }
-  mem_read ( len,S,l );
-  if (len>0)  {
-    L = new char[len+1];
-    memcpy ( L,&(S[l]),len );
-    L[len] = char(0);
-    l += len;
-  }
-}
-
-void mem_read ( Boolean & B, cpstr S, int & l )  {
-  B = (S[l++]=='Y');
-}
-
-void mem_read_byte ( byte & B, cpstr S, int & l )  {
-  B = byte(S[l++]);
-}
-
-// -------------------------------------------------------
-
-Boolean InitMatType()  {
-  MachEps      = MachinEps();
-  floatMachEps = floatMachinEps();
-  LnMaxReal    = log(fMaxReal);
-  LnMinReal    = log(fMinReal);
-  LnMaxRealExp = LnMaxReal;
-  LnMinRealExp = LnMinReal;
-  InitFPowers();
-  return True;
-}
-
-/* ===================================================  */
-
-// ***  end of  <MatType>
diff --git a/mmdb/mattype_.h b/mmdb/mattype_.h
deleted file mode 100755
index 43ecd4f..0000000
--- a/mmdb/mattype_.h
+++ /dev/null
@@ -1,659 +0,0 @@
-//  $Id: mattype_.h,v 1.30 2012/02/23 23:12:22 gxg60988 Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MatType_ <interface>
-//       ~~~~~~~~~
-//  **** Functions :
-//       ~~~~~~~~~~~
-//               GetString  ( reads substring from a string         )
-//               GetStrTer  ( reads substring and put term-ing null )
-//               strcpy_n   ( copies not more than n characters     )
-//               strcpy_ns  ( like strcpy_ns and pads with spaces   )
-//               strcpy_n0  ( like strcpy_n and adds terminating 0  )
-//               PadSpaces  ( pads a string with spaces             )
-//
-//  (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-
-#ifndef  __MatType__
-#define  __MatType__
-
-#ifndef __MATH_H
-#include <math.h>
-#endif
-
-#define  UseDoubleFloat
-
-#ifndef __ClassMacros
-
-# define __ClassMacros
-
- //  A Class definition macros
-# define DefineClass(ClassName)             \
-   class ClassName;                         \
-   typedef ClassName    * P##ClassName;     \
-   typedef ClassName    & R##ClassName;     \
-   typedef P##ClassName * PP##ClassName;    \
-   typedef P##ClassName & RP##ClassName;
-
- //  A Structure definition macros
-# define DefineStructure(StructureName)             \
-   struct StructureName;                            \
-   typedef StructureName    * P##StructureName;     \
-   typedef StructureName    & R##StructureName;     \
-   typedef P##StructureName * PP##StructureName;    \
-   typedef P##StructureName & RP##StructureName;
-
-#endif
-
-#define UNUSED_ARGUMENT(x) (void)x
-
-// -----------------------------------------------------
-
-#ifdef  UseDoubleFloat
-
-# define   MinReal      2.2250e-307
-# define   MaxReal      1.7976e+308
-# define   fMinReal     2.2250e-307
-# define   fMaxReal     1.7976e+308
-  typedef  double       realtype;
-
-#else
-
-# define   MinReal     1.1755e-38
-# define   MaxReal     3.4020e+38
-# define   fMinReal    1.1755e-38
-# define   fMaxReal    3.4020e+38
-  typedef  float       realtype;
-
-#endif
-
-typedef   float     shortreal;
-#define   MinShortReal  1.1755e-38
-#define   MaxShortReal  3.4020e+38
-
-#define   strrchr   LastOccurence
-#define   fstrrchr  LastOccurence
-#define   strchr    FirstOccurence
-#define   fstrchr   FirstOccurence
-
-typedef   char     *         pstr;
-typedef   const char *       cpstr;
-typedef   unsigned int       word;
-typedef   unsigned char      byte;
-typedef   signed   char      short_int;
-typedef   byte               Boolean;
-typedef   unsigned int       word2;
-typedef   byte *             byteptr;
-typedef   unsigned long      lword;
-
-typedef   byte intUniBin      [4];
-typedef   byte shortUniBin    [2];
-typedef   byte longUniBin     [4];
-typedef   byte wordUniBin     [4];
-typedef   byte realUniBin     [10];
-typedef   byte floatUniBin    [5];
-typedef   byte shortrealUniBin[5];
-
-#ifdef _WIN32
-pstr strcasestr ( pstr s1, cpstr s2 );
-#endif
-
-#ifdef _MSC_VER
-#define   strncasecmp _strnicmp
-#define   strcasecmp  _stricmp
-#endif
-
-#define   True              Boolean(1)
-#define   False             Boolean(0)
-
-#define   MaxInt            32767
-#define   MinInt            (-32768)
-#define   MaxWord           65535L
-#define   MaxInt4           2147483647
-
-//    MinInt4 would have to be defined as  -2147483648,
-// however some compilers do not like that. To be on safe,
-// we define it as -2147483647:
-#define   MinInt4           (-2147483647)
-#define   MaxWord4          4294967295
-
-#define   Pi                3.141592653589793238462643
-#define   Eu                2.718281828459045235360287
-#define   ln10              2.3025850929940456840179915
-
-
-// ***  vectors   X[1..N] :
-typedef   realtype * rvector;
-typedef   int      * ivector;
-typedef   word     * wvector;
-typedef   byte     * bvector;
-typedef   long     * lvector;
-typedef   lword    * lwvector;
-typedef   pstr     * psvector;
-
-// ***  matrices   X[1..N][1..M] :
-typedef   rvector  * rmatrix;
-typedef   ivector  * imatrix;
-typedef   wvector  * wmatrix;
-typedef   bvector  * bmatrix;
-typedef   lvector  * lmatrix;
-typedef   lwvector * lwmatrix;
-typedef   psvector * psmatrix;
-
-// ***  matrices   X[1..N][1..M][1..K] :
-typedef   rmatrix  * rmatrix3;
-typedef   imatrix  * imatrix3;
-typedef   wmatrix  * wmatrix3;
-typedef   bmatrix  * bmatrix3;
-typedef   lmatrix  * lmatrix3;
-typedef   lwmatrix * lwmatrix3;
-typedef   psmatrix * psmatrix3;
-
-
-
-// ------------------------------------------------------------
-
-//  Initialization. Some C++ enviroments do not do call
-// InitMatType() automatically, therefore it is always
-// advisable to call InitMatType() explicitely from the top of
-// main(). It is completely harmless and cheap (although
-// unnecessary) to call InitMatType() multiple times.
-extern Boolean InitMatType();
-
-// ------------------------------------------------------------
-
-/*
-extern  int       mround ( realtype X );
-extern  int       ifloor ( realtype X );
-extern  int       Abs    ( int x      );
-
-extern  void      ISwap  ( int      & x, int      & y );
-extern  void      WSwap  ( word     & x, word     & y );
-extern  void      BSwap  ( byte     & x, byte     & y );
-extern  void      LSwap  ( long     & x, long     & y );
-extern  void      RSwap  ( realtype & x, realtype & y );
-
-extern  realtype  RMax   ( const realtype x1, const realtype x2 );
-extern  long      LMax   ( const long     x1, const long     x2 );
-extern  word      WMax   ( const word     x1, const word     x2 );
-extern  int       IMax   ( const int      x1, const int      x2 );
-extern  realtype  RMin   ( const realtype x1, const realtype x2 );
-extern  long      LMin   ( const long     x1, const long     x2 );
-extern  word      WMin   ( const word     x1, const word     x2 );
-extern  int       IMin   ( const int      x1, const int      x2 );
-extern  realtype  fsign  ( const realtype x1, const realtype x2 );
-*/
-
-inline int mround ( realtype X )  { return  (int)floor(X+0.5);   }
-inline int ifloor ( realtype X )  { return  (int)floor(X);       }
-inline int Abs    ( int x )       { return ( x >= 0 ? x : -x );  }
-
-inline void ISwap ( int & x, int & y )
-{ int  b = x;  x = y;  y = b; }
-
-inline void WSwap ( word & x, word & y )
-{ word  b = x;  x = y;  y = b; }
-
-inline void BSwap ( byte & x, byte & y )
-{ byte b = x;  x = y;  y = b; }
-
-inline void LSwap ( long & x, long & y )
-{ long b = x;  x = y;  y = b; }
-
-inline void RSwap ( realtype & x, realtype & y )
-{ realtype b = x;  x = y;  y = b; }
-
-inline realtype RMax ( const realtype x1, const realtype x2 )
-{ return ( x1 > x2 ? x1 : x2 );  }
-
-inline long LMax ( const long x1, const long x2 )
-{ return ( x1 > x2 ? x1 : x2 );  }
-
-inline word WMax ( const word x1, const word x2 )
-{ return ( x1 > x2 ? x1 : x2 );  }
-
-inline int IMax ( const int x1,  const int x2  )
-{ return ( x1 > x2 ? x1 : x2 );  }
-
-inline realtype RMin ( const realtype x1, const realtype x2 )
-{ return ( x1 < x2 ? x1 : x2 );  }
-
-inline long LMin ( const long x1, const long x2 )
-{ return ( x1 < x2 ? x1 : x2 );  }
-
-inline word WMin ( const word x1, const word x2 )
-{ return ( x1 < x2 ? x1 : x2 );  }
-
-inline int  IMin ( const int x1,  const int x2  )
-{ return ( x1 < x2 ? x1 : x2 );  }
-
-inline realtype fsign ( const realtype x1,  const realtype x2 )  {
-realtype  ax;
-  if (x1>=0.0)  ax = x1;
-          else  ax = -x1;
-  return ( x2 >= 0.0 ? ax : -ax );
-}
-
-
-// ------------------------------------------------------------
-
-//    Allocated vectors are enumerated as [Shift..Shift+N-1]
-//  rather than [0..N-1] !
-//    Get-functions return  <true>  if memory was allocated;
-//  if allocation attemt fails,  vector is assigned with  NULL
-
-extern Boolean GetVectorMemory ( rvector  & V, word N, word Shift=1 );
-extern Boolean GetVectorMemory ( ivector  & I, word N, word Shift=1 );
-extern Boolean GetVectorMemory ( wvector  & W, word N, word Shift=1 );
-extern Boolean GetVectorMemory ( bvector  & B, word N, word Shift=1 );
-extern Boolean GetVectorMemory ( lvector  & L, word N, word Shift=1 );
-extern Boolean GetVectorMemory ( lwvector & L, word N, word Shift=1 );
-extern Boolean GetVectorMemory ( psvector & P, word N, word Shift=1 );
-
-//    Shift at deallocation MUST be the same as that at allocation !
-//   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//    Free-functions do nothing if vector has value  NULL (e.g.
-//  after unsuccessful allocation).
-
-extern void FreeVectorMemory ( rvector  & V, word Shift=1 );
-extern void FreeVectorMemory ( ivector  & I, word Shift=1 );
-extern void FreeVectorMemory ( wvector  & W, word Shift=1 );
-extern void FreeVectorMemory ( bvector  & B, word Shift=1 );
-extern void FreeVectorMemory ( lvector  & L, word Shift=1 );
-extern void FreeVectorMemory ( lwvector & L, word Shift=1 );
-extern void FreeVectorMemory ( psvector & P, word Shift=1 );
-
-// -------------------------------------------------------------
-
-//    Allocated matrices are enumerated as
-//          [ShiftN..ShiftN+N-1, ShiftM..ShiftM+M-1]
-//  rather than [0..N-1,0..M-1] !
-//    Get-functions return  <true>  if memory was allocated;
-//  if allocation attemt fails,  matrix is assigned with  NULL
-//    Free-functions do nothing if matrix has value  NULL (e.g.
-//  after unsuccessful allocation).
-
-extern Boolean GetMatrixMemory
-       ( rmatrix  & A, word N, word M, word ShiftN=1, word ShiftM=1 );
-extern Boolean GetMatrixMemory
-       ( imatrix  & A, word N, word M, word ShiftN=1, word ShiftM=1 );
-extern Boolean GetMatrixMemory
-       ( wmatrix  & W, word N, word M, word ShiftN=1, word ShiftM=1 );
-extern Boolean GetMatrixMemory
-       ( bmatrix  & B, word N, word M, word ShiftN=1, word ShiftM=1 );
-extern Boolean GetMatrixMemory
-       ( lmatrix  & L, word N, word M, word ShiftN=1, word ShiftM=1 );
-extern Boolean GetMatrixMemory
-       ( lwmatrix & L, word N, word M, word ShiftN=1, word ShiftM=1 );
-extern Boolean GetMatrixMemory
-       ( psmatrix & P, word N, word M, word ShiftN=1, word ShiftM=1 );
-
-//    ShiftN and ShiftM at deallocation MUST be the same as those at
-//   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//                          allocation !
-//                         ~~~~~~~~~~~~~
-
-extern  void FreeMatrixMemory  ( rmatrix  & A,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-extern  void FreeMatrixMemory  ( imatrix  & A,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-extern  void FreeMatrixMemory  ( wmatrix  & W,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-extern  void FreeMatrixMemory  ( bmatrix  & B,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-extern  void FreeMatrixMemory  ( lmatrix  & L,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-extern  void FreeMatrixMemory  ( lwmatrix & L,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-extern  void FreeMatrixMemory  ( psmatrix & P,  word N,
-                 word ShiftN=1, word ShiftM=1 );
-
-
-// -------------------------------------------------------------
-//   3D matrices
-
-extern Boolean GetMatrix3Memory
-           ( rmatrix3  & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern Boolean GetMatrix3Memory
-           ( imatrix3  & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern Boolean GetMatrix3Memory
-           ( wmatrix3  & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern Boolean GetMatrix3Memory
-           ( bmatrix3  & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern Boolean GetMatrix3Memory
-           ( lmatrix3  & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern Boolean GetMatrix3Memory
-           ( lwmatrix3 & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern Boolean GetMatrix3Memory
-           ( psmatrix3 & A, word N, word M, word K,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-
-//
-//    ShiftN, ShiftM and ShiftK at deallocation MUST be
-//   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//         the same as those at allocation !
-//        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-extern void FreeMatrix3Memory
-               ( rmatrix3  & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern void FreeMatrix3Memory
-               ( imatrix3  & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern void FreeMatrix3Memory
-               ( wmatrix3  & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern void FreeMatrix3Memory
-               ( bmatrix3  & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern void FreeMatrix3Memory
-               ( lmatrix3  & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern void FreeMatrix3Memory
-               ( lwmatrix3 & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-extern void FreeMatrix3Memory
-               ( psmatrix3 & A, word N, word M,
-                 word ShiftN=1, word ShiftM=1, word ShiftK=1 );
-
-// -------------------------------------------------------------
-
-extern  realtype  MachEps;
-extern  realtype  floatMachEps;
-extern  realtype  LnMaxReal;
-extern  realtype  LnMinReal;
-
-extern  realtype  MachinEps     ();
-extern  realtype  floatMachinEps();
-extern  realtype  frac  ( realtype R   );
-extern  long      mod   ( long     x, long     y );
-extern  realtype  Pow   ( realtype X, int      y );
-extern  realtype  Pow1  ( realtype X, realtype Y );
-extern  realtype  Exp   ( realtype X );   // use to avoid catastrophies
-extern  Boolean   Odd   ( int      i );
-extern  long    HexValL ( cpstr S );
-extern  long    OctValL ( cpstr S );
-extern  long    BinValL ( cpstr S );
-extern  pstr    BinValS ( long L, pstr S  );  // S[sizeof(long)+1] at least
-
-extern  pstr ParamStr ( pstr D, cpstr S, realtype V, int M=5,
-                        cpstr S1=(pstr)"" );
-extern  pstr ParamStr ( pstr D, cpstr S, realtype V, int M,
-                        cpstr S1, realtype V2, int M2=5,
-                        cpstr S2=(pstr)"" );
-
-
-
-//  ----------  Strings
-
-//   CreateCopy(..) allocates Dest string and copies the contents of
-// Source into it. If Dest is not NULL prior calling the function,
-// it is attempted to deallocate first.
-
-extern pstr CreateCopy     ( pstr & Dest, cpstr Source );
-extern pstr CreateCopy_n   ( pstr & Dest, cpstr Source, int n );
-
-extern pstr CreateConcat   ( pstr & Dest, cpstr Source );
-extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2 );
-extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2,
-                                          cpstr Source3 );
-extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2,
-                                          cpstr Source3,
-                                          cpstr Source4 );
-extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2,
-                                          cpstr Source3,
-                                          cpstr Source4,
-                                          cpstr Source5 );
-
-extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2,
-                                          cpstr Source3,
-                                          cpstr Source4,
-                                          cpstr Source5 );
-extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2,
-                                          cpstr Source3,
-                                          cpstr Source4 );
-extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2,
-                                          cpstr Source3 );
-extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
-                                          cpstr Source2 );
-
-extern pstr LastOccurence  ( cpstr S     , char c      );
-extern pstr FirstOccurence ( cpstr S     , char c      );
-extern int  indexOf        ( cpstr S     , char c      );
-extern pstr FirstOccurence ( cpstr S, int Slen,
-                             cpstr Q, int Qlen );
-extern int  indexOf        ( cpstr S, int Slen,
-                             cpstr Q, int Qlen );
-
-extern pstr LowerCase ( pstr s );
-extern pstr UpperCase ( pstr s );
-
-//   GetString(..) copies first M characters of string S into string
-// L, appending the terminating null. If S contains less then M
-// characters, L will be padded with spaces.
-extern void GetString ( pstr L, cpstr S, int M );
-
-//   GetStrTer(..) copies at least n (or LMax if LMax<n) first symbols
-// of string S into string L, then continues copying until first space
-// or terminating null is found. If the terminating null is met among
-// the first n characters or if SMax<n, the string L will be padded
-// with spaces till the length of minimum of n and LMax and then
-// terminated with the null.
-//   LMax and SMax are the buffer lengths of L and S,
-// respectively. Even if no space is found, the last character
-// in L will be the terminating null.
-extern void GetStrTer ( pstr L, cpstr S, int n, int LMax,
-                        int SMax );
-
-
-// Version of GetStrTer(..) allowing for spaces in the string.
-//
-//   Copies at least n (or LMax if LMax<n) first symbols of
-// string S into string L, then continues copying until first
-// terminating null is found. If the terminating null
-// is met among the first n characters or if SMax<n, the string
-// L will be padded with spaces till the length of minimum of
-// n and LMax and then terminated with the null.
-//   SMax are buffer lengths of L and S, respectively. The last
-// character in L will be the terminating null.
-extern void GetStrTerWin32File ( pstr L, cpstr S, int n,
-                                 int LMax, int SMax );
-
-
-//   strcpy_n(..) copies at most n symbols from string s to d,
-// but no more than strlen(s) (s must contain a terminating
-// null). The terminating null IS NEITHER appended OR copied
-// to d.
-extern void strcpy_n  ( pstr d, cpstr s, int n );
-
-//   strcpy_n1(..) copies at most n last symbols from string s
-// to d, but no more than strlen(s) (s must contain a terminating
-// null). The string in d is aligned to the right and added with
-// spaces at the left, if necessary. The terminating null
-// IS NEITHER appended OR copied to d.
-extern void strcpy_n1 ( pstr d, cpstr s, int n );
-
-//   Copies at most n symbols from string s to d, but no
-// more than strlen(s) (s must contain a terminating null).
-// The string in d is aligned to the right and added with
-// spaces at the left, if necessary. The terminating null
-// IS NEITHER appended NOR copied to d.
-extern void strcpy_nr ( pstr d, cpstr s, int n );
-
-//   strcpy_ns(..) copies at most n symbols from string s to d,
-// but no more than strlen(s) (s must contain a terminating
-// null). The terminating null IS NEITHER appended NOR copied
-// to d; rather, d is padded with spaces up to the length of n
-// if strlen(s)<n.
-extern void strcpy_ns ( pstr d, cpstr s, int n );
-
-//   strcpy_cs(..) copies string s to string d cutting all
-// spaces at the end. Thus, " abcde   " will be copied
-// like " abcde" (terminating null appended).
-//   The function returns d.
-extern pstr strcpy_cs ( pstr d, cpstr s );
-
-//   strcpy_ncs(..) copies at most n characters from string s
-// to string d cutting all spaces at at the end. Thus, " abcde   "
-// will be copied like " abc" at n=4 and like " abcde" at n>5
-// (terminating null appended).
-//   The function returns d.
-extern pstr strcpy_ncs ( pstr d, cpstr s, int n );
-
-//   strcpy_css(..) copies string s to string d cutting all
-// spaces at the begining and at the end. Thus, " ab c de  "
-// will be copied like "ab c de" (terminating null appended).
-//   The function returns d.
-extern pstr strcpy_css ( pstr d, cpstr s );
-
-//   strcpy_ncss(..) copies at most n characters from string s
-// to string d cutting all spaces at the begining and at the end.
-// Thus, " ab c de  " will be copied like "ab" at n=3 (terminating
-// null appended).
-//   The function returns d.
-extern pstr strcpy_ncss ( pstr d, cpstr s, int n );
-
-//   strcpy_n0(..) copies at most n symbols from string s to d,
-// but no more than strlen(s) (s must contain a terminating
-// null). The terminating null IS appended to d.
-//   The function returns d.
-extern pstr strcpy_n0 ( pstr d, cpstr s, int n );
-
-//   strlen_des returns the length of a string as if all extra
-// spaces from the latter have been deleted. Extra spaces
-// include all leading and tracing spaces and any sequential
-// spaces when more than one. The string does not change.
-extern int strlen_des ( cpstr s );
-
-//   strcpy_des copies string s into string d removing all extra
-// spaces from the latter. Extra spaces include all leading and
-// tracing spaces and any sequential spaces when more than one.
-extern pstr strcpy_des ( pstr d, cpstr s );
-
-//   strcat_des appends string s to string d removing all extra
-// spaces from the latter. Extra spaces include all leading and
-// tracing spaces and any sequential spaces when more than one.
-extern pstr strcat_des ( pstr d, cpstr s );
-
-//  PadSpaces(..) pads string S with spaces making its length
-// equal to len. The terminating zero is added, so that S should
-// reserve space of a minimum len+1 characters.
-extern void PadSpaces ( pstr S, int len );
-
-
-#define SCUTKEY_BEGIN   0x00000001
-#define SCUTKEY_END     0x00000002
-#define SCUTKEY_BEGEND  0x00000003
-
-//   CutSpaces(..) cuts spaces at the begining or end of
-// string S according to the value of CutKey. The function
-// returns S.
-extern pstr CutSpaces ( pstr S, int CutKey );
-
-//   DelSpaces(..) removes all spaces (or other symbols as
-// specified by 'c') from the string. The string is then
-// shrinked by the number of removed characters. Thus,
-// " as ttt  " becomes "asttt".
-extern pstr DelSpaces ( pstr S, char c=' ' );
-
-//   EnforceSpaces(..) replaces all unprintable characters,
-// except <CR>, <LF>, <TAB> and some others, for spaces
-extern pstr EnforceSpaces ( pstr S );
-
-// -------------------------------------------------------------
-
-///   This call will produce correct floats in universal binaries but
-/// make them incompatible with old files. Without this call, float
-/// read/write will result in error after 6th digit.
-///   UniBin read/write of other types (realtype, shortreal, int etc)
-/// is not affected by this call, and to the best of knowledge is
-/// correct (no loss of precision).
-extern void   set_new_float_unibin();
-extern Boolean is_new_float_unibin();
-extern void   set_old_float_unibin();
-
-extern void __modify4();
-
-extern void int2UniBin       ( int       I,  intUniBin        iUB  );
-extern void short2UniBin     ( short     S,  shortUniBin      sUB  );
-extern void long2UniBin      ( long      L,  longUniBin       lUB  );
-extern void word2UniBin      ( word      W,  wordUniBin       wUB  );
-extern void real2UniBin      ( realtype  R,  realUniBin       rUB  );
-extern void float2UniBin     ( realtype  R,  floatUniBin      fUB  );
-extern void shortreal2UniBin ( shortreal R,  shortrealUniBin  srUB );
-extern void UniBin2int       ( intUniBin        iUB, int       & I );
-extern void UniBin2short     ( shortUniBin      sUB, short     & S );
-extern void UniBin2long      ( longUniBin       lUB, long      & L );
-extern void UniBin2word      ( wordUniBin       wUB, word      & W );
-extern void UniBin2real      ( realUniBin       rUB, realtype  & R );
-extern void UniBin2shortreal ( shortrealUniBin srUB, shortreal & R );
-extern void UniBin2float     ( floatUniBin      fUB, realtype  & R );
-
-extern void mem_write ( int       I, pstr S, int & l );
-extern void mem_write ( short     I, pstr S, int & l );
-extern void mem_write ( long      I, pstr S, int & l );
-extern void mem_write ( word      W, pstr S, int & l );
-extern void mem_write ( realtype  R, pstr S, int & l );
-extern void mem_write ( shortreal R, pstr S, int & l );
-extern void mem_write ( pstr      L, int len, pstr S, int & l );
-extern void mem_write ( pstr      L, pstr S, int & l );
-extern void mem_write ( Boolean   B, pstr S, int & l );
-extern void mem_write_byte ( byte B, pstr S, int & l );
-
-extern void mem_read  ( int       & I, cpstr S, int & l );
-extern void mem_read  ( short     & I, cpstr S, int & l );
-extern void mem_read  ( long      & I, cpstr S, int & l );
-extern void mem_read  ( word      & W, cpstr S, int & l );
-extern void mem_read  ( realtype  & R, cpstr S, int & l );
-extern void mem_read  ( shortreal & R, cpstr S, int & l );
-extern void mem_read  ( pstr        L, int len, cpstr S, int & l );
-extern void mem_read  ( pstr      & L, cpstr S, int & l );
-extern void mem_read  ( Boolean   & B, cpstr S, int & l );
-extern void mem_read_byte ( byte  & B, cpstr S, int & l );
-
-#endif
-
-/* ===================================================  */
-
diff --git a/mmdb/mmdb_align.cpp b/mmdb/mmdb_align.cpp
deleted file mode 100755
index 4081ce7..0000000
--- a/mmdb/mmdb_align.cpp
+++ /dev/null
@@ -1,1219 +0,0 @@
-//  $Id: mmdb_align.cpp,v 1.22 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    19.04.11   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Align <implementation>
-//       ~~~~~~~~~
-//  **** Classes    :  CAlignment  ( alignment of character strings )
-//       ~~~~~~~~~~~~  CAlignment1 ( alignment of integer vectors   )
-//
-//  (C) E.Krissinel'  2000-2011
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __MMDB_Align__
-#include "mmdb_align.h"
-#endif
-
-
-//  =====================   CAligParams   ======================
-
-CAlignParams::CAlignParams() : CStream()  {
-  InitAlignParams();
-}
-
-CAlignParams::CAlignParams ( RPCStream Object ) : CStream ( Object )  {
-  InitAlignParams();
-}
-
-void CAlignParams::InitAlignParams()  {
-  gapWeight   = -1.0;
-  spaceWeight = -1.0;
-  equalScore  =  2.0;
-  nequalScore = -1.0;
-  method      = ALIGN_GLOBAL;
-}
-
-void CAlignParams::write ( RCFile f )  {
-  f.WriteReal ( &gapWeight   );
-  f.WriteReal ( &spaceWeight );
-  f.WriteReal ( &equalScore  );
-  f.WriteReal ( &nequalScore );
-  f.WriteInt  ( &method      );
-}
-
-void CAlignParams::read ( RCFile f )  {
-  f.ReadReal ( &gapWeight   );
-  f.ReadReal ( &spaceWeight );
-  f.ReadReal ( &equalScore  );
-  f.ReadReal ( &nequalScore );
-  f.ReadInt  ( &method      );
-}
-
-MakeStreamFunctions(CAlignParams)
-
-
-//  =====================   CAlignment   ======================
-
-CAlignment::CAlignment() : CStream()  {
-  InitAlignment();
-}
-
-CAlignment::CAlignment ( RPCStream Object ) : CStream ( Object )  {
-  InitAlignment();
-}
-
-CAlignment::~CAlignment()  {
-  FreeMemory();
-}
-
-void  CAlignment::InitAlignment()  {
-  Space     = '-';
-  SLen      = 0;
-  TLen      = 0;
-  VT        = NULL;
-  ET        = NULL;
-  FT        = NULL;
-  AlgnS     = NULL;
-  AlgnT     = NULL;
-  AlignKey  = ALIGN_GLOBAL;
-  VAchieved = 0.0;
-  SEq       =  2.0;
-  SNEq      = -1.0;
-  Wg        =  0.0;
-  Ws        = -1.0;
-}
-
-void  CAlignment::FreeMemory()  {
-  FreeMatrixMemory ( VT,TLen+1,0,0 );
-  FreeMatrixMemory ( ET,TLen+1,0,0 );
-  FreeMatrixMemory ( FT,TLen+1,0,0 );
-  if (AlgnS)  {
-    delete[] AlgnS;
-    AlgnS = NULL;
-  }
-  if (AlgnT)  {
-    delete[] AlgnT;
-    AlgnT = NULL;
-  }
-  TLen = 0;
-  SLen = 0;
-}
-
-void  CAlignment::SetAffineModel ( realtype WGap, realtype WSpace )  {
-  Wg = WGap;
-  Ws = WSpace;
-}
-
-void  CAlignment::SetScores ( realtype SEqual, realtype SNEqual )  {
-  SEq  = SEqual;
-  SNEq = SNEqual;
-}
-
-void  CAlignment::Align  ( cpstr S, cpstr T, int Method )  {
-int i,j,i0,j0;
-
-  FreeMemory();
-
-  AlignKey = Method;
-
-  switch (Method)  {
-
-    default             :
-    case ALIGN_GLOBAL   : // global pairwise alignment of S and T
-                          BuildGATable ( S,T, False,False );
-                          VAchieved = VT[TLen][SLen];
-                          Backtrace ( S,T,SLen,TLen,False );
-                          if ((AlgnS[0]!=Space) && (AlgnT[0]!=Space))
-                            VAchieved -= Wg;
-                        break;
-
-    case ALIGN_LOCAL    : // local pairwise alignment of S and T
-                          BuildLATable ( S,T );
-                          VAchieved  = 0.0;
-                          i0 = -1;
-                          j0 = -1;
-                          for (i=0;i<=TLen;i++)
-                            for (j=0;j<=SLen;j++)
-                              if (VT[i][j]>VAchieved)  {
-                                VAchieved = VT[i][j];
-                                i0 = i;
-                                j0 = j;
-                              }
-                          Backtrace ( S,T,j0,i0,True );
-                        break;
-
-    case ALIGN_GLOBLOC  : // global alignment with non-penalized
-                          // end gaps in T
-                          BuildGATable ( S,T,False,True );
-                          VAchieved = -MaxReal;
-                          i0 = -1;
-                          j0 = -1;
-                          for (i=0;i<=TLen;i++)
-                            if (VT[i][SLen]>VAchieved)  {
-                              VAchieved = VT[i][SLen];
-                              i0 = i;
-                              j0 = SLen;
-                            }
-                          Backtrace  ( S,T,j0,i0,False );
-                          AdjustEnds ( S,T,j0,i0 );
-                        break;
-
-    case ALIGN_FREEENDS : // global alignment with non-penalized
-                          // end gaps in both S and T
-                          BuildGATable ( S,T,True,True );
-                          VAchieved = -MaxReal;
-                          i0 = -1;
-                          j0 = -1;
-                          for (i=0;i<=TLen;i++)
-                            if (VT[i][SLen]>VAchieved)  {
-                              VAchieved = VT[i][SLen];
-                              i0 = i;
-                              j0 = SLen;
-                            }
-                          for (j=0;j<=SLen;j++)
-                            if (VT[TLen][j]>VAchieved)  {
-                              VAchieved = VT[TLen][j];
-                              i0 = TLen;
-                              j0 = j;
-                            }
-                          Backtrace  ( S,T,j0,i0,False );
-                          AdjustEnds ( S,T,j0,i0 );
-
-  }
-
-}
-
-
-void  CAlignment::BuildGATable ( cpstr S, cpstr T,
-                                 Boolean FreeSEnd,
-                                 Boolean FreeTEnd )  {
-int      i,j;
-realtype V1;
-
-  SLen = strlen ( S );
-  TLen = strlen ( T );
-  GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
-
-  //  Base conditions
-  if (FreeSEnd || FreeTEnd)  VT[0][0] = RMax(0.0,Wg);
-                       else  VT[0][0] = Wg;
-  ET[0][0] = VT[0][0];
-  FT[0][0] = VT[0][0];
-
-  if (FreeTEnd)
-    for (i=1;i<=TLen;i++)  {
-      V1       = RMax ( 0.0,VT[i-1][0]+Ws );
-      VT[i][0] = V1;
-      ET[i][0] = V1;
-    }
-  else
-    for (i=1;i<=TLen;i++)  {
-      V1       = VT[i-1][0] + Ws;
-      VT[i][0] = V1;
-      ET[i][0] = V1;
-    }
-
-  if (FreeSEnd)
-    for (j=1;j<=SLen;j++)  {
-      V1       = RMax ( 0.0,VT[0][j-1]+Ws );
-      VT[0][j] = V1;
-      FT[0][j] = V1;
-    }
-  else
-    for (j=1;j<=SLen;j++)  {
-      V1       = VT[0][j-1] + Ws;
-      VT[0][j] = V1;
-      FT[0][j] = V1;
-    }
-
-  //  Recurrence
-  for (i=1;i<=TLen;i++)
-    for (j=1;j<=SLen;j++)  {
-      V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
-      ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
-      FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
-      VT[i][j] = RMax ( RMax(V1,ET[i][j]),FT[i][j] );
-    }
-
-  FreeMatrixMemory ( ET,TLen+1,0,0 );
-  FreeMatrixMemory ( FT,TLen+1,0,0 );
-
-//  PrintVT ( S,T );
-
-}
-
-
-void  CAlignment::BuildLATable ( cpstr S, cpstr T )  {
-int      i,j;
-realtype V1;
-
-  SLen = strlen ( S );
-  TLen = strlen ( T );
-  GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
-
-  //  Base conditions
-  VT[0][0] = RMax ( 0.0,Wg );
-  ET[0][0] = VT[0][0];
-  FT[0][0] = VT[0][0];
-  for (i=1;i<=TLen;i++)  {
-    V1       = RMax ( 0.0,VT[i-1][0]+Ws );
-    VT[i][0] = V1;
-    ET[i][0] = V1;
-  }
-  for (j=1;j<=SLen;j++)  {
-    V1       = RMax ( 0.0,VT[0][j-1]+Ws );
-    VT[0][j] = V1;
-    FT[0][j] = V1;
-  }
-
-  //  Recurrence
-  for (i=1;i<=TLen;i++)
-    for (j=1;j<=SLen;j++)  {
-      V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
-      ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
-      FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
-      VT[i][j] = RMax ( RMax(V1,ET[i][j]),RMax(0.0,FT[i][j]) );
-    }
-
-  FreeMatrixMemory ( ET,TLen+1,0,0 );
-  FreeMatrixMemory ( FT,TLen+1,0,0 );
-
-//  PrintVT ( S,T );
-
-}
-
-void  CAlignment::PrintVT ( cpstr S, cpstr T )  {
-int i,j;
-  printf ( "\n       " );
-  for (j=0;j<=SLen;j++)
-    printf ( " %2i",j );
-  printf ( " \n           " );
-  for (j=1;j<=SLen;j++)
-    printf ( " %c ",S[j-1] );
-  printf ( " \n\n " );
-  for (i=0;i<=TLen;i++)  {
-    if (i>0)  printf ( " %2i %c ",i,T[i-1] );
-        else  printf ( " %2i   ",i );
-    for (j=0;j<=SLen;j++)
-      printf ( " %2i",mround(VT[i][j]) );
-    printf ( " \n " );
-  }
-  printf ( " \n" );
-}
-
-
-void  CAlignment::Backtrace ( cpstr S, cpstr T, int J, int I,
-                              Boolean StopAtZero )  {
-int       i,j,k, i1,j1, sk,tk;
-char      C;
-realtype  V,SV,TV;
-Boolean   Stop;
-
-  //  1. Allocate memory
-
-  if (AlgnS)  delete[] AlgnS;
-  if (AlgnT)  delete[] AlgnT;
-
-  i = SLen+TLen+1;
-  AlgnS = new char[i];
-  AlgnT = new char[i];
-  memset ( AlgnS,Space,i );
-  memset ( AlgnT,Space,i );
-
-  //  2. Initialize backtracing
-  i  = I;   // backtracing
-  j  = J;   //    indices
-  k  = 0;   // alignment index
-  SV = 0.0;  sk = -1;   // alignment indices and leading elements
-  TV = 0.0;  tk = -1;   //   for vertical and horizontal sections
-
-
-  //  3. Backtracing
-  Stop = False;
-  while ((!Stop) && (i>0) && (j>0))  {
-
-    V = VT[i][j];
-
-    // find next leading element
-    if (VT[i][j-1]>VT[i-1][j])  {
-      i1 = i;    j1 = j-1;
-    } else  {
-      i1 = i-1;  j1 = j;
-    }
-    if (VT[i-1][j-1]>=VT[i1][j1])  {
-      i1 = i-1;  j1 = j-1;
-    }
-
-//printf ( "  i=%i  j=%i \n",i,j );
-
-    Stop = StopAtZero && (VT[i1][j1]<=0.0);  // used at local alignment
-
-    // treat horizontal section
-    if ((sk<0) || (V>SV))  {
-      sk = k;
-      SV = V;
-    }
-    if ((j1!=j) || Stop)  {  // end of horizontal section
-      AlgnS[sk] = S[j-1];
-      sk = -1;
-    }
-
-    // treat vertical section
-    if ((tk<0) || (V>TV))  {
-      tk = k;
-      TV = V;
-    }
-    if ((i1!=i) || Stop)  {  // end of vertical section
-      AlgnT[tk] = T[i-1];
-      tk = -1;
-    }
-
-    i = i1;
-    j = j1;
-    k++;
-
-  }
-
-  if (!StopAtZero)  {
-    //  4. Finish the last horizontal section
-    sk = k;
-    while (j>0)  AlgnS[k++] = S[--j];
-    //  5. Finish the last vertical section
-    while (i>0)  AlgnT[sk++] = T[--i];
-    k = IMax ( k,sk );
-  }
-
-  //  6. Put the termination character
-  AlgnS[k] = char(0);
-  AlgnT[k] = char(0);
-
-  //  7. Reverse the strings
-  i = 0;
-  j = k-1;
-  if (StopAtZero)  {
-    // should work only for local alignment
-    while ((j>0) && ((AlgnS[j]==Space) || (AlgnT[j]==Space)))  j--;
-    k = j+1;
-    AlgnS[k] = char(0);
-    AlgnT[k] = char(0);
-  }
-  while (j>i)  {
-    C = AlgnS[i];  AlgnS[i] = AlgnS[j];  AlgnS[j] = C;
-    C = AlgnT[i];  AlgnT[i] = AlgnT[j];  AlgnT[j] = C;
-    i++;
-    j--;
-  }
-
-  //  8. Collapse the alternating spaces
-  do  {
-    k = 0;
-    i = 0;
-    while (AlgnS[k])  {
-      if ((AlgnS[k]==Space) && (AlgnT[k]==Space))  k++;
-      else if ((AlgnS[k]==Space) && (AlgnS[k+1]!=Space) &&
-               (AlgnT[k]!=Space) && (AlgnT[k+1]==Space))  {
-        AlgnS[i] = AlgnS[k+1];
-        AlgnT[i] = AlgnT[k];
-        k++;
-      } else if ((AlgnS[k]!=Space) && (AlgnS[k+1]==Space) &&
-                 (AlgnT[k]==Space) && (AlgnT[k+1]!=Space))  {
-        AlgnS[i] = AlgnS[k];
-        AlgnT[i] = AlgnT[k+1];
-        k++;
-      } else if (i!=k)  {
-        AlgnS[i] = AlgnS[k];
-        AlgnT[i] = AlgnT[k];
-      }
-      if (AlgnS[k])  {
-        k++;
-        i++;
-      }
-    }
-    if (i!=k)  {  // terminating character
-      AlgnS[i] = AlgnS[k];
-      AlgnT[i] = AlgnT[k];
-    }
-  } while (k>i);
-
-}
-
-
-void  CAlignment::AdjustEnds ( cpstr S, cpstr T, int J, int I )  {
-int si,ti,m;
-
-  if (J<SLen)  strcat ( AlgnS,&(S[J]) );
-  if (I<TLen)  strcat ( AlgnT,&(T[I]) );
-  si = strlen ( AlgnS );
-  ti = strlen ( AlgnT );
-  m  = IMax ( si,ti );
-  while (si<m)  AlgnS[si++] = Space;
-  while (ti<m)  AlgnT[ti++] = Space;
-  AlgnS[si] = char(0);
-  AlgnT[ti] = char(0);
-
-/*
-int k,m;
-
-  if (J>I)  {
-    k = J-I;
-    strcat ( AlgnT,&(T[IMax(0,TLen-k)]) );
-    k = strlen ( AlgnS );
-    m = strlen ( AlgnT );
-    while (k<m)
-      AlgnS[k++] = Space;
-    AlgnS[k] = char(0);
-  } else if (I>J)  {
-    k = I-J;
-    strcat ( AlgnS,&(S[IMax(0,SLen-k)]) );
-    k = strlen ( AlgnT );
-    m = strlen ( AlgnS );
-    while (k<m)
-      AlgnT[k++] = Space;
-    AlgnT[k] = char(0);
-  }
-*/
-
-}
-
-
-realtype CAlignment::Score ( char A, char B )  {
-  if (A==B)  return SEq;
-  if ((A==Space) || (B==Space))  return Ws;
-  return SNEq;
-}
-
-realtype CAlignment::GetSimilarity()  {
-realtype s,a;
-int      i,n;
-
-  s = 0.0;
-  a = 0.0;
-  n = IMin ( strlen(AlgnS),strlen(AlgnT) );
-
-  for (i=0;i<n;i++)
-    if ((AlgnS[i]!=Space) || (AlgnT[i]!=Space))  {
-      a += RMax ( Score(AlgnS[i],AlgnS[i]),Score(AlgnT[i],AlgnT[i]) );
-      s += Score ( AlgnS[i],AlgnT[i] );
-    }
-
-  if ((s>0.0) && (a>0.0))  return s/a;
-  return 0.0;
-
-}
-
-
-realtype CAlignment::GetSeqId()  {
-realtype s;
-int      i,n,ne,ns,nt;
-
-  ne = 0;
-  ns = 0;
-  nt = 0;
-  n  = IMin ( strlen(AlgnS),strlen(AlgnT) );
-
-  for (i=0;i<n;i++)  {
-    if (AlgnS[i]!=Space)  ns++;
-    if (AlgnT[i]!=Space)  {
-      nt++;
-      if (AlgnS[i]==AlgnT[i])
-        ne++;
-    }
-  }
-
-  s = IMin ( ns,nt );
-  if (s>0.0)  return ne/s;
-  return 0.0;
-
-}
-
-
-#define  WrapPeriod  61
-
-void  CAlignment::OutputResults ( RCFile f, cpstr S, cpstr T )  {
-int   k,l,n;
-char  P[3];
-
-  P[1] = char(0);
-  if ((!AlgnS) || (!AlgnT))  {
-    f.LF();
-    f.WriteLine ( pstr(" NO ALIGNMENT HAS BEEN DONE.") );
-    f.shut();
-    return;
-  }
-  f.LF();
-  f.WriteLine ( pstr(" ========  INPUT DATA") );
-  f.LF();
-  f.WriteLine ( pstr(" String S:") );
-  f.Write ( pstr(" ") );
-  l = 1;
-  k = 0;
-  while (S[k])  {
-    P[0] = S[k++];
-    f.Write ( P );
-    l++;
-    if (l>=WrapPeriod)  {
-      f.LF();  f.Write ( pstr(" ") );  l = 1;
-    }
-  }
-  f.LF();
-  f.LF();
-  f.WriteLine ( pstr(" String T:") );
-  f.Write ( pstr(" ") );
-  l = 1;
-  k = 0;
-  while (T[k])  {
-    P[0] = T[k++];
-    f.Write ( P );
-    l++;
-    if (l>=WrapPeriod)  {
-      f.LF();  f.Write ( pstr(" ") );  l = 1;
-    }
-  }
-  f.LF();
-  f.LF();
-  f.WriteParameter ( pstr(" Score equal")  ,SEq ,20,10 );
-  f.WriteParameter ( pstr(" Score unequal"),SNEq,20,10 );
-  f.LF();
-  f.WriteParameter ( pstr(" Gap weight")   ,Wg  ,20,10 );
-  f.WriteParameter ( pstr(" Space weight") ,Ws  ,20,10 );
-  f.LF();
-  f.LF();
-  f.Write ( pstr(" ========  RESULT OF ") );
-  switch (AlignKey)  {
-    default             :
-    case ALIGN_GLOBAL   : f.Write ( pstr("GLOBAL")       );  break;
-    case ALIGN_LOCAL    : f.Write ( pstr("LOCAL")        );  break;
-    case ALIGN_GLOBLOC  : f.Write ( pstr("GLOBAL/LOCAL") );  break;
-    case ALIGN_FREEENDS : f.Write ( pstr("FREE-ENDS")    );
-  }
-  f.WriteLine ( pstr(" ALIGNMENT") );
-  f.LF();
-  if (AlignKey==ALIGN_GLOBLOC)  {
-    f.WriteLine ( pstr(" End gaps in T-string were not penalized") );
-    f.LF();
-  }
-  f.WriteParameter ( pstr(" Highest score achieved:"),VAchieved,26,10 );
-  f.LF();
-  f.WriteLine ( pstr(" Aligned S (upper string) and T (lower string):") );
-  f.LF();
-  k = 0;
-  n = 0;
-  l = 1;  f.Write ( pstr(" ") );
-  while (AlgnS[k])  {
-    P[0] = AlgnS[k++];
-    f.Write ( P );
-    l++;
-    if ((l>=WrapPeriod) || (!AlgnS[k]))  {
-      f.LF();  f.Write ( pstr(" ") );  l = 1;
-      while (AlgnT[n] && (l<WrapPeriod))  {
-        P[0] = AlgnT[n++];
-        f.Write ( P );
-        l++;
-      }
-      f.LF(); f.LF(); f.Write ( pstr(" ") );  l = 1;
-    }
-  }
-
-}
-
-
-//  -----------------  Streaming  -----------------------------
-
-void  CAlignment::write ( RCFile f )  {
-int Version=1;
-  f.WriteFile ( &Version,sizeof(Version) );
-  CStream::write ( f );
-}
-
-void  CAlignment::read ( RCFile f )  {
-int Version;
-  f.ReadFile ( &Version,sizeof(Version) );
-  CStream::write ( f );
-}
-
-
-
-//  =====================   CAlignment1   ======================
-
-CAlignment1::CAlignment1() : CStream()  {
-  InitAlignment1();
-}
-
-CAlignment1::~CAlignment1()  {
-  FreeMemory();
-}
-
-void  CAlignment1::InitAlignment1()  {
-  Space     = 0;
-  SLen      = 0;
-  TLen      = 0;
-  AlgnLen   = 0;
-  VT        = NULL;
-  ET        = NULL;
-  FT        = NULL;
-  AlgnS     = NULL;
-  AlgnT     = NULL;
-  AlignKey  = ALIGN_GLOBAL;
-  VAchieved = 0.0;
-  SEq       =  2.0;
-  SNEq      = -1.0;
-  Wg        =  0.0;
-  Ws        = -1.0;
-}
-
-void  CAlignment1::FreeMemory()  {
-  FreeMatrixMemory ( VT,TLen+1,0,0 );
-  FreeMatrixMemory ( ET,TLen+1,0,0 );
-  FreeMatrixMemory ( FT,TLen+1,0,0 );
-  FreeVectorMemory ( AlgnS,0 );
-  FreeVectorMemory ( AlgnT,0 );
-  TLen    = 0;
-  SLen    = 0;
-  AlgnLen = 0;
-}
-
-void  CAlignment1::SetAffineModel ( realtype WGap, realtype WSpace )  {
-  Wg = WGap;
-  Ws = WSpace;
-}
-
-void  CAlignment1::SetScores ( realtype SEqual, realtype SNEqual )  {
-  SEq  = SEqual;
-  SNEq = SNEqual;
-}
-
-void  CAlignment1::Align  ( ivector S, int SLength,
-                            ivector T, int TLength, int Method )  {
-int i,j,i0,j0;
-
-  FreeMemory();
-
-  SLen = SLength;
-  TLen = TLength;
-
-  AlignKey = Method;
-
-  switch (Method)  {
-
-    default             :
-    case ALIGN_GLOBAL   : // global pairwise alignment of S and T
-                          BuildGATable ( S,T, False,False );
-                          VAchieved = VT[TLen][SLen];
-                          Backtrace ( S,T,SLen,TLen,False );
-                          if ((AlgnS[0]!=Space) && (AlgnT[0]!=Space))
-                            VAchieved -= Wg;
-                        break;
-
-    case ALIGN_LOCAL    : // local pairwise alignment of S and T
-                          BuildLATable ( S,T );
-                          VAchieved = 0.0;
-                          i0 = -1;
-                          j0 = -1;
-                          for (i=0;i<=TLen;i++)
-                            for (j=0;j<=SLen;j++)
-                              if (VT[i][j]>VAchieved)  {
-                                VAchieved = VT[i][j];
-                                i0 = i;
-                                j0 = j;
-                              }
-                          Backtrace ( S,T,j0,i0,True );
-                        break;
-
-    case ALIGN_GLOBLOC  : // global alignment with non-penalized
-                          // end gaps in T
-                          BuildGATable ( S,T,False,True );
-                          VAchieved = -MaxReal;
-                          i0 = -1;
-                          j0 = -1;
-                          for (i=0;i<=TLen;i++)
-                            if (VT[i][SLen]>VAchieved)  {
-                              VAchieved = VT[i][SLen];
-                              i0 = i;
-                              j0 = SLen;
-                            }
-                          Backtrace  ( S,T,j0,i0,False );
-                          AdjustEnds ( S,T,j0,i0 );
-                        break;
-
-    case ALIGN_FREEENDS : // global alignment with non-penalized
-                          // end gaps in both S and T
-                          BuildGATable ( S,T,True,True );
-                          VAchieved = -MaxReal;
-                          i0 = -1;
-                          j0 = -1;
-                          for (i=0;i<=TLen;i++)
-                            if (VT[i][SLen]>VAchieved)  {
-                              VAchieved = VT[i][SLen];
-                              i0 = i;
-                              j0 = SLen;
-                            }
-                          for (j=0;j<=SLen;j++)
-                            if (VT[TLen][j]>VAchieved)  {
-                              VAchieved = VT[TLen][j];
-                              i0 = TLen;
-                              j0 = j;
-                            }
-                          Backtrace  ( S,T,j0,i0,False );
-                          AdjustEnds ( S,T,j0,i0 );
-  }
-
-}
-
-
-void  CAlignment1::BuildGATable ( ivector S, ivector T,
-                                  Boolean FreeSEnd,
-                                  Boolean FreeTEnd )  {
-int      i,j;
-realtype V1;
-
-  GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
-
-  //  Base conditions
-  if (FreeSEnd || FreeTEnd)  VT[0][0] = RMax(0.0,Wg);
-                       else  VT[0][0] = Wg;
-  ET[0][0] = VT[0][0];
-  FT[0][0] = VT[0][0];
-
-  if (FreeTEnd)
-    for (i=1;i<=TLen;i++)  {
-      V1       = RMax ( 0.0,VT[i-1][0]+Ws );
-      VT[i][0] = V1;
-      ET[i][0] = V1;
-    }
-  else
-    for (i=1;i<=TLen;i++)  {
-      V1       = VT[i-1][0] + Ws;
-      VT[i][0] = V1;
-      ET[i][0] = V1;
-    }
-
-  if (FreeSEnd)
-    for (j=1;j<=SLen;j++)  {
-      V1       = RMax ( 0.0,VT[0][j-1]+Ws );
-      VT[0][j] = V1;
-      FT[0][j] = V1;
-    }
-  else
-    for (j=1;j<=SLen;j++)  {
-      V1       = VT[0][j-1] + Ws;
-      VT[0][j] = V1;
-      FT[0][j] = V1;
-    }
-
-  //  Recurrence
-  for (i=1;i<=TLen;i++)
-    for (j=1;j<=SLen;j++)  {
-      V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
-      ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
-      FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
-      VT[i][j] = RMax ( RMax(V1,ET[i][j]),FT[i][j] );
-    }
-
-  FreeMatrixMemory ( ET,TLen+1,0,0 );
-  FreeMatrixMemory ( FT,TLen+1,0,0 );
-
-//  PrintVT ( S,T );
-
-}
-
-
-void  CAlignment1::BuildLATable ( ivector S, ivector T )  {
-int      i,j;
-realtype V1;
-
-  GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
-  GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
-
-  //  Base conditions
-  VT[0][0] = RMax ( 0.0,Wg );
-  ET[0][0] = VT[0][0];
-  FT[0][0] = VT[0][0];
-  for (i=1;i<=TLen;i++)  {
-    V1       = RMax ( 0.0,VT[i-1][0]+Ws );
-    VT[i][0] = V1;
-    ET[i][0] = V1;
-  }
-  for (j=1;j<=SLen;j++)  {
-    V1       = RMax ( 0.0,VT[0][j-1]+Ws );
-    VT[0][j] = V1;
-    FT[0][j] = V1;
-  }
-
-  //  Recurrence
-  for (i=1;i<=TLen;i++)
-    for (j=1;j<=SLen;j++)  {
-      V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
-      ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
-      FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
-      VT[i][j] = RMax ( RMax(V1,ET[i][j]),RMax(0.0,FT[i][j]) );
-    }
-
-  FreeMatrixMemory ( ET,TLen+1,0,0 );
-  FreeMatrixMemory ( FT,TLen+1,0,0 );
-
-//  PrintVT ( S,T );
-
-}
-
-void  CAlignment1::PrintVT ( ivector S, ivector T )  {
-int i,j;
-  printf ( "\n       " );
-  for (j=0;j<=SLen;j++)
-    printf ( " %2i",j );
-  printf ( " \n           " );
-  for (j=1;j<=SLen;j++)
-    printf ( " %3i ",S[j-1] );
-  printf ( " \n\n " );
-  for (i=0;i<=TLen;i++)  {
-    if (i>0)  printf ( " %2i %3i ",i,T[i-1] );
-        else  printf ( " %2i   ",i );
-    for (j=0;j<=SLen;j++)
-      printf ( " %2i",mround(VT[i][j]) );
-    printf ( " \n " );
-  }
-  printf ( " \n" );
-}
-
-
-void  CAlignment1::Backtrace ( ivector S, ivector T, int J, int I,
-                               Boolean StopAtZero )  {
-int       i,j,k, i1,j1, sk,tk;
-int       C;
-realtype  V,SV,TV;
-Boolean   Stop;
-
-  //  1. Allocate memory
-
-  FreeVectorMemory ( AlgnS,0 );
-  FreeVectorMemory ( AlgnT,0 );
-  AlgnLen = 0;
-
-  k = SLen+TLen+1;
-  GetVectorMemory  ( AlgnS,k,0 );
-  GetVectorMemory  ( AlgnT,k,0 );
-  for (i=0;i<k;i++)  {
-    AlgnS[i] = Space;
-    AlgnT[i] = Space;
-  }
-
-  //  2. Initialize backtracing
-  i = I;   // backtracing
-  j = J;   //    indices
-
-  k  = 0;   // alignment index
-  SV = 0.0;  sk = -1;   // alignment indices and leading elements
-  TV = 0.0;  tk = -1;   //   for vertical and horizontal sections
-
-
-  //  3. Backtracing
-  Stop = False;
-  while ((!Stop) && (i>0) && (j>0))  {
-
-    V = VT[i][j];
-
-    // find next leading element
-    if (VT[i][j-1]>VT[i-1][j])  {
-      i1 = i;    j1 = j-1;
-    } else  {
-      i1 = i-1;  j1 = j;
-    }
-    if (VT[i-1][j-1]>=VT[i1][j1]) {
-      i1 = i-1;  j1 = j-1;
-    }
-
-    Stop = StopAtZero && (VT[i1][j1]<=0.0);  // used at local alignment
-
-    // treat horizontal section
-    if ((sk<0) || (V>SV))  {
-      sk = k;
-      SV = V;
-    }
-    if ((j1!=j) || Stop)  {  // end of horizontal section
-      AlgnS[sk] = S[j-1];
-      sk = -1;
-    }
-
-    // treat vertical section
-    if ((tk<0) || (V>TV))  {
-      tk = k;
-      TV = V;
-    }
-    if ((i1!=i) || Stop)  {  // end of vertical section
-      AlgnT[tk] = T[i-1];
-      tk = -1;
-    }
-
-    i = i1;
-    j = j1;
-    k++;
-
-  }
-
-  if (!StopAtZero)  {
-    //  4. Finish the last horizontal section
-    sk = k;
-    while (j>0)  AlgnS[k++] = S[--j];
-    //  5. Finish the last vertical section
-    while (i>0)  AlgnT[sk++] = T[--i];
-    k = IMax ( k,sk );
-  }
-
-  //  6. Put the termination character
-  AlgnLen  = k;
-
-  //  7. Reverse the strings
-  i = 0;
-  j = k-1;
-  if (StopAtZero)  {
-    // should work only for local alignment
-    while ((j>0) && ((AlgnS[j]==Space) || (AlgnT[j]==Space)))  j--;
-    AlgnLen = j+1;
-  }
-  while (j>i)  {
-    C = AlgnS[i];  AlgnS[i] = AlgnS[j];  AlgnS[j] = C;
-    C = AlgnT[i];  AlgnT[i] = AlgnT[j];  AlgnT[j] = C;
-    i++;
-    j--;
-  }
-
-  //  8. Filter out parasite spaces
-  k = 0;
-  i = 0;
-  while (k<AlgnLen) {
-    while ((k<AlgnLen) && (AlgnS[k]==Space) && (AlgnT[k]==Space))  k++;
-    if (k<AlgnLen) {
-      AlgnS[i] = AlgnS[k];
-      AlgnT[i] = AlgnT[k];
-      k++;
-      i++;
-    }
-  }
-
-  AlgnLen = i;
-
-  //  9. Collapse the alternating spaces
-  do  {
-
-    k = 0;
-    i = 0;
-    while (k<AlgnLen)  {
-      if ((AlgnS[k]==Space) && (AlgnT[k]==Space))  k++;
-      else if ((k+1<AlgnLen) &&
-               (AlgnS[k]==Space) && (AlgnS[k+1]!=Space) &&
-               (AlgnT[k]!=Space) && (AlgnT[k+1]==Space))  {
-        AlgnS[i] = AlgnS[k+1];
-        AlgnT[i] = AlgnT[k];
-        k++;
-      } else if ((k+1<AlgnLen) &&
-                 (AlgnS[k]!=Space) && (AlgnS[k+1]==Space) &&
-                 (AlgnT[k]==Space) && (AlgnT[k+1]!=Space))  {
-        AlgnS[i] = AlgnS[k];
-        AlgnT[i] = AlgnT[k+1];
-        k++;
-      } else if (i!=k)  {
-        AlgnS[i] = AlgnS[k];
-        AlgnT[i] = AlgnT[k];
-      }
-      if (k<AlgnLen)  {
-        k++;
-        i++;
-      }
-    }
-
-    AlgnLen = i;
-
-  } while (k>i);
-
-
-}
-
-
-void  CAlignment1::AdjustEnds ( ivector S, ivector T, int J, int I )  {
-int is,it;
-  is = J;
-  it = I;
-  while ((is<SLen) || (it<TLen))  {
-    if (is<SLen)  AlgnS[AlgnLen] = S[is];
-            else  AlgnS[AlgnLen] = Space;
-    if (it<TLen)  AlgnT[AlgnLen] = T[it];
-            else  AlgnT[AlgnLen] = Space;
-    is++;
-    it++;
-    AlgnLen++;
-  }
-}
-
-realtype CAlignment1::Score ( int A, int B )  {
-  if (A==B)  {
-    if (A==Space)  return 0.0;
-             else  return SEq;
-  }
-  if ((A==Space) || (B==Space))  return Ws;
-  return SNEq;
-}
-
-
-realtype CAlignment1::GetSimilarity()  {
-realtype s,a;
-int      i;
-
-  s = 0.0;
-  a = 0.0;
-
-  for (i=0;i<AlgnLen;i++)
-    if ((AlgnS[i]!=Space) || (AlgnT[i]!=Space))  {
-      a += RMax ( Score(AlgnS[i],AlgnS[i]),Score(AlgnT[i],AlgnT[i]) );
-      s += Score ( AlgnS[i],AlgnT[i] );
-    }
-
-  if ((s>0.0) && (a>0.0))  return s/a;
-  return 0.0;
-
-}
-
-
-void  CAlignment1::OutputResults ( RCFile  f, ivector S, int lenS,
-                                   ivector T, int lenT )  {
-int   k,l,n;
-char  P[10];
-
-  if ((!AlgnS) || (!AlgnT))  {
-    f.LF();
-    f.WriteLine ( pstr(" NO ALIGNMENT HAS BEEN DONE.") );
-    f.shut();
-    return;
-  }
-  f.LF();
-  f.WriteLine ( pstr(" ========  INPUT DATA") );
-  f.LF();
-  f.WriteLine ( pstr(" String S:") );
-  f.Write ( pstr(" ") );
-  l = 1;
-  k = 0;
-  while (k<lenS)  {
-    sprintf ( P,"%4i ",S[k++] );
-    f.Write ( P );
-    l += 5;
-    if (l>=WrapPeriod)  {
-      f.LF();  f.Write ( pstr(" ") );  l = 1;
-    }
-  }
-  f.LF();
-  f.LF();
-  f.WriteLine ( pstr(" String T:") );
-  f.Write ( pstr(" ") );
-  l = 1;
-  k = 0;
-  while (k<lenT)  {
-    sprintf ( P,"%4i ",T[k++] );
-    f.Write ( P );
-    l += 5;
-    if (l>=WrapPeriod)  {
-      f.LF();  f.Write ( pstr(" ") );  l = 1;
-    }
-  }
-  f.LF();
-  f.LF();
-  f.WriteParameter ( pstr(" Score equal")  ,SEq ,20,10 );
-  f.WriteParameter ( pstr(" Score unequal"),SNEq,20,10 );
-  f.LF();
-  f.WriteParameter ( pstr(" Gap weight")   ,Wg  ,20,10 );
-  f.WriteParameter ( pstr(" Space weight") ,Ws  ,20,10 );
-  f.LF();
-  f.LF();
-  f.Write ( pstr(" ========  RESULT OF ") );
-  switch (AlignKey)  {
-    default             :
-    case ALIGN_GLOBAL   : f.Write ( pstr("GLOBAL")       );  break;
-    case ALIGN_LOCAL    : f.Write ( pstr("LOCAL")        );  break;
-    case ALIGN_GLOBLOC  : f.Write ( pstr("GLOBAL/LOCAL") );  break;
-    case ALIGN_FREEENDS : f.Write ( pstr("FREE-ENDS")    );
-  }
-  f.WriteLine ( pstr(" ALIGNMENT") );
-  f.LF();
-  if (AlignKey==ALIGN_GLOBLOC)  {
-    f.WriteLine ( pstr(" End gaps in T-string were not penalized") );
-    f.LF();
-  }
-  f.WriteParameter ( pstr(" Highest score achieved:"),
-                     VAchieved,26,10 );
-  f.LF();
-  f.WriteLine ( pstr(" Aligned S (upper string) and T "
-                     "(lower string):") );
-  f.LF();
-  k = 0;
-  n = 0;
-  l = 1;  f.Write ( pstr(" ") );
-  while (k<AlgnLen)  {
-    sprintf ( P,"%4i ",AlgnS[k++] );
-    f.Write ( P );
-    l += 5;
-    if ((l>=WrapPeriod) || (!AlgnS[k]))  {
-      f.LF();  f.Write ( pstr(" ") );  l = 1;
-      while ((n<AlgnLen) && (l<WrapPeriod))  {
-        sprintf ( P,"%4i ",AlgnT[n++] );
-        f.Write ( P );
-        l += 5;
-      }
-      f.LF(); f.LF(); f.Write ( pstr(" ") );  l = 1;
-    }
-  }
-
-}
-
-
-//  -----------------  Streaming  -----------------------------
-
-void  CAlignment1::write ( RCFile f )  {
-int Version=1;
-  f.WriteFile ( &Version,sizeof(Version) );
-  CStream::write ( f );
-}
-
-void  CAlignment1::read ( RCFile f )  {
-int Version;
-  f.ReadFile ( &Version,sizeof(Version) );
-  CStream::write ( f );
-}
-
diff --git a/mmdb/mmdb_align.h b/mmdb/mmdb_align.h
deleted file mode 100755
index be2ebb9..0000000
--- a/mmdb/mmdb_align.h
+++ /dev/null
@@ -1,189 +0,0 @@
-//  $Id: mmdb_align.h,v 1.21 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    19.04.11   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Align <interface>
-//       ~~~~~~~~~
-//  **** Classes    :  CAlignment  ( alignment of character strings )
-//       ~~~~~~~~~~~~  CAlignment1 ( alignment of integer vectors   )
-//
-//  (C) E.Krissinel'  2000-2011
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Align__
-#define __MMDB_Align__
-
-#ifndef  __Stream__
-#include "stream_.h"
-#endif
-
-
-//  =====================   CAlignParams   ======================
-
-
-DefineClass(CAlignParams);
-DefineStreamFunctions(CAlignParams);
-
-class CAlignParams : public CStream  {
-
-  public :
-
-    realtype  gapWeight,spaceWeight;
-    realtype  equalScore,nequalScore;
-    int       method;
-
-    CAlignParams();
-    CAlignParams ( RPCStream Object );
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected :
-    void InitAlignParams();
-
-};
-
-
-//  =====================   CAlignment   ======================
-
-DefineClass(CAlignment);
-
-#define ALIGN_GLOBAL    0
-#define ALIGN_LOCAL     1
-#define ALIGN_GLOBLOC   2
-#define ALIGN_FREEENDS  3
-
-class  CAlignment : public CStream  {
-
-  public :
-
-    CAlignment  ();
-    CAlignment  ( RPCStream Object );
-    ~CAlignment ();
-
-    void SetAffineModel ( realtype WGap,   realtype WSpace  );
-    void SetScores      ( realtype SEqual, realtype SNEqual );
-
-    void Align          ( cpstr S, cpstr T, int Method=ALIGN_GLOBAL );
-
-    pstr     GetAlignedS()  {  return AlgnS;      }
-    pstr     GetAlignedT()  {  return AlgnT;      }
-    realtype GetScore   ()  {  return VAchieved;  }
-    char     GetSpace   ()  {  return Space;      }
-
-    realtype GetSimilarity(); // Score-weighted sequence id
-    realtype GetSeqId     (); // Primitive sequence id
-
-    virtual void OutputResults ( RCFile f, cpstr S, cpstr T  );
-
-    void read   ( RCFile f );
-    void write  ( RCFile f );
-
-  protected :
-
-    char     Space;
-    int      AlignKey, SLen,TLen;
-    rmatrix  VT,ET,FT;
-    pstr     AlgnS,AlgnT;
-    realtype VAchieved;
-    realtype SEq,SNEq, Wg,Ws;
-
-    virtual void  InitAlignment();
-    virtual void  FreeMemory   ();
-    virtual realtype  Score    ( char A, char B );
-
-    void    BuildGATable ( cpstr S, cpstr T,
-                           Boolean FreeSEnd, Boolean FreeTEnd );
-    void    BuildLATable ( cpstr S, cpstr T );
-    void    Backtrace    ( cpstr S, cpstr T, int J, int I,
-                           Boolean StopAtZero );
-    void    AdjustEnds   ( cpstr S, cpstr T, int J, int I );
-    void    PrintVT      ( cpstr S, cpstr T );
-
-};
-
-
-
-//  =====================   CAlignment1   ======================
-
-DefineClass(CAlignment1);
-
-class  CAlignment1 : public CStream  {
-
-  public :
-
-    CAlignment1 ();
-    CAlignment1 ( RPCStream Object );
-    ~CAlignment1();
-
-    void SetAffineModel ( realtype WGap,   realtype WSpace  );
-    void SetScores      ( realtype SEqual, realtype SNEqual );
-
-    void Align          ( ivector S, int SLength,
-                          ivector T, int TLength,
-                          int Method=ALIGN_GLOBAL );
-
-    ivector  GetAlignedS   ()  { return AlgnS;     }
-    ivector  GetAlignedT   ()  { return AlgnT;     }
-    int      GetAlignLength()  { return AlgnLen;   }
-    realtype GetScore      ()  { return VAchieved; }
-
-    realtype GetSimilarity(); // Score-weighted sequence id
-
-    virtual void OutputResults ( RCFile f, ivector S, int lenS,
-                                           ivector T, int lenT );
-
-    void read   ( RCFile f );
-    void write  ( RCFile f );
-
-  protected :
-
-    int      Space;
-    int      AlignKey, SLen,TLen, AlgnLen;
-    rmatrix  VT,ET,FT;
-    ivector  AlgnS,AlgnT;
-    realtype VAchieved;
-    realtype SEq,SNEq, Wg,Ws;
-
-    virtual void  InitAlignment1();
-    virtual void  FreeMemory    ();
-    virtual realtype  Score     ( int A, int B );
-
-    void    BuildGATable ( ivector S, ivector T,
-                           Boolean FreeSEnds, Boolean FreeTEnds );
-    void    BuildLATable ( ivector S, ivector T );
-    void    Backtrace    ( ivector S, ivector T, int J, int I,
-                           Boolean StopAtZero );
-    void    AdjustEnds   ( ivector S, ivector T, int J, int I );
-    void    PrintVT      ( ivector S, ivector T );
-
-};
-
-
-#endif
diff --git a/mmdb/mmdb_atom.cpp b/mmdb/mmdb_atom.cpp
deleted file mode 100755
index b9c3285..0000000
--- a/mmdb/mmdb_atom.cpp
+++ /dev/null
@@ -1,3495 +0,0 @@
-//  $Id: mmdb_atom.cpp,v 1.31 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    23.04.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Atom  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CAtom    ( atom class    )
-//       ~~~~~~~~~  CResidue ( residue class )
-//
-//  Copyright (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __MMDB_Chain__
-#include "mmdb_chain.h"
-#endif
-
-#ifndef  __MMDB_Model__
-#include "mmdb_model.h"
-#endif
-
-#ifndef  __MMDB_File__
-#include "mmdb_file.h"
-#endif
-
-#ifndef  __MMDB_Tables__
-#include "mmdb_tables.h"
-#endif
-
-#ifndef  __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-#ifndef IOTBX_PDB_HYBRID_36_C_H
-#include "hybrid_36.h"
-#endif
-
-
-//  ================================================================
-
-#define  ASET_ShortBinary   0x10000000
-#define  ASET_ShortTer      0x20000000
-#define  ASET_ShortHet      0x40000000
-
-Boolean  ignoreSegID            = False;
-Boolean  ignoreElement          = False;
-Boolean  ignoreCharge           = False;
-Boolean  ignoreNonCoorPDBErrors = False;
-Boolean  ignoreUnmatch          = False;
-
-
-//  ==========================  CAtom  =============================
-
-CAtom::CAtom() : CUDData()  {
-  InitAtom();
-}
-
-CAtom::CAtom ( PCResidue res ) : CUDData()  {
-  InitAtom();
-  if (res)
-    res->AddAtom ( this );
-}
-
-CAtom::CAtom ( RPCStream Object ) : CUDData(Object)  {
-  InitAtom();
-}
-
-CAtom::~CAtom()  {
-int     nA;
-PPCAtom A;
-  FreeMemory();
-  if (residue)  {
-    A  = NULL;
-    nA = 0;
-    if (residue->chain)  {
-      if (residue->chain->model)  {
-        A  = residue->chain->model->GetAllAtoms();
-        nA = residue->chain->model->GetNumberOfAllAtoms();
-      }
-    }
-    residue->_ExcludeAtom ( index );
-    if ((0<index) && (index<=nA))  A[index-1] = NULL;
-  }
-}
-
-void  CAtom::InitAtom()  {
-  serNum     = -1;         // serial number
-  index      = -1;         // index in the file
-  name[0]    = char(0);    // atom name
-  label_atom_id[0] = char(0); // assigned atom name (not aligned)
-  altLoc[0]  = char(0);    // alternate location indicator
-  residue    = NULL;       // reference to residue
-  x          = 0.0;        // orthogonal x-coordinate in angstroms
-  y          = 0.0;        // orthogonal y-coordinate in angstroms
-  z          = 0.0;        // orthogonal z-coordinate in angstroms
-  occupancy  = 0.0;        // occupancy
-  tempFactor = 0.0;        // temperature factor
-  segID[0]   = char(0);    // segment identifier
-  strcpy ( element,"  " ); // chemical element symbol - RIGHT JUSTIFIED
-  energyType[0] = char(0); // chemical element symbol - RIGHT JUSTIFIED
-  charge     = 0.0;        // charge on the atom
-  sigX       = 0.0;        // standard deviation of the stored x-coord
-  sigY       = 0.0;        // standard deviation of the stored y-coord
-  sigZ       = 0.0;        // standard deviation of the stored z-coord
-  sigOcc     = 0.0;        // standard deviation of occupancy
-  sigTemp    = 0.0;        // standard deviation of temperature factor
-  u11        = 0.0;        //
-  u22        = 0.0;        // anisotropic
-  u33        = 0.0;        //
-  u12        = 0.0;        //    temperature
-  u13        = 0.0;        //
-  u23        = 0.0;        //        factors
-  su11       = 0.0;        //
-  su22       = 0.0;        // standard
-  su33       = 0.0;        //    deviations of
-  su12       = 0.0;        //       anisotropic
-  su13       = 0.0;        //          temperature
-  su23       = 0.0;        //             factors
-  Het        = False;      // indicator of atom in non-standard groups
-  Ter        = False;      // chain terminator
-  WhatIsSet  = 0x00000000; // nothing is set
-  nBonds     = 0;          // no bonds
-  Bond       = NULL;       // empty array of bonds
-}
-
-void  CAtom::FreeMemory()  {
-  FreeBonds();
-}
-
-void  CAtom::FreeBonds()  {
-  if (Bond)  delete[] Bond;
-  Bond   = NULL;
-  nBonds = 0;
-}
-
-int CAtom::GetNBonds()  {
-  return nBonds & 0x000000FF;
-}
-
-void CAtom::GetBonds ( RPSAtomBond AtomBond, int & nAtomBonds )  {
-//    This GetBonds(..) returns pointer to the CAtom's
-//  internal Bond structure, IT MUST NOT BE DISPOSED.
-  nAtomBonds = nBonds & 0x000000FF;
-  AtomBond   = Bond;
-}
-
-void CAtom::GetBonds ( RPSAtomBondI AtomBondI, int & nAtomBonds )  {
-//    This GetBonds(..) disposes AtomBondI, if it was not set
-//  to NULL, allocates AtomBondI[nAtomBonds] and returns its
-//  pointer. AtomBondI MUST BE DISPOSED BY APPLICATION.
-int i;
-
-  if (AtomBondI)  delete[] AtomBondI;
-
-  nAtomBonds = nBonds & 0x000000FF;
-
-  if (nAtomBonds<=0)
-    AtomBondI = NULL;
-  else  {
-    AtomBondI = new SAtomBondI[nAtomBonds];
-    for (i=0;i<nAtomBonds;i++) {
-      if (Bond[i].atom)
-            AtomBondI[i].index = Bond[i].atom->index;
-      else  AtomBondI[i].index = -1;
-      AtomBondI[i].order = Bond[i].order;
-    }
-
-  }
-
-}
-
-void CAtom::GetBonds ( PSAtomBondI AtomBondI, int & nAtomBonds,
-                       int maxlength )  {
-//    This GetBonds(..) does not dispose or allocate AtomBond.
-//  It is assumed that length of AtomBond is sufficient to
-//  accomodate all bonded atoms.
-int  i;
-
-  nAtomBonds = IMin(maxlength,nBonds & 0x000000FF);
-
-  for (i=0;i<nAtomBonds;i++)  {
-    if (Bond[i].atom)
-          AtomBondI[i].index = Bond[i].atom->index;
-    else  AtomBondI[i].index = -1;
-    AtomBondI[i].order = Bond[i].order;
-  }
-
-}
-
-
-int  CAtom::AddBond ( PCAtom bond_atom, int bond_order,
-                      int nAdd_bonds )  {
-PSAtomBond B1;
-int        i,k,nb,nballoc;
-
-  nb = nBonds & 0x000000FF;
-  k  = -1;
-  for (i=0;(i<nb) && (k<0);i++)
-    if (Bond[i].atom==bond_atom)  k = i;
-  if (k>=0)  return -k;
-
-  nballoc = (nBonds >> 8) & 0x000000FF;
-  if (nBonds>=nballoc)  {
-    nballoc += nAdd_bonds;
-    B1 = new SAtomBond[nballoc];
-    for (i=0;i<nb;i++)  {
-      B1[i].atom  = Bond[i].atom;
-      B1[i].order = Bond[i].order;
-    }
-    if (Bond)  delete[] Bond;
-    Bond = B1;
-  }
-  Bond[nb].atom  = bond_atom;
-  Bond[nb].order = bond_order;
-  nb++;
-
-  nBonds = nb | (nballoc << 8);
-
-  return nb;
-
-}
-
-void  CAtom::SetResidue ( PCResidue res )  {
-  residue = res;
-}
-
-void  CAtom::StandardPDBOut ( cpstr Record, pstr S )  {
-char N[10];
-  strcpy    ( S,Record );
-  PadSpaces ( S,80     );
-  if (serNum>99999)  {
-    hy36encode ( 5,serNum,N );
-    strcpy_n   ( &(S[6]),N,5 );
-  } else if (serNum>0)
-    PutInteger ( &(S[6]),serNum,5 );
-  else if (index<=99999)
-    PutInteger ( &(S[6]),index,5 );
-  else {
-    hy36encode ( 5,index,N );
-    strcpy_n   ( &(S[6]),N,5 );
-  }
-  if (!Ter)  {
-    if (altLoc[0])  S[16] = altLoc[0];
-    strcpy_n  ( &(S[12]),name   ,4 );
-    strcpy_n  ( &(S[72]),segID  ,4 );
-    strcpy_nr ( &(S[76]),element,2 );
-    if (WhatIsSet & ASET_Charge)  {
-      if (charge>0)       sprintf ( N,"%1i+",mround(charge)  );
-      else if (charge<0)  sprintf ( N,"%1i-",mround(-charge) );
-                    else  strcpy  ( N,"  " );
-      strcpy_n ( &(S[78]),N,2 );
-    } else
-      strcpy_n ( &(S[78]),"  ",2 );
-  }
-  strcpy_nr ( &(S[17]),residue->name,3 );
-  strcpy_nr ( &(S[20]),residue->chain->chainID,2 );
-  if (residue->seqNum>MinInt4)  {
-    if ((-999<=residue->seqNum) && (residue->seqNum<=9999))
-      PutIntIns  ( &(S[22]),residue->seqNum,4,residue->insCode );
-    else  {
-      hy36encode ( 4,residue->seqNum,N );
-      strcpy_n   ( &(S[22]),N,4 );
-    }
-  }
-}
-
-void  CAtom::PDBASCIIDump ( RCFile f )  {
-// makes the ASCII PDB  ATOM, HETATM, SIGATOM, ANISOU
-// SIGUIJ and TER lines from the class' data
-char S[100];
-  if (Ter)  {
-    if (WhatIsSet & ASET_Coordinates)  {
-      StandardPDBOut ( pstr("TER"),S );
-      f.WriteLine ( S );
-    }
-  } else  {
-    if (WhatIsSet & ASET_Coordinates)  {
-      if (Het)  StandardPDBOut ( pstr("HETATM"),S );
-          else  StandardPDBOut ( pstr("ATOM")  ,S );
-      PutRealF ( &(S[30]),x,8,3 );
-      PutRealF ( &(S[38]),y,8,3 );
-      PutRealF ( &(S[46]),z,8,3 );
-      if (WhatIsSet & ASET_Occupancy)
-        PutRealF ( &(S[54]),occupancy ,6,2 );
-      if (WhatIsSet & ASET_tempFactor)
-        PutRealF ( &(S[60]),tempFactor,6,2 );
-      f.WriteLine ( S );
-    }
-    if (WhatIsSet & ASET_CoordSigma)  {
-      StandardPDBOut ( pstr("SIGATM"),S );
-      PutRealF ( &(S[30]),sigX,8,3 );
-      PutRealF ( &(S[38]),sigY,8,3 );
-      PutRealF ( &(S[46]),sigZ,8,3 );
-      if ((WhatIsSet & ASET_OccSigma) &&
-          (WhatIsSet & ASET_Occupancy))
-        PutRealF ( &(S[54]),sigOcc,6,2 );
-      if ((WhatIsSet & ASET_tFacSigma) &&
-          (WhatIsSet & ASET_tempFactor))
-        PutRealF ( &(S[60]),sigTemp,6,2 );
-      f.WriteLine ( S );
-    }
-    if (WhatIsSet & ASET_Anis_tFac)  {
-      StandardPDBOut ( pstr("ANISOU"),S );
-      PutInteger  ( &(S[28]),mround(u11*1.0e4),7 );
-      PutInteger  ( &(S[35]),mround(u22*1.0e4),7 );
-      PutInteger  ( &(S[42]),mround(u33*1.0e4),7 );
-      PutInteger  ( &(S[49]),mround(u12*1.0e4),7 );
-      PutInteger  ( &(S[56]),mround(u13*1.0e4),7 );
-      PutInteger  ( &(S[63]),mround(u23*1.0e4),7 );
-      f.WriteLine ( S );
-      if (WhatIsSet & ASET_Anis_tFSigma)  {
-        StandardPDBOut ( pstr("SIGUIJ"),S );
-        PutInteger  ( &(S[28]),mround(su11*1.0e4),7 );
-        PutInteger  ( &(S[35]),mround(su22*1.0e4),7 );
-        PutInteger  ( &(S[42]),mround(su33*1.0e4),7 );
-        PutInteger  ( &(S[49]),mround(su12*1.0e4),7 );
-        PutInteger  ( &(S[56]),mround(su13*1.0e4),7 );
-        PutInteger  ( &(S[63]),mround(su23*1.0e4),7 );
-        f.WriteLine ( S );
-      }
-    }
-  }
-}
-
-void  CAtom::MakeCIF ( PCMMCIFData CIF )  {
-PCMMCIFLoop  Loop;
-AtomName     AtName;
-Element      el;
-char         N[10];
-int          i,j,RC;
-PCChain      chain       = NULL;
-PCModel      model       = NULL;
-//Boolean      singleModel = True;
-
-  if (residue)  chain = residue->chain;
-  if (chain)    model = PCModel(chain->model);
-//  if (model)  {
-//    if (model->manager)
-//      singleModel = PCMMDBFile(model->manager)->nModels<=1;
-//  }
-
-/*
-
-loop_
-*0  _atom_site.group_PDB
-*1  _atom_site.id
-*2  _atom_site.type_symbol         <- chem elem
--3  _atom_site.label_atom_id       <- atom name
-*4  _atom_site.label_alt_id        <- alt code
-=5  _atom_site.label_comp_id       <- res name ???
-=6  _atom_site.label_asym_id       <- chain id ???
-=7  _atom_site.label_entity_id     < ???
-=8  _atom_site.label_seq_id        <- poly seq id
-+9  _atom_site.pdbx_PDB_ins_code   <- ins code
--10 _atom_site.segment_id          <- segment id
-*11 _atom_site.Cartn_x
-*12 _atom_site.Cartn_y
-*13 _atom_site.Cartn_z
-*14 _atom_site.occupancy
-*15 _atom_site.B_iso_or_equiv
-*16 _atom_site.Cartn_x_esd
-*17 _atom_site.Cartn_y_esd
-*18 _atom_site.Cartn_z_esd
-*19 _atom_site.occupancy_esd
-*20 _atom_site.B_iso_or_equiv_esd
-*21 _atom_site.pdbx_formal_charge
-+22 _atom_site.auth_seq_id          <- seq id we want
-+23 _atom_site.auth_comp_id         <- res name we want
-+24 _atom_site.auth_asym_id         <- ch id we want ?
-*25 _atom_site.auth_atom_id         <- atom name we want ?
-+26 _atom_site.pdbx_PDB_model_num   <- model no
-
-'+' is read in CMMDBFile::CheckAtomPlace()
-'=' new in residue
-'-' new in atom
-
-
-*/
-
-  RC = CIF->AddLoop ( CIFCAT_ATOM_SITE,Loop );
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-
-    Loop->AddLoopTag ( CIFTAG_GROUP_PDB          ); // ATOM, TER etc.
-    Loop->AddLoopTag ( CIFTAG_ID                 ); // serial number
-
-    Loop->AddLoopTag ( CIFTAG_TYPE_SYMBOL        ); // element symbol
-    Loop->AddLoopTag ( CIFTAG_LABEL_ATOM_ID      ); // atom name
-    Loop->AddLoopTag ( CIFTAG_LABEL_ALT_ID       ); // alt location
-    Loop->AddLoopTag ( CIFTAG_LABEL_COMP_ID      ); // residue name
-    Loop->AddLoopTag ( CIFTAG_LABEL_ASYM_ID      ); // chain ID
-    Loop->AddLoopTag ( CIFTAG_LABEL_ENTITY_ID    ); // entity ID
-    Loop->AddLoopTag ( CIFTAG_LABEL_SEQ_ID       ); // res seq number
-    Loop->AddLoopTag ( CIFTAG_PDBX_PDB_INS_CODE  ); // insertion code
-    Loop->AddLoopTag ( CIFTAG_SEGMENT_ID         ); // segment ID
-
-    Loop->AddLoopTag ( CIFTAG_CARTN_X            ); // x-coordinate
-    Loop->AddLoopTag ( CIFTAG_CARTN_Y            ); // y-coordinate
-    Loop->AddLoopTag ( CIFTAG_CARTN_Z            ); // z-coordinate
-    Loop->AddLoopTag ( CIFTAG_OCCUPANCY          ); // occupancy
-    Loop->AddLoopTag ( CIFTAG_B_ISO_OR_EQUIV     ); // temp factor
-
-    Loop->AddLoopTag ( CIFTAG_CARTN_X_ESD        ); // x-sigma
-    Loop->AddLoopTag ( CIFTAG_CARTN_Y_ESD        ); // y-sigma
-    Loop->AddLoopTag ( CIFTAG_CARTN_Z_ESD        ); // z-sigma
-    Loop->AddLoopTag ( CIFTAG_OCCUPANCY_ESD      ); // occupancy-sigma
-    Loop->AddLoopTag ( CIFTAG_B_ISO_OR_EQUIV_ESD ); // t-factor-sigma
-
-    Loop->AddLoopTag ( CIFTAG_PDBX_FORMAL_CHARGE ); // charge on atom
-
-    Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID        ); // res seq number
-    Loop->AddLoopTag ( CIFTAG_AUTH_COMP_ID       ); // residue name
-    Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID       ); // chain id
-    Loop->AddLoopTag ( CIFTAG_AUTH_ATOM_ID       ); // atom name
-
-    Loop->AddLoopTag ( CIFTAG_PDBX_PDB_MODEL_NUM ); // model number
-
-  }
-
-  if (Ter)  {   // ter record
-
-    if (!(WhatIsSet & ASET_Coordinates))
-      return;
-
-    // (0)
-    Loop->AddString  ( pstr("TER") );
-    // (1)
-    if (serNum>0)  Loop->AddInteger ( serNum );
-             else  Loop->AddInteger ( index  );
-    // (2,3,4)
-    Loop->AddNoData ( CIF_NODATA_QUESTION );  // no element symbol
-    Loop->AddNoData ( CIF_NODATA_QUESTION );  // no atom name
-    Loop->AddNoData ( CIF_NODATA_QUESTION );  // no alt code
-    if (residue)  {
-      // (5)
-      Loop->AddString ( residue->label_comp_id );
-      // (6)
-      Loop->AddString ( residue->label_asym_id );
-      // (7)
-      if (residue->label_entity_id>0)
-           Loop->AddInteger ( residue->label_entity_id );
-      else Loop->AddNoData  ( CIF_NODATA_DOT           );
-      // (8)
-      if (residue->label_seq_id>MinInt4)
-           Loop->AddInteger ( residue->label_seq_id );
-      else Loop->AddNoData  ( CIF_NODATA_DOT        );
-      // (9)
-      Loop->AddString ( residue->insCode,True );
-    } else  {
-      // (5,6,7,8,9)
-      Loop->AddString ( NULL );
-      Loop->AddString ( NULL );
-      Loop->AddNoData ( CIF_NODATA_DOT );
-      Loop->AddNoData ( CIF_NODATA_DOT );
-      Loop->AddNoData ( CIF_NODATA_DOT );
-    }
-
-    // (10-21)
-    for (i=10;i<=21;i++)
-      Loop->AddNoData ( CIF_NODATA_QUESTION );
-
-    // (22,23)
-    if (residue)  {
-      if (residue->seqNum>MinInt4)
-           Loop->AddInteger ( residue->seqNum  );
-      else Loop->AddNoData  ( CIF_NODATA_DOT   );
-      Loop->AddString ( residue->name );
-    } else  {
-      Loop->AddNoData ( CIF_NODATA_DOT );
-      Loop->AddString ( NULL           );
-    }
-
-    // (24)
-    if (chain)  Loop->AddString ( chain->chainID,True );
-          else  Loop->AddString ( NULL                );
-
-    // (25)
-    Loop->AddNoData ( CIF_NODATA_QUESTION );  // no atom name
-
-  } else if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma))  {
-    // normal atom record
-
-    if (!WhatIsSet)  return;
-
-    // (0)
-    if (Het)  Loop->AddString ( pstr("HETATM") );
-        else  Loop->AddString ( pstr("ATOM")   );
-    // (1)
-    if (serNum>0)  Loop->AddInteger ( serNum );
-             else  Loop->AddInteger ( index  );
-
-
-    if (WhatIsSet & ASET_Coordinates)  {
-
-      // (2)
-      strcpy_css ( el,element );
-      Loop->AddString ( el,True );
-      // (3)
-      Loop->AddString ( label_atom_id  );  // assigned atom name
-      // (4)
-      Loop->AddString  ( altLoc,True );  // alt code
-
-      if (residue)  {
-        // (5)
-        Loop->AddString ( residue->label_comp_id );
-        // (6)
-        Loop->AddString ( residue->label_asym_id );
-        // (7)
-        if (residue->label_entity_id>0)
-             Loop->AddInteger ( residue->label_entity_id );
-        else Loop->AddNoData  ( CIF_NODATA_DOT           );
-        // (8)
-        if (residue->label_seq_id>MinInt4)
-             Loop->AddInteger ( residue->label_seq_id );
-        else Loop->AddNoData  ( CIF_NODATA_DOT        );
-        // (9)
-        Loop->AddString ( residue->insCode,True );
-      } else  {
-        // (5,6,7,8,9)
-        Loop->AddString ( NULL );
-        Loop->AddString ( NULL );
-        Loop->AddNoData ( CIF_NODATA_DOT );
-        Loop->AddNoData ( CIF_NODATA_DOT );
-        Loop->AddNoData ( CIF_NODATA_DOT );
-      }
-
-      // (10)
-      Loop->AddString ( segID ,True );
-      // (11,12,13)
-      Loop->AddReal ( x );
-      Loop->AddReal ( y );
-      Loop->AddReal ( z );
-      // (14)
-      if (WhatIsSet & ASET_Occupancy)
-            Loop->AddReal   ( occupancy );
-      else  Loop->AddNoData ( CIF_NODATA_QUESTION );
-      // (15)
-      if (WhatIsSet & ASET_tempFactor)
-            Loop->AddReal   ( tempFactor );
-      else  Loop->AddNoData ( CIF_NODATA_QUESTION );
-
-      // (16,17,18)
-      if (WhatIsSet & ASET_CoordSigma)  {
-        Loop->AddReal ( sigX );
-        Loop->AddReal ( sigY );
-        Loop->AddReal ( sigZ );
-      } else  {
-        Loop->AddNoData ( CIF_NODATA_QUESTION );
-        Loop->AddNoData ( CIF_NODATA_QUESTION );
-        Loop->AddNoData ( CIF_NODATA_QUESTION );
-      }
-      // (19)
-      if ((WhatIsSet & ASET_OccSigma) && (WhatIsSet & ASET_Occupancy))
-            Loop->AddReal   ( sigOcc  );
-      else  Loop->AddNoData ( CIF_NODATA_QUESTION );
-      // (20)
-      if ((WhatIsSet & ASET_tFacSigma) && (WhatIsSet & ASET_tempFactor))
-            Loop->AddReal   ( sigTemp );
-      else  Loop->AddNoData ( CIF_NODATA_QUESTION );
-
-    } else
-      for (i=0;i<18;i++)
-        Loop->AddNoData ( CIF_NODATA_QUESTION );
-
-    // (21)
-    if (WhatIsSet & ASET_Charge)  {
-      sprintf ( N,"%+2i",mround(charge) );
-      Loop->AddString ( N,True );
-    } else
-      Loop->AddNoData ( CIF_NODATA_QUESTION );
-
-    if (residue)  {
-      // (22)
-      if (residue->seqNum>MinInt4)
-           Loop->AddInteger ( residue->seqNum  );
-      else Loop->AddNoData  ( CIF_NODATA_DOT   );
-      // (23)
-      Loop->AddString ( residue->name );
-    } else  {
-      Loop->AddNoData ( CIF_NODATA_DOT );
-      Loop->AddNoData ( CIF_NODATA_DOT );
-    }
-
-    // (24)
-    if (chain)  Loop->AddString ( chain->chainID,True );
-          else  Loop->AddNoData ( CIF_NODATA_DOT      );
-    // (25)
-    strcpy_css      ( AtName,name );
-    Loop->AddString ( AtName      );  // atom name
-
-  }
-
-  // (26)
-  if (!model)                Loop->AddNoData  ( CIF_NODATA_QUESTION );
-  else if (model->serNum>0)  Loop->AddInteger ( model->serNum       );
-                       else  Loop->AddNoData  ( CIF_NODATA_QUESTION );
-
-
-  if (WhatIsSet & ASET_Anis_tFac)  {
-
-    RC = CIF->AddLoop ( CIFCAT_ATOM_SITE_ANISOTROP,Loop );
-    if (RC!=CIFRC_Ok)  {
-      // the category was (re)created, provide tags
-      Loop->AddLoopTag ( CIFTAG_ID      ); // serial number
-      Loop->AddLoopTag ( CIFTAG_U11     ); // component u11
-      Loop->AddLoopTag ( CIFTAG_U22     ); // component u22
-      Loop->AddLoopTag ( CIFTAG_U33     ); // component u33
-      Loop->AddLoopTag ( CIFTAG_U12     ); // component u12
-      Loop->AddLoopTag ( CIFTAG_U13     ); // component u13
-      Loop->AddLoopTag ( CIFTAG_U23     ); // component u23
-      Loop->AddLoopTag ( CIFTAG_U11_ESD ); // component u11 sigma
-      Loop->AddLoopTag ( CIFTAG_U22_ESD ); // component u22 sigma
-      Loop->AddLoopTag ( CIFTAG_U33_ESD ); // component u33 sigma
-      Loop->AddLoopTag ( CIFTAG_U12_ESD ); // component u12 sigma
-      Loop->AddLoopTag ( CIFTAG_U13_ESD ); // component u13 sigma
-      Loop->AddLoopTag ( CIFTAG_U23_ESD ); // component u23 sigma
-      for (i=1;i<index;i++)  {
-        Loop->AddInteger ( i );
-        for (j=0;j<12;j++)
-          Loop->AddString ( NULL );
-      }
-    }
-
-    if (serNum>0)  Loop->AddInteger ( serNum );
-             else  Loop->AddInteger ( index  );
-
-    Loop->AddReal ( u11 );
-    Loop->AddReal ( u22 );
-    Loop->AddReal ( u33 );
-    Loop->AddReal ( u12 );
-    Loop->AddReal ( u13 );
-    Loop->AddReal ( u23 );
-    if (WhatIsSet & ASET_Anis_tFSigma)  {
-      Loop->AddReal ( su11 );
-      Loop->AddReal ( su22 );
-      Loop->AddReal ( su33 );
-      Loop->AddReal ( su12 );
-      Loop->AddReal ( su13 );
-      Loop->AddReal ( su23 );
-    }
-
-  }
-
-}
-
-int CAtom::ConvertPDBATOM ( int ix, cpstr S )  {
-//   Gets data from the PDB ASCII ATOM record.
-//   This function DOES NOT check the "ATOM" keyword and
-// does not decode the chain and residue parameters! These
-// must be treated by calling process, see
-// Chain::ConvertPDBASCII().
-
-  index = ix;
-
-  if (WhatIsSet & ASET_Coordinates)
-    return Error_ATOM_AlreadySet;
-
-  if (!(GetReal(x,&(S[30]),8) &&
-        GetReal(y,&(S[38]),8) &&
-        GetReal(z,&(S[46]),8)))
-    return Error_ATOM_Unrecognized;
-
-  WhatIsSet |= ASET_Coordinates;
-  Het = False;
-  Ter = False;
-
-  if (GetReal(occupancy ,&(S[54]),6))  WhatIsSet |= ASET_Occupancy;
-  if (GetReal(tempFactor,&(S[60]),6))  WhatIsSet |= ASET_tempFactor;
-
-  if (WhatIsSet & (ASET_CoordSigma | ASET_Anis_tFac |
-                   ASET_Anis_tFSigma))
-    // something was already submitted. check complience
-    return CheckData ( S );
-  else
-    // first data submission. just take the data
-    GetData ( S );
-
-  return 0;
-
-}
-
-void  CAtom::SetAtomName ( int            ix,
-                           int            sN,
-                           const AtomName aName,
-                           const AltLoc   aLoc,
-                           const SegID    sID,
-                           const Element  eName )  {
-  index   = ix;
-  serNum  = sN;
-  strcpy     ( name         ,aName      );
-  strcpy     ( label_atom_id,aName      );
-  strcpy_css ( altLoc       ,pstr(aLoc) );
-  strcpy_css ( segID        ,pstr(sID)  );
-  if (!eName[0])  element[0] = char(0);
-  else if (!eName[1])  {
-    element[0] = ' ';
-    strcpy ( &(element[1]),eName );
-  } else
-    strcpy   ( element,eName );
-  WhatIsSet = 0;
-}
-
-int CAtom::ConvertPDBSIGATM ( int ix, cpstr S )  {
-//   Gets data from the PDB ASCII SIGATM record.
-//   This function DOES NOT check the "SIGATM" keyword and
-// does not decode the chain and residue parameters! These
-// must be treated by the calling process, see
-// Chain::ConvertPDBASCII().
-
-  index = ix;
-
-  if (WhatIsSet & ASET_CoordSigma)
-    return Error_ATOM_AlreadySet;
-
-  if (!(GetReal(sigX,&(S[30]),8) &&
-        GetReal(sigY,&(S[38]),8) &&
-        GetReal(sigZ,&(S[46]),8)))
-    return Error_ATOM_Unrecognized;
-
-  WhatIsSet |= ASET_CoordSigma;
-
-  if (GetReal(sigOcc ,&(S[54]),6))  WhatIsSet |= ASET_OccSigma;
-  if (GetReal(sigTemp,&(S[60]),6))  WhatIsSet |= ASET_tFacSigma;
-
-  if (WhatIsSet & (ASET_Coordinates | ASET_Anis_tFac |
-                   ASET_Anis_tFSigma))
-    // something was already submitted. check complience
-    return CheckData ( S );
-  else
-    // first data submission. just take the data
-    GetData ( S );
-
-  return 0;
-
-}
-
-int CAtom::ConvertPDBANISOU ( int ix, cpstr S )  {
-//   Gets data from the PDB ASCII ANISOU record.
-//   This function DOES NOT check the "ANISOU" keyword and
-// does not decode chain and residue parameters! These must
-// be treated by the calling process, see
-// Chain::ConvertPDBASCII().
-
-  index = ix;
-
-  if (WhatIsSet & ASET_Anis_tFac)
-    return Error_ATOM_AlreadySet;
-
-  if (!(GetReal(u11,&(S[28]),7) &&
-        GetReal(u22,&(S[35]),7) &&
-        GetReal(u33,&(S[42]),7) &&
-        GetReal(u12,&(S[49]),7) &&
-        GetReal(u13,&(S[56]),7) &&
-        GetReal(u23,&(S[63]),7)))
-    return Error_ATOM_Unrecognized;
-
-  u11 /= 1.0e4;
-  u22 /= 1.0e4;
-  u33 /= 1.0e4;
-  u12 /= 1.0e4;
-  u13 /= 1.0e4;
-  u23 /= 1.0e4;
-
-  WhatIsSet |= ASET_Anis_tFac;
-
-  if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma |
-                   ASET_Anis_tFSigma))
-    // something was already submitted. check complience
-    return CheckData ( S );
-  else
-    // first data submission. just take the data
-    GetData ( S );
-
-  return 0;
-
-}
-
-int CAtom::ConvertPDBSIGUIJ ( int ix, cpstr S )  {
-//   Gets data from the PDB ASCII SIGUIJ record.
-//   This function DOES NOT check the "SIGUIJ" keyword and
-// does not decode the chain and residue parameters! These
-// must be treated by the calling process, see
-// Chain::ConvertPDBASCII().
-
-  index = ix;
-
-  if (WhatIsSet & ASET_Anis_tFSigma)
-    return Error_ATOM_AlreadySet;
-
-  if (!(GetReal(su11,&(S[28]),7) &&
-        GetReal(su22,&(S[35]),7) &&
-        GetReal(su33,&(S[42]),7) &&
-        GetReal(su12,&(S[49]),7) &&
-        GetReal(su13,&(S[56]),7) &&
-        GetReal(su23,&(S[63]),7)))
-    return Error_ATOM_Unrecognized;
-
-  su11 /= 1.0e4;
-  su22 /= 1.0e4;
-  su33 /= 1.0e4;
-  su12 /= 1.0e4;
-  su13 /= 1.0e4;
-  su23 /= 1.0e4;
-
-  WhatIsSet |= ASET_Anis_tFSigma;
-
-  if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma |
-                   ASET_Anis_tFac))
-    // something was already submitted. check complience
-    return CheckData ( S );
-  else
-    // first data submission. just take the data
-    GetData ( S );
-
-  return 0;
-
-}
-
-int CAtom::ConvertPDBTER ( int ix, cpstr S )  {
-//   Gets data from the PDB ASCII TER record.
-//   This function DOES NOT check the "TER" keyword and
-// does not decode the chain and residue parameters! These
-// must be treated by the calling process, see
-// Chain::ConvertPDBASCII().
-
-  index = ix;
-
-  if (((S[6]>='0') && (S[6]<='9')) || (S[6]==' '))  {
-    //   Although against strict PDB format, 'TER' is
-    // actually allowed not to have a serial number.
-    // This negative value implies that the number is
-    // not set.
-    if (!(GetInteger(serNum,&(S[6]),5)))  serNum = -1;
-  } else
-    hy36decode ( 5,&(S[6]),5,&serNum );
-
-//  if (!(GetInteger(serNum,&(S[6]),5)))  serNum = -1;
-
-  if (WhatIsSet & ASET_Coordinates)
-    return Error_ATOM_AlreadySet;
-
-  WhatIsSet       |= ASET_Coordinates;
-  Het              = False;
-  Ter              = True;
-  name[0]          = char(0);
-  label_atom_id[0] = char(0);
-  element[0]       = char(0);
-
-  return 0;
-
-}
-
-
-int CAtom::GetModelNum()  {
-  if (residue) {
-    if (residue->chain)
-      if (residue->chain->model)
-        return residue->chain->model->GetSerNum();
-  }
-  return 0;
-}
-
-pstr CAtom::GetChainID()  {
-  if (residue) {
-    if (residue->chain)  return residue->chain->chainID;
-  }
-  return  pstr("");
-}
-
-pstr CAtom::GetLabelAsymID()  {
-  if (residue)  return residue->label_asym_id;
-          else  return pstr("");
-}
-
-pstr  CAtom::GetResName()  {
-  if (residue)  return residue->name;
-          else  return pstr("");
-}
-
-pstr  CAtom::GetLabelCompID()  {
-  if (residue)  return residue->label_comp_id;
-          else  return pstr("");
-}
-
-int   CAtom::GetAASimilarity ( const ResName resName )  {
-  if (residue)  return  ::GetAASimilarity ( pstr(residue->name),
-                                            pstr(resName) );
-          else  return -3;
-}
-
-int   CAtom::GetAASimilarity ( PCAtom A )  {
-  if (residue)  {
-    if (A->residue)
-          return ::GetAASimilarity ( pstr(residue->name),
-                                     pstr(A->residue->name) );
-    else  return -4;
-  } else
-    return -3;
-}
-
-realtype CAtom::GetAAHydropathy()  {
-  if (residue)  return  ::GetAAHydropathy ( pstr(residue->name) );
-          else  return  MaxReal;
-}
-
-realtype CAtom::GetOccupancy()  {
-  if (WhatIsSet & ASET_Occupancy)  return occupancy;
-                             else  return 0.0;
-}
-
-int   CAtom::GetSeqNum()  {
-  if (residue)  return residue->seqNum;
-          else  return ATOM_NoSeqNum;
-}
-
-int   CAtom::GetLabelSeqID()  {
-  if (residue)  return residue->label_seq_id;
-          else  return ATOM_NoSeqNum;
-}
-
-int   CAtom::GetLabelEntityID()  {
-  if (residue)  return residue->label_entity_id;
-          else  return -1;
-}
-
-pstr  CAtom::GetInsCode()  {
-  if (residue)  return residue->insCode;
-          else  return pstr("");
-}
-
-int   CAtom::GetSSEType()  {
-// works only after SSE calculations
-  if (residue)  return residue->SSE;
-          else  return SSE_None;
-}
-
-pstr  CAtom::GetAtomCharge ( pstr chrg )  {
-  if (WhatIsSet & ASET_Charge)  sprintf ( chrg,"%+2i",mround(charge) );
-                          else  strcpy  ( chrg,"  " );
-  return chrg;
-}
-
-PCResidue CAtom::GetResidue()  {
-  return residue;
-}
-
-PCChain  CAtom::GetChain()  {
-  if (residue)  return residue->chain;
-          else  return NULL;
-}
-
-PCModel  CAtom::GetModel()  {
-  if (residue)  {
-    if (residue->chain)  return (PCModel)residue->chain->model;
-  }
-  return NULL;
-}
-
-int  CAtom::GetResidueNo()  {
-  if (residue)  {
-    if (residue->chain)
-         return  residue->chain->GetResidueNo (
-                          residue->seqNum,residue->insCode );
-    else  return -2;
-  } else
-    return -1;
-}
-
-
-void * CAtom::GetCoordHierarchy()  {
-  if (residue)  return residue->GetCoordHierarchy();
-  return NULL;
-}
-
-
-void  CAtom::GetStat ( realtype   v,
-                       realtype & v_min, realtype & v_max,
-                       realtype & v_m,   realtype & v_m2 )  {
-  if (v<v_min)  v_min = v;
-  if (v>v_max)  v_max = v;
-  v_m  += v;
-  v_m2 += v*v;
-}
-
-
-
-void  CAtom::GetChainCalphas ( PPCAtom & Calphas, int & nCalphas,
-                               cpstr altLoc )  {
-//   GetChainCalphas(...) is a specialized function for quick
-// access to C-alphas of chain which includes given atom.
-// This function works faster than an equivalent implementation
-// through MMDB's selection procedures.
-//    Parameters:
-//       Calphas   - array to accept pointers on C-alpha atoms
-//                  If Calphas!=NULL, then the function will
-//                  delete and re-allocate it. When the array
-//                  is no longer needed, the application MUST
-//                  delete it:  delete[] Calphas; Deleting
-//                  Calphas does not delete atoms from MMDB.
-//       nCalphas   - integer to accept number of C-alpha atoms
-//                  and the length of Calphas array.
-//       altLoc     - alternative location indicator. By default
-//                  (""), maximum-occupancy locations are taken.
-PCChain    chain;
-PPCResidue res;
-PPCAtom    atom;
-int        nResidues, nAtoms, i,j,k;
-
-  if (Calphas)  {
-    delete[] Calphas;
-    Calphas = NULL;
-  }
-  nCalphas = 0;
-
-  if (residue)  chain = residue->chain;
-          else  chain = NULL;
-
-  if (chain)  {
-
-    chain->GetResidueTable ( res,nResidues );
-
-    if (nResidues>0)  {
-
-      Calphas = new PCAtom[nResidues];
-
-      if ((!altLoc[0]) || (altLoc[0]==' '))  {  // main conformation
-
-        for (i=0;i<nResidues;i++)  {
-          nAtoms = res[i]->nAtoms;
-          atom   = res[i]->atom;
-          for (j=0;j<nAtoms;j++)
-            if (!strcmp(atom[j]->name," CA "))  {
-              Calphas[nCalphas++] = atom[j];
-              break;
-            }
-        }
-
-      } else  {  // specific conformation
-
-        for (i=0;i<nResidues;i++)  {
-          nAtoms = res[i]->nAtoms;
-          atom   = res[i]->atom;
-          k      = 0;
-          for (j=0;j<nAtoms;j++)
-            if (!strcmp(atom[j]->name," CA "))  {
-              k = 1;
-              if (!atom[j]->altLoc[0])  {
-                // take main conformation now as we do not know if
-                // the specific one is in the file
-                Calphas[nCalphas] = atom[j];
-                k = 2;
-              } else if (atom[j]->altLoc[0]==altLoc[0])  {
-                // get specific conformation and quit
-                Calphas[nCalphas] = atom[j];
-                k = 2;
-                break;
-              }
-            } else if (k)
-              break;
-          if (k==2)  nCalphas++;
-        }
-
-      }
-
-    }
-
-  } else if (residue)  {  // check just this atom's residue
-
-    Calphas = new PCAtom[1]; // can't be more than 1 C-alpha!
-
-    nAtoms = residue->nAtoms;
-    atom   = residue->atom;
-
-    if ((!altLoc[0]) || (altLoc[0]==' '))  {  // main conformation
-
-      for (j=0;j<nAtoms;j++)
-        if (!strcmp(atom[j]->name," CA "))  {
-          Calphas[nCalphas++] = atom[j];
-          break;
-        }
-
-    } else  {  // specific conformation
-
-      k = 0;
-      for (j=0;j<nAtoms;j++)
-        if (!strcmp(atom[j]->name," CA "))  {
-          k = 1;
-          if (!atom[j]->altLoc[0])  {
-            Calphas[nCalphas] = atom[j];
-            k = 2;
-          } else if (atom[j]->altLoc[0]==altLoc[0])  {
-            Calphas[nCalphas] = atom[j];
-            k = 2;
-            break;
-          }
-        } else if (k)
-          break;
-      if (k==2)  nCalphas++;
-
-    }
-
-  }
-
-  if (Calphas && (!nCalphas))  {
-    delete[] Calphas;
-    Calphas = NULL;
-  }
-
-}
-
-Boolean CAtom::isMetal()  {
-  return  ::isMetal ( element );
-}
-
-Boolean CAtom::isSolvent()  {
-  if (residue)  return  residue->isSolvent();
-  return False;
-}
-
-Boolean CAtom::isInSelection ( int selHnd )  {
-PCMMDBFile manager = (PCMMDBFile)GetCoordHierarchy();
-PCMask     Mask;
-  if (manager)  {
-    Mask = manager->GetSelMask ( selHnd );
-    if (Mask)  return CheckMask ( Mask );
-  }
-  return False;
-}
-
-Boolean CAtom::isNTerminus()  {
-  if (residue)  return  residue->isNTerminus();
-  return False;
-}
-
-Boolean CAtom::isCTerminus()  {
-  if (residue)  return  residue->isCTerminus();
-  return False;
-}
-
-void  CAtom::CalcAtomStatistics ( RSAtomStat AS )  {
-//   AS must be initialized. The function only accumulates
-// the statistics.
-
-  if (!Ter)  {
-
-    AS.nAtoms++;
-
-    if (AS.WhatIsSet & WhatIsSet & ASET_Coordinates)  {
-      GetStat ( x,AS.xmin,AS.xmax,AS.xm,AS.xm2 );
-      GetStat ( y,AS.ymin,AS.ymax,AS.ym,AS.ym2 );
-      GetStat ( z,AS.zmin,AS.zmax,AS.zm,AS.zm2 );
-    } else
-      AS.WhatIsSet &= ~ASET_Coordinates;
-
-    if (AS.WhatIsSet & WhatIsSet & ASET_Occupancy)
-          GetStat(occupancy,AS.occ_min,AS.occ_max,AS.occ_m,AS.occ_m2);
-    else  AS.WhatIsSet &= ~ASET_Occupancy;
-
-    if (AS.WhatIsSet & WhatIsSet & ASET_tempFactor)
-          GetStat ( tempFactor,AS.tFmin,AS.tFmax,AS.tFm,AS.tFm2 );
-    else  AS.WhatIsSet &= ~ASET_tempFactor;
-
-    if (AS.WhatIsSet & WhatIsSet & ASET_Anis_tFac)  {
-      GetStat ( u11,AS.u11_min,AS.u11_max,AS.u11_m,AS.u11_m2 );
-      GetStat ( u22,AS.u22_min,AS.u22_max,AS.u22_m,AS.u22_m2 );
-      GetStat ( u33,AS.u33_min,AS.u33_max,AS.u33_m,AS.u33_m2 );
-      GetStat ( u12,AS.u12_min,AS.u12_max,AS.u12_m,AS.u12_m2 );
-      GetStat ( u13,AS.u13_min,AS.u13_max,AS.u13_m,AS.u13_m2 );
-      GetStat ( u23,AS.u23_min,AS.u23_max,AS.u23_m,AS.u23_m2 );
-    } else
-      AS.WhatIsSet &= ~ASET_Anis_tFac;
-
-  }
-
-}
-
-
-realtype CAtom::GetDist2 ( PCAtom a )  {
-realtype dx,dy,dz;
-  dx = a->x - x;
-  dy = a->y - y;
-  dz = a->z - z;
-  return  dx*dx + dy*dy + dz*dz;
-}
-
-realtype CAtom::GetDist2 ( PCAtom a, mat44 & tm )  {
-realtype dx,dy,dz;
-  dx = tm[0][0]*a->x + tm[0][1]*a->y + tm[0][2]*a->z + tm[0][3] - x;
-  dy = tm[1][0]*a->x + tm[1][1]*a->y + tm[1][2]*a->z + tm[1][3] - y;
-  dz = tm[2][0]*a->x + tm[2][1]*a->y + tm[2][2]*a->z + tm[2][3] - z;
-  return  dx*dx + dy*dy + dz*dz;
-}
-
-realtype CAtom::GetDist2 ( PCAtom a, mat33 & r, vect3 & t )  {
-realtype dx,dy,dz;
-  dx = r[0][0]*a->x + r[0][1]*a->y + r[0][2]*a->z + t[0] - x;
-  dy = r[1][0]*a->x + r[1][1]*a->y + r[1][2]*a->z + t[1] - y;
-  dz = r[2][0]*a->x + r[2][1]*a->y + r[2][2]*a->z + t[2] - z;
-  return  dx*dx + dy*dy + dz*dz;
-}
-
-realtype CAtom::GetDist2 ( realtype ax, realtype ay, realtype az )  {
-realtype dx,dy,dz;
-  dx = ax - x;
-  dy = ay - y;
-  dz = az - z;
-  return  dx*dx + dy*dy + dz*dz;
-}
-
-realtype CAtom::GetCosine ( PCAtom a1, PCAtom a2 )  {
-// Calculates cosing of angle a1-this-a2, i.e. that between
-// bond [a1,this] and [this,a2].
-realtype dx1,dy1,dz1, dx2,dy2,dz2,r;
-
-  dx1 = a1->x - x;
-  dy1 = a1->y - y;
-  dz1 = a1->z - z;
-  r   = dx1*dx1 + dy1*dy1 + dz1*dz1;
-
-  dx2 = a2->x - x;
-  dy2 = a2->y - y;
-  dz2 = a2->z - z;
-  r  *= dx2*dx2 + dy2*dy2 + dz2*dz2;
-
-  if (r>0.0)  return (dx1*dx2 + dy1*dy2 + dz1*dz2)/sqrt(r);
-        else  return 0.0;
-
-}
-
-
-void  CAtom::MakeTer()  {
-  WhatIsSet |= ASET_Coordinates;
-  Het        = False;
-  Ter        = True;
-}
-
-
-void  CAtom::SetAtomName ( const AtomName atomName )  {
-  strcpy ( name,atomName );
-}
-
-
-void  CAtom::SetElementName ( const Element elName )  {
-  strcpy ( element,elName );
-  if (!element[0])  strcpy ( element,"  " );
-  else if ((!element[1]) || (element[1]==' '))  {
-    element[2] = char(0);
-    element[1] = element[0];
-    element[0] = ' ';
-  }
-}
-
-void  CAtom::SetCharge ( cpstr chrg )  {
-pstr p;
-  charge = strtod ( chrg,&p );
-  if (p!=chrg)  {
-    WhatIsSet |= ASET_Charge;
-    if ((charge>0.0) && (*p=='-'))
-      charge = -charge;
-  }
-}
-
-void  CAtom::SetCharge ( realtype chrg )  {
-  if (chrg<MaxReal)  {
-    charge = chrg;
-    WhatIsSet |= ASET_Charge;
-  }
-}
-
-void  CAtom::SetAtomIndex ( int ix )  {
-// don't use in your applications!
-  index = ix;
-}
-
-pstr  CAtom::GetAtomID ( pstr AtomID )  {
-char  S[50];
-  AtomID[0] = char(0);
-  if (residue)  {
-    if (residue->chain)  {
-      if (residue->chain->model)
-            sprintf (AtomID,"/%i/",residue->chain->model->GetSerNum());
-      else  strcpy  ( AtomID,"/-/" );
-      strcat ( AtomID,residue->chain->chainID );
-    } else
-      strcpy ( AtomID,"/-/-" );
-    ParamStr ( AtomID,pstr("/"),residue->seqNum );
-    if (residue->name[0])  {
-      strcat ( AtomID,"(" );
-      strcat ( AtomID,residue->name );
-      strcat ( AtomID,")" );
-    }
-    if (residue->insCode[0])  {
-      strcat ( AtomID,"." );
-      strcat ( AtomID,residue->insCode );
-    }
-    strcat ( AtomID,"/" );
-  } else
-    strcpy ( AtomID,"/-/-/-/" );
-  strcpy_css ( S,name );
-  if (!S[0])  strcpy ( S,"-" );
-  strcat     ( AtomID,S );
-  strcpy_css ( S,element );
-  if (S[0])  {
-    strcat ( AtomID,"[" );
-    strcat ( AtomID,S   );
-    strcat ( AtomID,"]" );
-  }
-  if (altLoc[0])  {
-    strcat ( AtomID,":" );
-    strcat ( AtomID,altLoc );
-  }
-  return AtomID;
-}
-
-pstr  CAtom::GetAtomIDfmt ( pstr AtomID )  {
-int  n;
-char S[50];
-  AtomID[0] = char(0);
-  if (residue)  {
-    if (residue->chain)  {
-      if (residue->chain->model)  {
-        n = residue->chain->model->GetNumberOfModels();
-    if      (n<10)   strcpy ( S,"/%1i/" );
-    else if (n<100)  strcpy ( S,"/%2i/" );
-    else if (n<1000) strcpy ( S,"/%3i/" );
-                    else strcpy ( S,"/%i/"  );
-        sprintf ( AtomID,S,residue->chain->model->GetSerNum() );
-      } else
-        strcpy  ( AtomID,"/-/" );
-      strcat ( AtomID,residue->chain->chainID );
-    } else
-      strcpy ( AtomID,"/-/-" );
-    if ((-999<=residue->seqNum) && (residue->seqNum<=9999))
-          sprintf ( S,"/%4i",residue->seqNum );
-    else  sprintf ( S,"/%i" ,residue->seqNum );
-    strcat  ( AtomID,S );
-    sprintf ( S,"(%3s).%1s/",residue->name,residue->insCode );
-    strcat  ( AtomID,S );
-  } else
-    strcpy ( AtomID,"/-/-/----(---).-/" );
-  sprintf ( S,"%4s[%2s]:%1s",name,element,altLoc );
-  strcat  ( AtomID,S );
-  return AtomID;
-}
-
-
-
-int CAtom::ConvertPDBHETATM ( int ix, cpstr S )  {
-//   Gets data from the PDB ASCII HETATM record.
-//   This function DOES NOT check the "HETATM" keyword and
-// does not decode the chain and residue parameters! These
-// must be treated by the calling process, see
-// Chain::ConvertPDBASCII().
-int RC;
-  RC  = ConvertPDBATOM ( ix,S );
-  Het = True;
-  return RC;
-}
-
-void CAtom::GetData ( cpstr S )  {
-pstr p;
-
-  if (((S[6]>='0') && (S[6]<='9')) || (S[6]==' '))  {
-    //   Here we forgive cards with unreadable serial numbers
-    // as we always have index (ix) for the card. For the sake
-    // of strict PDB syntax we would have to return
-    // Error_UnrecognizedInteger here.
-    if (!(GetInteger(serNum,&(S[6]),5)))  serNum = -1;
-  } else
-    hy36decode ( 5,&(S[6]),5,&serNum );
-
-//  if (!(GetInteger(serNum,&(S[6]),5)))  serNum = index;
-
-  altLoc[0] = S[16];
-  if (altLoc[0]==' ')  altLoc[0] = char(0);
-                 else  altLoc[1] = char(0);
-  GetString   ( name   ,&(S[12]),4 );
-  strcpy_ncss ( segID  ,&(S[72]),4 );
-  GetString   ( element,&(S[76]),2 );
-  charge = strtod ( &(S[78]),&p );
-  if ((charge!=0.0) && (p!=&(S[78])))  {
-    WhatIsSet |= ASET_Charge;
-    if ((charge>0.0) && (*p=='-'))
-      charge = -charge;
-  }
-
-  RestoreElementName();
-  strcpy ( label_atom_id,name );
-
-}
-
-int  CAtom::CheckData ( cpstr S )  {
-int      sN;
-AltLoc   aloc;
-SegID    sID;
-Element  elmnt;
-pstr     p;
-realtype achrg;
-
-  aloc[0] = S[16];
-  if (aloc[0]==' ')  aloc[0] = char(0);
-               else  aloc[1] = char(0);
-
-  strcpy_ncss ( sID  ,&(S[72]),4 );
-  GetString   ( elmnt,&(S[76]),2 );
-
-  if (ignoreCharge)
-    achrg = charge;
-  else  {
-    achrg = strtod ( &(S[78]),&p );
-    if ((achrg!=0.0) && (p!=&(S[78])))  {
-      if ((achrg>0.0) && (*p=='-'))
-        achrg = -achrg;
-    }
-  }
-
-//  if (!(GetInteger(sN,&(S[6]),5)))
-//    sN = index;
-
-  if (hy36decode(5,&(S[6]),5,&sN))
-    sN = index;
-
-  if (ignoreSegID)  {
-    if (segID[0])  strcpy ( sID,segID );
-             else  strcpy ( segID,sID );
-  }
-
-  if (ignoreElement)  {
-    if (element[0])  strcpy ( elmnt,element );
-               else  strcpy ( element,elmnt );
-  }
-
-  if (ignoreUnmatch)  return 0;
-
-  //   Here we forgive cards with unreadable serial numbers
-  // as we always have index (ix) for the card. For the sake
-  // of strict PDB syntax we would have to return
-  // Error_UnrecognizedInteger .
-  if ((sN!=serNum)                  ||
-      (strcmp (altLoc ,aloc      )) ||
-      (strncmp(name   ,&(S[12]),4)) ||
-      (strcmp (segID  ,sID       )) ||
-      (strcmp (element,elmnt     )) ||
-      (charge!=achrg))  {
-    /*
-char name1[100];
-strncpy ( name1,&(S[12]),4 );  name1[4] = char(0);
-    printf ( "\n  serNum   %5i  %5i\n"
-             "  residue  '%s' '%s'\n"
-             "  altLoc   '%s' '%s'\n"
-             "  name     '%s' '%s'\n"
-             "  segId    '%s' '%s'\n"
-             "  element  '%s' '%s'\n"
-             "  charge   '%s' '%s'\n",
-             sN,serNum, res->name,residue->name,
-             altLoc ,aloc,  name,name1,
-         segID  ,sID,
-      element,elmnt,
-         charge ,achrg );
-    if (res!=residue)  printf (" it's a residue\n" );
-    */
-    return Error_ATOM_Unmatch;
-  }
-
-  return 0;
-
-}
-
-
-int CAtom::GetCIF ( int ix, PCMMCIFLoop Loop,
-                    PCMMCIFLoop LoopAnis )  {
-char PDBGroup[30];
-int  k;
-int  RC;
-
-  index = ix;
-
-  if (WhatIsSet & ASET_Coordinates)
-    return Error_ATOM_AlreadySet;
-
-/*
-
-loop_
-*0  _atom_site.group_PDB
-*1  _atom_site.id
-*2  _atom_site.type_symbol         <- chem elem
--3  _atom_site.label_atom_id       <- atom name
-*4  _atom_site.label_alt_id        <- alt code
-=5  _atom_site.label_comp_id       <- res name ???
-=6  _atom_site.label_asym_id       <- chain id ???
-=7  _atom_site.label_entity_id     < ???
-=8  _atom_site.label_seq_id        <- poly seq id
-+9  _atom_site.pdbx_PDB_ins_code   <- ins code
--10 _atom_site.segment_id          <- segment id
-*11 _atom_site.Cartn_x
-*12 _atom_site.Cartn_y
-*13 _atom_site.Cartn_z
-*14 _atom_site.occupancy
-*15 _atom_site.B_iso_or_equiv
-*16 _atom_site.Cartn_x_esd
-*17 _atom_site.Cartn_y_esd
-*18 _atom_site.Cartn_z_esd
-*19 _atom_site.occupancy_esd
-*20 _atom_site.B_iso_or_equiv_esd
-*21 _atom_site.pdbx_formal_charge
-+22 _atom_site.auth_seq_id          <- seq id we want
-+23 _atom_site.auth_comp_id         <- res name we want
-+24 _atom_site.auth_asym_id         <- ch id we want ?
-*25 _atom_site.auth_atom_id         <- atom name we want ?
-+26 _atom_site.pdbx_PDB_model_num   <- model no
-
-'+' read in CMMDBFile::CheckAtomPlace()
-'=' new in residue, read in CMMDBFile::CheckAtomPlace()
-'-' new in atom
-
-*/
-
-
-  // (0)
-  k = ix-1;
-  CIFGetString ( PDBGroup,Loop,CIFTAG_GROUP_PDB,k,
-                 sizeof(PDBGroup),pstr("") );
-
-  Ter = !strcmp(PDBGroup,pstr("TER")   );
-  Het = !strcmp(PDBGroup,pstr("HETATM"));
-
-  // (1)
-  RC = CIFGetInteger1 ( serNum,Loop,CIFTAG_ID,k );
-  if (RC)  {
-    if (Ter)                    serNum = -1;
-    else if (RC==Error_NoData)  serNum = index;
-    else
-      return RC;
-  }
-
-  if (Ter)  {
-    Loop->DeleteRow ( k );
-    WhatIsSet |= ASET_Coordinates;
-    return 0;
-  }
-
-  // (25)
-  CIFGetString ( name,Loop,CIFTAG_AUTH_ATOM_ID,k,
-                        sizeof(name)  ,pstr("") );
-  // (3)
-  CIFGetString ( label_atom_id,Loop,CIFTAG_LABEL_ATOM_ID,k,
-                        sizeof(label_atom_id),pstr("") );
-  // (4)
-  CIFGetString ( altLoc,Loop,CIFTAG_LABEL_ALT_ID ,k,
-                        sizeof(altLoc),pstr("") );
-
-  // (11,12,13)
-  RC = CIFGetReal1 ( x,Loop,CIFTAG_CARTN_X,k );
-  if (!RC) RC = CIFGetReal1 ( y,Loop,CIFTAG_CARTN_Y,k );
-  if (!RC) RC = CIFGetReal1 ( z,Loop,CIFTAG_CARTN_Z,k );
-  if (RC)  return Error_ATOM_Unrecognized;
-  WhatIsSet |= ASET_Coordinates;
-
-  // (14)
-  if (!CIFGetReal1(occupancy,Loop,CIFTAG_OCCUPANCY,k))
-    WhatIsSet |= ASET_Occupancy;
-  // (15)
-  if (!CIFGetReal1(tempFactor,Loop,CIFTAG_B_ISO_OR_EQUIV,k))
-    WhatIsSet |= ASET_tempFactor;
-
-  // (10)
-  CIFGetString ( segID,Loop,CIFTAG_SEGMENT_ID,k,
-                       sizeof(segID) ,pstr("") );
-  // (21)
-  if (!CIFGetReal1(charge,Loop,CIFTAG_PDBX_FORMAL_CHARGE,k))
-    WhatIsSet |= ASET_Charge;
-  // (2)
-  RC = CIFGetString ( element,Loop,CIFTAG_TYPE_SYMBOL,k,
-                              sizeof(element),pstr("  ") );
-  if (RC)
-    CIFGetString ( element,Loop,CIFTAG_ATOM_TYPE_SYMBOL,k,
-                        sizeof(element),pstr("  ") );
-
-  RestoreElementName();
-  MakePDBAtomName   ();
-//  printf ( "    '%s' '%s'\n",name,element );
-
-  // (16,17,18)
-  RC = CIFGetReal1 ( sigX,Loop,CIFTAG_CARTN_X_ESD,k );
-  if (!RC) RC = CIFGetReal1 ( sigY,Loop,CIFTAG_CARTN_Y_ESD,k );
-  if (!RC) RC = CIFGetReal1 ( sigZ,Loop,CIFTAG_CARTN_Z_ESD,k );
-  if (RC==Error_UnrecognizedReal)
-    return RC;
-  if (!RC) WhatIsSet |= ASET_CoordSigma;
-
-  // (19)
-  if (!CIFGetReal1(sigOcc,Loop,CIFTAG_OCCUPANCY_ESD,k))
-    WhatIsSet |= ASET_OccSigma;
-  // (20)
-  if (!CIFGetReal1(sigTemp,Loop,CIFTAG_B_ISO_OR_EQUIV_ESD,k))
-    WhatIsSet |= ASET_tFacSigma;
-
-  Loop->DeleteRow ( k );
-
-  if (LoopAnis)  {
-
-    RC = CIFGetReal1 ( u11,LoopAnis,CIFTAG_U11,k );
-    if (!RC) RC = CIFGetReal1 ( u22,LoopAnis,CIFTAG_U22,k );
-    if (!RC) RC = CIFGetReal1 ( u33,LoopAnis,CIFTAG_U33,k );
-    if (!RC) RC = CIFGetReal1 ( u13,LoopAnis,CIFTAG_U13,k );
-    if (!RC) RC = CIFGetReal1 ( u12,LoopAnis,CIFTAG_U12,k );
-    if (!RC) RC = CIFGetReal1 ( u23,LoopAnis,CIFTAG_U23,k );
-    if (RC==Error_UnrecognizedReal)
-      return RC;
-    if (!RC) WhatIsSet |= ASET_Anis_tFac;
-
-    RC = CIFGetReal1 ( su11,LoopAnis,CIFTAG_U11_ESD,k );
-    if (!RC) RC = CIFGetReal1 ( su22,LoopAnis,CIFTAG_U22_ESD,k );
-    if (!RC) RC = CIFGetReal1 ( su33,LoopAnis,CIFTAG_U33_ESD,k );
-    if (!RC) RC = CIFGetReal1 ( su13,LoopAnis,CIFTAG_U13_ESD,k );
-    if (!RC) RC = CIFGetReal1 ( su12,LoopAnis,CIFTAG_U12_ESD,k );
-    if (!RC) RC = CIFGetReal1 ( su23,LoopAnis,CIFTAG_U23_ESD,k );
-    if (RC==Error_UnrecognizedReal)
-      return RC;
-    if (!RC) WhatIsSet |= ASET_Anis_tFSigma;
-
-    LoopAnis->DeleteRow ( k );
-
-  }
-
-  return 0;
-
-}
-
-Boolean CAtom::RestoreElementName()  {
-//  This function works only if element name is not given.
-  if (Ter)  {
-    name[0]    = char(0);
-    element[0] = char(0);
-    return False;
-  }
-  if ((!element[0]) ||
-      ((element[0]==' ') && ((!element[1]) || (element[1]==' '))))  {
-    if ((name[0]>='A') && (name[0]<='Z'))  {
-      element[0] = name[0];
-      element[1] = name[1];
-    } else  {
-      element[0] = ' ';
-      element[1] = name[1];
-    }
-    element[2] = char(0);
-    return False;
-  } else if (!element[1])  {
-    // not aligned element name, possibly coming from mmCIF
-    element[1] = element[0];
-    element[0] = ' ';
-    element[2] = char(0);
-    return False;
-  }
-  return True;
-}
-
-Boolean CAtom::MakePDBAtomName()  {
-int     i,k;
-  if (Ter)  {
-    name[0]    = char(0);
-    element[0] = char(0);
-    return False;
-  }
-  UpperCase ( name    );
-  UpperCase ( element );
-  if ((element[0]==' ') && (element[1]==' '))  {
-    // element name not given, make one from the atom name
-    if ((name[0]>='A') && (name[0]<='Z'))  {
-      if (!name[1])  {
-        name[4] = char(0);
-        name[3] = ' ';
-        name[2] = ' ';
-        name[1] = name[0];
-        name[0] = ' ';
-      }
-      /* the commented part looks like a wrong inheritance
-         from FORTRAN RWBrook. Commented on 04.03.2004,
-         to be removed.
-      else if ((name[0]=='C') && (name[1]=='A'))  {
-        name[4] = char(0);
-        name[3] = name[2];
-        name[2] = name[1];
-        name[1] = name[0];
-        name[0] = ' ';
-      }
-      */
-      element[0] = name[0];
-      element[1] = name[1];
-    } else  {
-      element[0] = ' ';
-      element[1] = name[1];
-    }
-    element[2] = char(0);
-    return False;
-  } else if ((name[0]>='A') && (name[0]<='Z'))  {
-    if (!element[1])  {
-      element[2] = char(0);
-      element[1] = element[0];
-      element[0] = ' ';
-      k = strlen(name);
-      if (k<4)  {
-        for (i=3;i>0;i--)
-          name[i] = name[i-1];
-        name[0] = ' ';
-        k++;
-        while (k<4)
-          name[k++] = ' ';
-        name[k] = char(0);
-      }
-    } else if ((element[0]==' ') && (element[1]!=name[1]))  {
-      for (i=3;i>0;i--)
-        name[i] = name[i-1];
-      name[0] = ' ';
-      k = strlen(name);
-      while (k<4)
-        name[k++] = ' ';
-      name[k] = char(0);
-    } else  {
-      k = strlen(name);
-      while (k<4)
-        name[k++] = ' ';
-      name[k] = char(0);
-    }
-  }
-  return True;
-}
-
-void  CAtom::SetCoordinates ( realtype xx,  realtype yy, realtype zz,
-                              realtype occ, realtype tFac )  {
-  x = xx;
-  y = yy;
-  z = zz;
-  occupancy  = occ;
-  tempFactor = tFac;
-  WhatIsSet |= ASET_Coordinates | ASET_Occupancy | ASET_tempFactor;
-}
-
-void  CAtom::Transform ( mat33 & tm, vect3 & v ) {
-realtype  x1,y1,z1;
-  x1 = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + v[0];
-  y1 = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + v[1];
-  z1 = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + v[2];
-  x = x1;
-  y = y1;
-  z = z1;
-}
-
-void  CAtom::Transform ( mat44 & tm ) {
-realtype  x1,y1,z1;
-  x1 = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3];
-  y1 = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3];
-  z1 = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3];
-  x = x1;
-  y = y1;
-  z = z1;
-}
-
-void  CAtom::TransformCopy ( mat44    & tm,
-                             realtype & xx,
-                             realtype & yy,
-                             realtype & zz )  {
-  xx = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3];
-  yy = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3];
-  zz = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3];
-}
-
-void  CAtom::TransformSet ( mat44  & tm,
-                            realtype xx,
-                            realtype yy,
-                            realtype zz ) {
-  x = tm[0][0]*xx + tm[0][1]*yy + tm[0][2]*zz + tm[0][3];
-  y = tm[1][0]*xx + tm[1][1]*yy + tm[1][2]*zz + tm[1][3];
-  z = tm[2][0]*xx + tm[2][1]*yy + tm[2][2]*zz + tm[2][3];
-}
-
-
-// -------  user-defined data handlers
-
-int  CAtom::PutUDData ( int UDDhandle, int iudd )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::putUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CAtom::PutUDData ( int UDDhandle, realtype rudd )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::putUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CAtom::PutUDData ( int UDDhandle, cpstr sudd )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::putUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CAtom::GetUDData ( int UDDhandle, int & iudd )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::getUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CAtom::GetUDData ( int UDDhandle, realtype & rudd )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::getUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CAtom::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::getUDData ( UDDhandle,sudd,maxLen );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CAtom::GetUDData ( int UDDhandle, pstr & sudd )  {
-  if (UDDhandle & UDRF_ATOM)
-        return  CUDData::getUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-
-void  CAtom::Copy ( PCAtom atom )  {
-// this does not make any references in residues and does
-// not change indices!! it does change serial numbers, though.
-
-  serNum     = atom->serNum;
-  x          = atom->x;
-  y          = atom->y;
-  z          = atom->z;
-  occupancy  = atom->occupancy;
-  tempFactor = atom->tempFactor;
-  sigX       = atom->sigX;
-  sigY       = atom->sigY;
-  sigZ       = atom->sigZ;
-  sigOcc     = atom->sigOcc;
-  sigTemp    = atom->sigTemp;
-  u11        = atom->u11;
-  u22        = atom->u22;
-  u33        = atom->u33;
-  u12        = atom->u12;
-  u13        = atom->u13;
-  u23        = atom->u23;
-  su11       = atom->su11;
-  su22       = atom->su22;
-  su33       = atom->su33;
-  su12       = atom->su12;
-  su13       = atom->su13;
-  su23       = atom->su23;
-  Het        = atom->Het;
-  Ter        = atom->Ter;
-  WhatIsSet  = atom->WhatIsSet;
-
-  strcpy ( name         ,atom->name          );
-  strcpy ( label_atom_id,atom->label_atom_id );
-  strcpy ( altLoc       ,atom->altLoc        );
-  strcpy ( segID        ,atom->segID         );
-  strcpy ( element      ,atom->element       );
-  strcpy ( energyType   ,atom->energyType    );
-  charge = atom->charge;
-
-}
-
-int CAtom::CheckID ( const AtomName aname, const Element elname,
-                     const AltLoc aloc )  {
-pstr p1,p2;
-  if (aname)  {
-    if (aname[0]!='*')  {
-      p1 = name;
-      while (*p1==' ') p1++;
-      p2 = pstr(aname);
-      while (*p2==' ') p2++;
-      while ((*p2) && (*p1) && (*p1!=' ') && (*p2!=' '))  {
-        if (*p1!=*p2)  return 0;
-        p1++;
-        p2++;
-      }
-      if (*p1!=*p2)  {
-        if (((*p1) && (*p1!=' ')) ||
-            ((*p2) && (*p2!=' ')))  return 0;
-      }
-    }
-  }
-  if (elname)  {
-    if (elname[0]!='*')  {
-      p1 = element;
-      while (*p1==' ')  p1++;
-      p2 = pstr(elname);
-      while (*p2==' ')  p2++;
-      while ((*p2) && (*p1) && (*p1!=' ') && (*p2!=' '))  {
-        if (*p1!=*p2)  return 0;
-        p1++;
-        p2++;
-      }
-      if (*p1!=*p2)  return 0;
-    }
-  }
-  if (aloc)  {
-    if ((aloc[0]!='*') && (strcmp(aloc,altLoc)))   return 0;
-  }
-  return 1;
-}
-
-int CAtom::CheckIDS ( cpstr ID )  {
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-pstr     p;
-  p = strrchr ( ID,'/' );
-  if (p)  p++;
-    else  p = pstr(ID);
-  ParseAtomID ( p,aname,elname,aloc );
-  return  CheckID ( aname,elname,aloc );
-}
-
-void  CAtom::SetShortBinary()  {
-  WhatIsSet |= ASET_ShortBinary;
-}
-
-void  CAtom::write ( RCFile f )  {
-int  i,k;
-byte Version=2;
-byte nb;
-
-  f.WriteWord ( &WhatIsSet );
-  if (WhatIsSet & ASET_ShortBinary)  {
-    if (Ter)  WhatIsSet |= ASET_ShortTer;
-    if (Het)  WhatIsSet |= ASET_ShortHet;
-    f.WriteInt     ( &index        );
-    f.WriteTerLine ( name   ,False );
-    f.WriteTerLine ( altLoc ,False );
-    f.WriteTerLine ( element,False );
-    if (WhatIsSet & ASET_Coordinates)  {
-      f.WriteFloat ( &x );
-      f.WriteFloat ( &y );
-      f.WriteFloat ( &z );
-    }
-    return;
-  }
-
-  f.WriteByte  ( &Version );
-
-  CUDData::write ( f );
-
-  f.WriteInt     ( &serNum );
-  f.WriteInt     ( &index  );
-  f.WriteTerLine ( name         ,False );
-  f.WriteTerLine ( label_atom_id,False );
-  f.WriteTerLine ( altLoc       ,False );
-  f.WriteTerLine ( segID        ,False );
-  f.WriteTerLine ( element      ,False );
-  f.WriteTerLine ( energyType   ,False );
-  f.WriteFloat   ( &charge );
-  f.WriteBool    ( &Het    );
-  f.WriteBool    ( &Ter    );
-
-  if (WhatIsSet & ASET_Coordinates)  {
-    f.WriteFloat ( &x );
-    f.WriteFloat ( &y );
-    f.WriteFloat ( &z );
-    if (WhatIsSet & ASET_Occupancy)
-      f.WriteFloat ( &occupancy  );
-    if (WhatIsSet & ASET_tempFactor)
-      f.WriteFloat ( &tempFactor );
-  }
-
-  if (WhatIsSet & ASET_CoordSigma)  {
-    f.WriteFloat ( &sigX );
-    f.WriteFloat ( &sigY );
-    f.WriteFloat ( &sigZ );
-    if ((WhatIsSet & ASET_Occupancy) &&
-        (WhatIsSet & ASET_OccSigma))
-      f.WriteFloat ( &sigOcc );
-    if ((WhatIsSet & ASET_tempFactor) &&
-        (WhatIsSet & ASET_tFacSigma))
-      f.WriteFloat ( &sigTemp );
-  }
-
-  if (WhatIsSet & ASET_Anis_tFac)  {
-    f.WriteFloat ( &u11 );
-    f.WriteFloat ( &u22 );
-    f.WriteFloat ( &u33 );
-    f.WriteFloat ( &u12 );
-    f.WriteFloat ( &u13 );
-    f.WriteFloat ( &u23 );
-    if (WhatIsSet & ASET_Anis_tFSigma)  {
-      f.WriteFloat ( &su11 );
-      f.WriteFloat ( &su22 );
-      f.WriteFloat ( &su33 );
-      f.WriteFloat ( &su12 );
-      f.WriteFloat ( &su13 );
-      f.WriteFloat ( &su23 );
-    }
-  }
-
-  nb = byte(nBonds & 0x000000FF);
-  f.WriteByte ( &nb );
-  for (i=0;i<nb;i++)
-    if (Bond[i].atom)  {
-      f.WriteInt  ( &(Bond[i].atom->index) );
-      f.WriteByte ( &(Bond[i].order)       );
-    } else  {
-      k = -1;
-      f.WriteInt  ( &k );
-    }
-
-}
-
-void  CAtom::read ( RCFile f ) {
-int  i,k;
-byte nb,Version;
-
-  FreeMemory();
-
-  f.ReadWord ( &WhatIsSet );
-  if (WhatIsSet & ASET_ShortBinary)  {
-    f.ReadInt     ( &index        );
-    f.ReadTerLine ( name   ,False );
-    f.ReadTerLine ( altLoc ,False );
-    f.ReadTerLine ( element,False );
-    if (WhatIsSet & ASET_Coordinates)  {
-      f.ReadFloat ( &x );
-      f.ReadFloat ( &y );
-      f.ReadFloat ( &z );
-    }
-    serNum     = index;
-    Ter        = WhatIsSet & ASET_ShortTer;
-    Het        = WhatIsSet & ASET_ShortHet;
-    name   [4] = char(0);
-    altLoc [1] = char(0);
-    element[2] = char(0);
-    segID  [0] = char(0);
-    charge     = 0.0;
-    WhatIsSet &= ASET_All;
-    return;
-  }
-
-  f.ReadByte  ( &Version );
-
-  CUDData::read ( f );
-
-  f.ReadInt     ( &serNum );
-  f.ReadInt     ( &index  );
-  f.ReadTerLine ( name      ,False );
-  if (Version>1)
-    f.ReadTerLine ( label_atom_id,False );
-  f.ReadTerLine ( altLoc    ,False );
-  f.ReadTerLine ( segID     ,False );
-  f.ReadTerLine ( element   ,False );
-  f.ReadTerLine ( energyType,False );
-  f.ReadFloat   ( &charge );
-  f.ReadBool    ( &Het    );
-  f.ReadBool    ( &Ter    );
-
-  if (WhatIsSet & ASET_Coordinates)  {
-    f.ReadFloat ( &x );
-    f.ReadFloat ( &y );
-    f.ReadFloat ( &z );
-    if (WhatIsSet & ASET_Occupancy)  f.ReadFloat ( &occupancy  );
-                               else  occupancy = 0.0;
-    if (WhatIsSet & ASET_tempFactor) f.ReadFloat ( &tempFactor );
-                               else  tempFactor = 0.0;
-  } else  {
-    x          = 0.0;
-    y          = 0.0;
-    z          = 0.0;
-    occupancy  = 0.0;
-    tempFactor = 0.0;
-  }
-
-  if (WhatIsSet & ASET_CoordSigma)  {
-    f.ReadFloat ( &sigX );
-    f.ReadFloat ( &sigY );
-    f.ReadFloat ( &sigZ );
-    if ((WhatIsSet & ASET_Occupancy) &&
-        (WhatIsSet & ASET_OccSigma))
-          f.ReadFloat ( &sigOcc );
-    else  sigOcc = 0.0;
-    if ((WhatIsSet & ASET_tempFactor) &&
-        (WhatIsSet & ASET_tFacSigma))
-          f.ReadFloat ( &sigTemp );
-    else  sigTemp = 0.0;
-  } else  {
-    sigX    = 0.0;
-    sigY    = 0.0;
-    sigZ    = 0.0;
-    sigOcc  = 0.0;
-    sigTemp = 0.0;
-  }
-
-  if (WhatIsSet & ASET_Anis_tFac)  {
-    f.ReadFloat ( &u11 );
-    f.ReadFloat ( &u22 );
-    f.ReadFloat ( &u33 );
-    f.ReadFloat ( &u12 );
-    f.ReadFloat ( &u13 );
-    f.ReadFloat ( &u23 );
-    if (WhatIsSet & ASET_Anis_tFSigma)  {
-      f.ReadFloat ( &su11 );
-      f.ReadFloat ( &su22 );
-      f.ReadFloat ( &su33 );
-      f.ReadFloat ( &su12 );
-      f.ReadFloat ( &su13 );
-      f.ReadFloat ( &su23 );
-    } else  {
-      su11 = 0.0;
-      su22 = 0.0;
-      su33 = 0.0;
-      su12 = 0.0;
-      su13 = 0.0;
-      su23 = 0.0;
-    }
-  } else  {
-    u11  = 0.0;
-    u22  = 0.0;
-    u33  = 0.0;
-    u12  = 0.0;
-    u13  = 0.0;
-    u23  = 0.0;
-    su11 = 0.0;
-    su22 = 0.0;
-    su33 = 0.0;
-    su12 = 0.0;
-    su13 = 0.0;
-    su23 = 0.0;
-  }
-
-  f.ReadByte ( &nb );
-  if (nb>0)  {
-    Bond = new SAtomBond[nb];
-    for (i=0;i<nb;i++)  {
-      f.ReadInt  ( &k );
-      if (k>0)  f.ReadByte ( &(Bond[i].order) );
-          else  Bond[i].order = 0;
-      // we place *index* of bonded atom temporary on the place
-      // of its pointer, and the pointer will be calculated
-      // after CResidue::read calls _setBonds(..).
-      memcpy ( &(Bond[i].atom),&k,4 );
-    }
-  }
-  nBonds = nb;
-  nBonds = nBonds | (nBonds << 8);
-
-}
-
-void CAtom::_setBonds ( PPCAtom A )  {
-int i,k,nb;
-  nb = nBonds & 0x000000FF;
-  for (i=0;i<nb;i++)  {
-    memcpy ( &k,&(Bond[i].atom),4 );
-    if (k>0)  Bond[i].atom = A[k];
-        else  Bond[i].atom = NULL;
-  }
-}
-
-
-MakeFactoryFunctions(CAtom)
-
-
-
-//  ===========================  CResidue  ===========================
-
-
-void  SAtomStat::Init()  {
-
-  nAtoms = 0;
-
-  xmin = MaxReal;   xmax = MinReal;    xm = 0.0;  xm2 = 0.0;
-  ymin = MaxReal;   ymax = MinReal;    ym = 0.0;  ym2 = 0.0;
-  zmin = MaxReal;   zmax = MinReal;    zm = 0.0;  zm2 = 0.0;
-
-  occ_min = MaxReal;  occ_max = MinReal;  occ_m = 0.0;  occ_m2 = 0.0;
-  tFmin   = MaxReal;  tFmax   = MinReal;  tFm   = 0.0;  tFm2   = 0.0;
-
-  u11_min = MaxReal;  u11_max = MinReal;  u11_m = 0.0;  u11_m2 = 0.0;
-  u22_min = MaxReal;  u22_max = MinReal;  u22_m = 0.0;  u22_m2 = 0.0;
-  u33_min = MaxReal;  u33_max = MinReal;  u33_m = 0.0;  u33_m2 = 0.0;
-  u12_min = MaxReal;  u12_max = MinReal;  u12_m = 0.0;  u12_m2 = 0.0;
-  u13_min = MaxReal;  u13_max = MinReal;  u13_m = 0.0;  u13_m2 = 0.0;
-  u23_min = MaxReal;  u23_max = MinReal;  u23_m = 0.0;  u23_m2 = 0.0;
-
-  WhatIsSet = ASET_All;
-
-  finished = False;
-
-}
-
-void  SAtomStat::Finish()  {
-realtype v;
-
-  if (!finished)  {
-
-    finished = True;
-
-    if (nAtoms>0)  {
-
-      v      = nAtoms;
-
-      xm    /= v;    xm2    /= v;
-      ym    /= v;    ym2    /= v;
-      zm    /= v;    zm2    /= v;
-
-      occ_m /= v;    occ_m2 /= v;
-      tFm   /= v;    tFm2   /= v;
-
-      u11_m /= v;    u11_m2 /= v;
-      u22_m /= v;    u22_m2 /= v;
-      u33_m /= v;    u33_m2 /= v;
-      u12_m /= v;    u12_m2 /= v;
-      u13_m /= v;    u13_m2 /= v;
-      u23_m /= v;    u23_m2 /= v;
-    }
-  }
-
-}
-
-realtype  SAtomStat::GetMaxSize()  {
-realtype  r;
-  r = RMax(xmax-xmin,ymax-ymin);
-  r = RMax(r,zmax-zmin);
-  return RMax(r,0.0);
-}
-
-
-// ----------------------------------------------------------------
-
-
-CResidue::CResidue() : CUDData()  {
-  InitResidue();
-}
-
-CResidue::CResidue ( PCChain Chain_Owner ) : CUDData()  {
-  InitResidue();
-  if (Chain_Owner)
-    Chain_Owner->AddResidue ( this );
-}
-
-CResidue::CResidue ( PCChain       Chain_Owner,
-                     const ResName resName,
-                     int           sqNum,
-                     const InsCode ins ) : CUDData()  {
-  InitResidue();
-  seqNum = sqNum;
-  strcpy_css ( name,pstr(resName) );
-  strcpy_css ( insCode,pstr(ins) );
-  if (Chain_Owner)
-    Chain_Owner->AddResidue ( this );
-}
-
-CResidue::CResidue ( RPCStream Object ) : CUDData(Object)  {
-  InitResidue();
-}
-
-CResidue::~CResidue()  {
-  FreeMemory();
-  if (chain)  chain->_ExcludeResidue ( name,seqNum,insCode );
-}
-
-
-void  CResidue::InitResidue()  {
-  strcpy ( name         ,"---"  );  // residue name
-  strcpy ( label_comp_id,"---"  );  // assigned residue name
-  label_asym_id[0] = char(0);       // assigned chain Id
-  seqNum           = -MaxInt;       // residue sequence number
-  label_seq_id     = -MaxInt;       // assigned residue sequence number
-  label_entity_id  = 1;             // assigned entity id
-  strcpy ( insCode,"" );            // residue insertion code
-  chain   = NULL;                   // reference to chain
-  index   = -1;                     // undefined index in chain
-  nAtoms  = 0;                      // number of atoms in the residue
-  AtmLen  = 0;                      // length of atom array
-  atom    = NULL;                   // array of atoms
-  Exclude = True;
-  SSE     = SSE_None;
-}
-
-void  CResidue::SetChain ( PCChain Chain_Owner )  {
-  chain = Chain_Owner;
-}
-
-
-int  CResidue::GetResidueNo()  {
-  if (chain)  return  chain->GetResidueNo ( seqNum,insCode );
-        else  return  -1;
-}
-
-void CResidue::SetChainID ( const ChainID chID )  {
-  if (chain)
-    chain->SetChainID ( chID );
-}
-
-
-int  CResidue::GetCenter ( realtype & x, realtype & y,
-                           realtype & z )  {
-int i,k;
-  x = 0.0;
-  y = 0.0;
-  z = 0.0;
-  k = 0;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (!atom[i]->Ter)  {
-        x += atom[i]->x;
-        y += atom[i]->y;
-        z += atom[i]->z;
-        k++;
-      }
-    }
-  if (k>0)  {
-    x /= k;
-    y /= k;
-    z /= k;
-    return 0;
-  }
-  return 1;
-}
-
-void * CResidue::GetCoordHierarchy()  {
-  if (chain)  return chain->GetCoordHierarchy();
-  return NULL;
-}
-
-void  CResidue::GetAltLocations ( int     & nAltLocs,
-                                  PAltLoc & aLoc,
-                                  rvector & occupancy,
-                                  int     & alflag )  {
-int      i,j,k, nal,nal1;
-realtype occ1;
-Boolean  B;
-PAltLoc  aL;
-rvector  occ;
-bvector  alv;
-
-  aLoc      = NULL;
-  occupancy = NULL;
-  nAltLocs  = 0;
-  alflag    = ALF_NoAltCodes;
-
-  if (nAtoms>0)  {
-
-    // temporary array for altcodes
-    aL = new AltLoc[nAtoms];
-    // temporary array for occupancies
-    GetVectorMemory ( occ,nAtoms,0 );
-    // temporary array for checking altcodes
-    GetVectorMemory ( alv,nAtoms,0 );
-    for (i=0;i<nAtoms;i++)
-      alv[i] = False;
-
-    k   = 0;  // counts unique alternation codes
-    nal = 0;
-    for (i=0;i<nAtoms;i++)
-      if (atom[i])  {
-        if (!atom[i]->Ter)  {
-          // Find if the alternation code of ith atom is
-          // a new one.
-          B = False;
-          for (j=0;(j<k) && (!B);j++)
-            B = !strcmp(atom[i]->altLoc,aL[j]);
-          if (!B)  {
-            // that's a new altcode, get its occupancy
-            if (atom[i]->WhatIsSet & ASET_Occupancy)
-                 occ[k] = atom[i]->occupancy;
-            else occ[k] = -1.0;
-            // store new altcode in temporary array
-            strcpy ( aL[k],atom[i]->altLoc );
-            // check consistency of the altcode data if:
-            //   a) the data was not found wrong so far
-            //   b) this atom name has not been checked before
-            //   c) altcode is not the "empty"-altcode
-            if ((!(alflag & ALF_Mess)) && (!alv[i]) &&
-                (atom[i]->altLoc[0]))  {
-              B    = False; // will be set True if "empty"-altcode
-                            // is found for current atom name
-              nal1 = 0;     // counts the number of different altcodes
-                            // for current atom name
-              occ1 = 0.0;   // will count the sum of occupancies for
-                            // current atom name
-              for (j=0;j<nAtoms;j++)
-                if (atom[j])  {
-                  if ((!atom[j]->Ter) &&
-                      (!strcmp(atom[j]->name,atom[i]->name)))  {
-                    if (atom[j]->WhatIsSet & ASET_Occupancy)
-                      occ1 += atom[j]->occupancy;
-                    if (!atom[j]->altLoc[0])  B = True;
-                    alv[j] = True;  // mark it as "checked"
-                    nal1++;
-                  }
-                }
-              if (!(alflag & (ALF_EmptyAltLoc | ALF_NoEmptyAltLoc)))  {
-                if (B)  alflag |= ALF_EmptyAltLoc;
-                  else  alflag |= ALF_NoEmptyAltLoc;
-              } else if (((alflag & ALF_EmptyAltLoc) && (!B)) ||
-                         ((alflag & ALF_NoEmptyAltLoc) && (B)))
-                alflag |= ALF_Mess;
-              if ((occ[k]>=0) && (fabs(1.0-occ1)>0.01))
-                alflag |= ALF_Occupancy;
-              if (nal==0)    // first time just remember the number
-                nal = nal1;  // of different altcodes
-              else if (nal!=nal1)   // check if number of different altcodes
-                alflag |= ALF_Mess; // is not the same through the residue
-            }
-            k++;
-          }
-        }
-      }
-    if (k>0)  {
-      aLoc = new AltLoc[k];
-      GetVectorMemory ( occupancy,k,0 );
-      for (i=0;i<k;i++) {
-        strcpy ( aLoc[i],aL[i] );
-        occupancy[i] = occ[i];
-      }
-      nAltLocs = k;
-    }
-
-    delete[] aL;
-    FreeVectorMemory ( occ,0 );
-    FreeVectorMemory ( alv,0 );
-
-  }
-
-}
-
-int CResidue::GetNofAltLocations() {
-int     i,j,k;
-Boolean B;
-  k = 0;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (!atom[i]->Ter)  {
-        B = False;
-        for (j=0;(j<i) && (!B);j++)
-          if (atom[j])  {
-            if (!atom[j]->Ter)
-              B = !strcmp(atom[i]->altLoc,atom[j]->altLoc);
-          }
-        if (!B)  k++;
-      }
-    }
-  return k;
-}
-
-void  CResidue::SetResID ( const ResName resName, int sqNum,
-                           const InsCode ins )  {
-  strcpy_css ( name,pstr(resName) );
-  seqNum = sqNum;
-  strcpy_css ( insCode,pstr(ins) );
-  strcpy (label_comp_id,name );
-}
-
-void  CResidue::FreeMemory()  {
-//   NOTE: individual atoms are disposed here as well!
-  DeleteAllAtoms();
-  if (atom)  delete[] atom;
-  atom   = NULL;
-  nAtoms = 0;
-  AtmLen = 0;
-}
-
-void CResidue::ExpandAtomArray ( int nAdd )  {
-int     i;
-PPCAtom atom1;
-  AtmLen += abs(nAdd);
-  atom1   = new PCAtom[AtmLen];
-  for (i=0;i<nAtoms;i++)
-    atom1[i] = atom[i];
-  for (i=nAtoms;i<AtmLen;i++)
-    atom1[i] = NULL;
-  if (atom)  delete[] atom;
-  atom = atom1;
-}
-
-int  CResidue::_AddAtom ( PCAtom atm )  {
-// Adds atom to the residue
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i]==atm)  return -i;  // this atom is already there
-  if (nAtoms>=AtmLen)
-    ExpandAtomArray ( nAtoms+10-AtmLen );
-  atom[nAtoms] = atm;
-  atom[nAtoms]->residue = this;
-  nAtoms++;
-  return 0;
-}
-
-int  CResidue::AddAtom ( PCAtom atm )  {
-//   AddAtom(..) adds atom to the residue. If residue is associated
-// with a coordinate hierarchy, and atom 'atm' is not, the latter
-// is checked in automatically. If atom 'atm' belongs to any
-// coordinate hierarchy (even though that of the residue), it is
-// *copied* rather than simply taken over, and is checked in.
-//   If residue is not associated with a coordinate hierarchy, all
-// added atoms will be checked in automatically once the residue
-// is checked in.
-PCMMDBFile manager;
-PCResidue  res;
-int        i;
-
-  for (i=0;i<nAtoms;i++)
-    if (atom[i]==atm)  return -i;  // this atom is already there
-
-  if (nAtoms>=AtmLen)
-    ExpandAtomArray ( nAtoms+10-AtmLen );
-
-  if (atm->GetCoordHierarchy()) {
-    atom[nAtoms] = newCAtom();
-    atom[nAtoms]->Copy ( atm );
-  } else  {
-    res = atm->GetResidue();
-    if (res)
-      for (i=0;i<res->nAtoms;i++)
-        if (res->atom[i]==atm)  {
-          res->atom[i] = NULL;
-          break;
-        }
-    atom[nAtoms] = atm;
-  }
-
-  atom[nAtoms]->residue = this;
-  manager = PCMMDBFile(GetCoordHierarchy());
-  if (manager)
-    manager->CheckInAtom ( 0,atom[nAtoms] );
-
-  nAtoms++;
-
-  return nAtoms;
-
-}
-
-int  CResidue::InsertAtom ( PCAtom atm, int position )  {
-//   InsertAtom(..) inserts atom into the specified position of
-// the residue. If residue is associated with a coordinate hierarchy,
-// and atom 'atm' is not, the latter is checked in automatically.
-// If atom 'atm' belongs to any coordinate hierarchy (even though
-// that of the residue), it is *copied* rather than simply taken
-// over, and is checked in.
-//   If residue is not associated with a coordinate hierarchy, all
-// added atoms will be checked in automatically once the residue
-// is checked in.
-PCMMDBFile manager;
-PCResidue  res;
-int        i,pos;
-
-  for (i=0;i<nAtoms;i++)
-    if (atom[i]==atm)  return -i;  // this atom is already there
-
-  if (nAtoms>=AtmLen)
-    ExpandAtomArray ( nAtoms+10-AtmLen );
-
-  pos = IMin(position,nAtoms);
-  for (i=nAtoms;i>pos;i--)
-    atom[i] = atom[i-1];
-
-  if (atm->GetCoordHierarchy()) {
-    atom[pos] = newCAtom();
-    atom[pos]->Copy ( atm );
-  } else  {
-    res = atm->GetResidue();
-    if (res)
-      for (i=0;i<res->nAtoms;i++)
-        if (res->atom[i]==atm)  {
-          res->atom[i] = NULL;
-          break;
-        }
-    atom[pos] = atm;
-  }
-
-  atom[pos]->residue = this;
-  manager = PCMMDBFile(GetCoordHierarchy());
-  if (manager)
-    manager->CheckInAtom ( 0,atom[pos] );
-
-  nAtoms++;
-
-  return nAtoms;
-
-}
-
-int  CResidue::InsertAtom ( PCAtom atm, const AtomName aname )  {
-//   This version inserts before the atom with given name. If such
-// name is not found, the atom is appended to the end.
-int i;
-  i = 0;
-  while (i<nAtoms)
-    if (!atom[i])  i++;
-    else if (!strcmp(aname,atom[i]->name))  break;
-    else i++;
-  return InsertAtom ( atm,i );
-}
-
-
-void  CResidue::CheckInAtoms()  {
-PCMMDBFile manager;
-int        i;
-  manager = PCMMDBFile(GetCoordHierarchy());
-  if (manager)
-    for (i=0;i<nAtoms;i++)
-      if (atom[i])  {
-        if (atom[i]->index<0)
-          manager->CheckInAtom ( 0,atom[i] );
-      }
-}
-
-
-int  CResidue::_ExcludeAtom ( int kndex )  {
-//  deletes atom from the residue
-int  i,k;
-
-  if (!Exclude)  return 0;
-
-  k = -1;
-  for (i=0;(i<nAtoms) && (k<0);i++)
-    if (atom[i])  {
-      if (atom[i]->index==kndex)  k = i;
-    }
-
-  if (k>=0)  {
-    for (i=k+1;i<nAtoms;i++)
-      atom[i-1] = atom[i];
-    nAtoms--;
-  }
-
-  if (nAtoms<=0)  return 1;
-            else  return 0;
-
-}
-
-
-void  CResidue::PDBASCIIAtomDump ( RCFile f )  {
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])
-      atom[i]->PDBASCIIDump ( f );
-}
-
-void  CResidue::MakeAtomCIF ( PCMMCIFData CIF )  {
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])
-      atom[i]->MakeCIF ( CIF );
-}
-
-
-void  CResidue::Copy ( PCResidue res )  {
-//
-//  Modify CResidue::Copy and both CResidues::_copy methods
-//  simultaneously!
-//
-//  This function will nake a copy of residue res in 'this' one.
-//  All atoms are copied, none is moved regardless to the association
-//  with coordinate hierarchy. If 'this' residue is associated with
-//  a coordinate hierarchy, all atoms are checked in.
-PCMMDBFile manager;
-int        i;
-
-  FreeMemory();
-
-  seqNum          = res->seqNum;
-  label_seq_id    = res->label_seq_id;
-  label_entity_id = res->label_entity_id;
-  index           = res->index;
-  AtmLen          = res->nAtoms;
-  SSE             = res->SSE;
-  strcpy ( name         ,res->name          );
-  strcpy ( label_comp_id,res->label_comp_id );
-  strcpy ( label_asym_id,res->label_asym_id );
-  strcpy ( insCode      ,res->insCode       );
-
-  if (AtmLen>0)  {
-    atom   = new PCAtom[AtmLen];
-    nAtoms = 0;
-    for (i=0;i<res->nAtoms;i++)
-      if (res->atom[i])  {
-        atom[nAtoms] = newCAtom();
-        atom[nAtoms]->Copy ( res->atom[i] );
-        atom[nAtoms]->SetResidue ( this );
-        nAtoms++;
-      }
-    for (i=nAtoms;i<AtmLen;i++)
-      atom[i] = NULL;
-    manager = PCMMDBFile(GetCoordHierarchy());
-    if (manager)
-      manager->CheckInAtoms ( 0,atom,nAtoms );
-  }
-
-}
-
-
-void  CResidue::_copy ( PCResidue res )  {
-//  Modify both CResidue::_copy and CResidue::Copy methods
-//  simultaneously!
-//
-//  will work properly only if atomic arrays
-//  this->chain->model->GetAtom() and
-//  res->chain->model->GetAtom() are identical
-//
-int     i;
-PPCAtom A;
-
-  FreeMemory();
-
-  seqNum          = res->seqNum;
-  label_seq_id    = res->label_seq_id;
-  label_entity_id = res->label_entity_id;
-  index           = res->index;
-  nAtoms          = res->nAtoms;
-  SSE             = res->SSE;
-  strcpy ( name         ,res->name          );
-  strcpy ( label_comp_id,res->label_comp_id );
-  strcpy ( label_asym_id,res->label_asym_id );
-  strcpy ( insCode      ,res->insCode       );
-
-  AtmLen = nAtoms;
-  A      = NULL;
-  if (chain)  {
-    if (chain->model)
-      A = chain->model->GetAllAtoms();
-  }
-  if ((nAtoms>0) && (A))  {
-    atom = new PCAtom[nAtoms];
-    for (i=0;i<nAtoms;i++)  {
-      atom[i] = A[res->atom[i]->index-1];
-      atom[i]->SetResidue ( this );
-    }
-  } else  {
-    nAtoms = 0;
-    AtmLen = 0;
-  }
-
-}
-
-void  CResidue::_copy ( PCResidue res, PPCAtom atm,
-                        int & atom_index )  {
-//  modify both CResidue::_copy and CResidue::Copy methods
-// simultaneously!
-//
-//  This function physically copies the atoms, creating new atom
-// instances and putting them into array 'atm' sequentially from
-// 'atom_index' position. 'atom_index' is modified (advanced).
-//
-int i;
-
-  FreeMemory();
-
-  seqNum          = res->seqNum;
-  label_seq_id    = res->label_seq_id;
-  label_entity_id = res->label_entity_id;
-  index           = res->index;
-  nAtoms          = res->nAtoms;
-  SSE             = res->SSE;
-  strcpy ( name         ,res->name          );
-  strcpy ( label_comp_id,res->label_comp_id );
-  strcpy ( label_asym_id,res->label_asym_id );
-  strcpy ( insCode      ,res->insCode       );
-
-  AtmLen = nAtoms;
-  if (AtmLen>0)  {
-    atom = new PCAtom[AtmLen];
-    for (i=0;i<nAtoms;i++)
-      if (res->atom[i])  {
-        if (!atm[atom_index])  atm[atom_index] = newCAtom();
-        atm[atom_index]->Copy ( res->atom[i] );
-        atm[atom_index]->residue = this;
-        atm[atom_index]->index = atom_index+1;
-        atom[i] = atm[atom_index];
-        atom_index++;
-      } else
-        atom[i] = NULL;
-  }
-
-}
-
-
-void  CResidue::GetAtomStatistics ( RSAtomStat AS )  {
-  AS.Init();
-  CalcAtomStatistics ( AS );
-  AS.Finish();
-}
-
-void  CResidue::CalcAtomStatistics ( RSAtomStat AS )  {
-//   AS must be initialized. The function only accumulates
-// the statistics.
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])
-      atom[i]->CalcAtomStatistics ( AS );
-}
-
-
-PCChain  CResidue::GetChain()  {
-  return chain;
-}
-
-PCModel  CResidue::GetModel()  {
-  if (chain) return (PCModel)chain->model;
-        else return NULL;
-}
-
-
-int CResidue::GetModelNum()  {
-  if (chain)  {
-    if (chain->model)
-      return chain->model->GetSerNum();
-  }
-  return 0;
-}
-
-pstr CResidue::GetChainID()  {
-  if (chain)  return chain->chainID;
-  return  pstr("");
-}
-
-pstr CResidue::GetLabelAsymID()  {
-  return label_asym_id;
-}
-
-pstr  CResidue::GetResName()  {
-  return name;
-}
-
-pstr  CResidue::GetLabelCompID()  {
-  return label_comp_id;
-}
-
-int   CResidue::GetAASimilarity ( const ResName resName )  {
-  return  ::GetAASimilarity ( pstr(name),pstr(resName) );
-}
-
-int   CResidue::GetAASimilarity ( PCResidue res )  {
-  return  ::GetAASimilarity ( name,res->name );
-}
-
-realtype CResidue::GetAAHydropathy()  {
-  return  ::GetAAHydropathy ( name );
-}
-
-void  CResidue::SetResName ( const ResName resName )  {
-  strcpy ( name,resName );
-}
-
-int   CResidue::GetSeqNum()  {
-  return seqNum;
-}
-
-int   CResidue::GetLabelSeqID()  {
-  return label_seq_id;
-}
-
-int   CResidue::GetLabelEntityID()  {
-  return label_entity_id;
-}
-
-pstr  CResidue::GetInsCode()  {
-  return insCode;
-}
-
-Boolean CResidue::isAminoacid ()  {
-  return ::isAminoacid ( name );
-}
-
-Boolean CResidue::isNucleotide()  {
-  return ::isNucleotide ( name );
-}
-
-int CResidue::isDNARNA()  {
-  return ::isDNARNA ( name );
-}
-
-Boolean CResidue::isSugar()  {
-  return ::isSugar ( name );
-}
-
-Boolean CResidue::isSolvent()  {
-  return ::isSolvent ( name );
-}
-
-Boolean CResidue::isModRes()  {
-PCChain  chn;
-PCModRes modRes;
-int      nModRes,i;
-  chn = GetChain();
-  if (chn)  {
-    nModRes = chn->GetNofModResidues();
-    for (i=0;i<nModRes;i++)  {
-      modRes = chn->GetModResidue ( i );
-      if (modRes)  {
-        if ((!strcmp(modRes->resName,name)) &&
-            (modRes->seqNum==seqNum)     &&
-            (!strcmp(modRes->insCode,insCode)))
-          return True;
-      }
-    }
-
-  }
-  return False;
-}
-
-Boolean CResidue::isInSelection ( int selHnd )  {
-PCMMDBFile manager = (PCMMDBFile)GetCoordHierarchy();
-PCMask     Mask;
-  if (manager)  {
-    Mask = manager->GetSelMask ( selHnd );
-    if (Mask)  return CheckMask ( Mask );
-  }
-  return False;
-}
-
-
-Boolean CResidue::isNTerminus()  {
-PPCResidue Res;
-int        i,j,nRes;
-  if (chain)  {
-    chain->GetResidueTable ( Res,nRes );
-    i = 0;
-    j = -1;
-    while ((i<nRes) && (j<0))  {
-      if (Res[i])  j = i;
-      i++;
-    }
-    if (j>=0)
-      return (Res[j]->index==index);
-  }
-  return False;
-}
-
-Boolean CResidue::isCTerminus()  {
-PPCResidue Res;
-int        i,j,nRes;
-  if (chain)  {
-    chain->GetResidueTable ( Res,nRes );
-    i = nRes-1;
-    j = -1;
-    while ((i>=0) && (j<0))  {
-      if (Res[i])  j = i;
-      i--;
-    }
-    if (j>=0)
-      return (Res[j]->index==index);
-  }
-  return False;
-}
-
-
-pstr  CResidue::GetResidueID ( pstr ResidueID )  {
-  ResidueID[0] = char(0);
-  if (chain)  {
-    if (chain->model)
-          sprintf ( ResidueID,"/%i/",chain->model->GetSerNum() );
-    else  strcpy  ( ResidueID,"/-/" );
-    strcat ( ResidueID,chain->chainID );
-  } else
-    strcpy ( ResidueID,"/-/-" );
-  ParamStr ( ResidueID,pstr("/"),seqNum );
-  strcat ( ResidueID,"(" );
-  strcat ( ResidueID,name );
-  strcat ( ResidueID,")" );
-  if (insCode[0])  {
-    strcat ( ResidueID,"." );
-    strcat ( ResidueID,insCode );
-  }
-  return ResidueID;
-}
-
-
-int CResidue::CheckID ( int * snum,
-                        const InsCode inscode,
-                        const ResName resname )  {
-  if (snum)  {
-    if (*snum!=seqNum)  return 0;
-  }
-  if (inscode)  {
-    if ((inscode[0]!='*') && (strcmp(inscode,insCode)))  return 0;
-  }
-  if (!resname)        return 1;
-  if ((resname[0]!='*') && (strcmp(resname,name))) return 0;
-  return 1;
-}
-
-int CResidue::CheckIDS ( cpstr CID )  {
-ChainID  chn;
-InsCode  inscode;
-ResName  resname;
-AtomName atm;
-Element  elm;
-AltLoc   aloc;
-pstr     p1,p2;
-int      mdl,sn,rc;
-
-  rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
-                       atm,elm,aloc,NULL );
- //  rc = ParseResID ( CID,sn,inscode,resname );
-
-  if (rc>=0)  {
-    p1 = NULL;
-    p2 = NULL;
-    if (inscode[0]!='*')  p1 = inscode;
-    if (resname[0]!='*')  p2 = resname;
-    if (!rc)  return  CheckID ( &sn ,p1,p2 );
-        else  return  CheckID ( NULL,p1,p2 );
-  }
-  return 0;
-
-}
-
-
-//  --------------------  Extracting atoms  -------------------------
-
-int  CResidue::GetNumberOfAtoms()  {
-  return nAtoms;
-}
-
-int  CResidue::GetNumberOfAtoms ( Boolean countTers )  {
-int i,na;
-  na = 0;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (countTers || (!atom[i]->Ter))  na++;
-    }
-  return na;
-}
-
-PCAtom CResidue::GetAtom ( const AtomName aname,
-                           const Element  elname,
-                           const AltLoc   aloc )  {
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (atom[i]->CheckID(aname,elname,aloc))
-        return atom[i];
-    }
-  return NULL;
-}
-
-PCAtom CResidue::GetAtom ( int atomNo )  {
-  if ((0<=atomNo) && (atomNo<nAtoms))
-    return atom[atomNo];
-  return NULL;
-}
-
-void CResidue::GetAtomTable ( PPCAtom & atomTable, int & NumberOfAtoms )  {
-  atomTable     = atom;
-  NumberOfAtoms = nAtoms;
-}
-
-void CResidue::GetAtomTable1 ( PPCAtom & atomTable, int & NumberOfAtoms )  {
-int i,j;
-  if (atomTable)  delete[] atomTable;
-  if (nAtoms>0)  {
-    atomTable = new PCAtom[nAtoms];
-    j = 0;
-    for (i=0;i<nAtoms;i++)
-      if (atom[i])  {
-        if (!atom[i]->Ter)
-          atomTable[j++] = atom[i];
-      }
-    NumberOfAtoms = j;
-  } else  {
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CResidue::TrimAtomTable()  {
-int i,j;
-  j = 0;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (j<i)  {
-        atom[j] = atom[i];
-        atom[i] = NULL;
-      }
-      j++;
-    }
-  nAtoms = j;
-}
-
-
-//  ---------------------  Deleting atoms  --------------------------
-
-int CResidue::DeleteAtom ( const AtomName aname,
-                           const Element  elname,
-                           const AltLoc   aloc )  {
-// apply CMMDBFile::FinishStructEdit() after all editings are done!
-// returns number of deleted atoms
-int     i,k,nA,kndex;
-PPCAtom A;
-
-  A  = NULL;
-  nA = 0;
-  if (chain)  {
-    if (chain->model)  {
-      A  = chain->model->GetAllAtoms();
-      nA = chain->model->GetNumberOfAllAtoms();
-    }
-  }
-
-  k = 0;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (atom[i]->CheckID(aname,elname,aloc))  {
-        k++;
-        kndex = atom[i]->index;
-        if ((0<kndex) && (kndex<=nA))   A[kndex-1] = NULL;
-        Exclude = False;
-        delete atom[i];
-        atom[i] = NULL;
-        Exclude = True;
-      }
-    }
-
-  return k;
-
-}
-
-int CResidue::DeleteAtom ( int atomNo )  {
-// apply CMMDBFile::FinishStructEdit() after all editings are done!
-// returns number of deleted atoms
-int     kndex,nA;
-PPCAtom A;
-
-  if ((0<=atomNo) && (atomNo<nAtoms))  {
-    if (atom[atomNo])  {
-      A  = NULL;
-      nA = 0;
-      if (chain)  {
-        if (chain->model)  {
-          A  = chain->model->GetAllAtoms();
-          nA = chain->model->GetNumberOfAllAtoms();
-        }
-      }
-      kndex = atom[atomNo]->index;
-      if ((0<kndex) && (kndex<=nA))   A[kndex-1] = NULL;
-      Exclude = False;
-      delete atom[atomNo];
-      atom[atomNo] = NULL;
-      Exclude = True;
-      return 1;
-    }
-  }
-
-  return 0;
-
-}
-
-
-int  CResidue::DeleteAllAtoms()  {
-int     i,k,nA,kndex;
-PPCAtom A;
-
-  Exclude = False;
-
-  A  = NULL;
-  nA = 0;
-  if (chain)  {
-    if (chain->model)  {
-      A  = chain->model->GetAllAtoms();
-      nA = chain->model->GetNumberOfAllAtoms();
-    }
-  }
-
-  k = 0;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      k++;
-      kndex = atom[i]->index;
-      if ((0<kndex) && (kndex<=nA))  A[kndex-1] = NULL;
-      delete atom[i];
-      atom[i] = NULL;
-    }
-  nAtoms  = 0;
-
-  Exclude = True;
-
-  return k;
-
-}
-
-
-int CResidue::DeleteAltLocs()  {
-//   This function leaves only alternative location with maximal
-// occupancy, if those are equal or unspecified, the one with
-// "least" alternative location indicator.
-//   The function returns the number of deleted atoms. The atom
-// table remains untrimmed, so that nAtoms are wrong until that
-// is done. Tables are trimmed by FinishStructEdit() or
-// explicitely.
-PPCAtom  A;
-AtomName aname;
-AltLoc   aLoc,aL;
-realtype occupancy,occ;
-int      nA,i,i1,i2,j,k,n,kndex;
-
-  A  = NULL;
-  nA = 0;
-  if (chain)  {
-    if (chain->model)  {
-      A  = chain->model->GetAllAtoms();
-      nA = chain->model->GetNumberOfAllAtoms();
-    }
-  }
-  Exclude = False;
-
-  n = 0;
-  for (i=0;i<nAtoms;i++)
-
-    if (atom[i])  {
-      if (!atom[i]->Ter)  {
-        occupancy = atom[i]->GetOccupancy();
-        strcpy ( aname,atom[i]->name );
-        strcpy ( aLoc ,atom[i]->altLoc );
-        i1 = -1;
-        i2 = i;
-        k  = 0;
-        for (j=i+1;j<nAtoms;j++)
-          if (atom[j])  {
-            if ((!atom[j]->Ter) && (!strcmp(atom[j]->name,aname)))  {
-              k++;
-              occ = atom[j]->GetOccupancy();
-              if (occ>occupancy)  {
-                occupancy = occ;
-                i1 = j;
-              }
-              if (aLoc[0])  {
-                strcpy ( aL,atom[j]->altLoc );
-                if (!aL[0])  {
-                  aLoc[0] = char(0);
-                  i2 = j;
-                } else if (strcmp(aL,aLoc)<0)  {
-                  strcpy ( aLoc,aL );
-                  i2 = j;
-                }
-              }
-            }
-          }
-        if (k>0)  {
-          if (i1<0)  {
-            if (atom[i]->WhatIsSet & ASET_Occupancy)  i1 = i;
-                                                else  i1 = i2;
-          }
-          for (j=i;j<nAtoms;j++)
-            if ((j!=i1) && atom[j])  {
-              if ((!atom[j]->Ter) && (!strcmp(atom[j]->name,aname)))  {
-                n++;
-                kndex = atom[j]->index;
-                if ((0<kndex) && (kndex<=nA))  A[kndex-1] = NULL;
-                delete atom[j];
-                atom[j] = NULL;
-              }
-            }
-        }
-      }
-    }
-
-  Exclude = True;
-
-  return n;
-
-}
-
-void  CResidue::ApplyTransform ( mat44 & TMatrix )  {
-// transforms all coordinates by multiplying with matrix TMatrix
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (!atom[i]->Ter)
-        atom[i]->Transform ( TMatrix );
-    }
-}
-
-
-
-//  -----------------------------------------------------------------
-
-
-void  CResidue::MaskAtoms ( PCMask Mask )  {
-int i;
-  for (i=0;i<nAtoms;i++)
-     if (atom[i])  atom[i]->SetMask ( Mask );
-}
-
-void  CResidue::UnmaskAtoms ( PCMask Mask )  {
-int i;
-  for (i=0;i<nAtoms;i++)
-     if (atom[i])  atom[i]->RemoveMask ( Mask );
-}
-
-
-
-// -------  user-defined data handlers
-
-int  CResidue::PutUDData ( int UDDhandle, int iudd )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::putUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CResidue::PutUDData ( int UDDhandle, realtype rudd )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::putUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CResidue::PutUDData ( int UDDhandle, cpstr sudd )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::putUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CResidue::GetUDData ( int UDDhandle, int & iudd )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::getUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CResidue::GetUDData ( int UDDhandle, realtype & rudd )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::getUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CResidue::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::getUDData ( UDDhandle,sudd,maxLen );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CResidue::GetUDData ( int UDDhandle, pstr & sudd )  {
-  if (UDDhandle & UDRF_RESIDUE)
-        return  CUDData::getUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-
-#define  NOmaxdist2   12.25
-
-Boolean CResidue::isMainchainHBond ( PCResidue res ) {
-//  Test if there is main chain Hbond between PCRes1 (donor) and
-//  PCRes2 (acceptor).
-//  As defined Kabsch & Sanders
-//  This probably needs the option of supporting alternative criteria
-PCAtom   NAtom,OAtom,CAtom;
-realtype abx,aby,abz;
-realtype acx,acy,acz;
-realtype bcx,bcy,bcz;
-realtype absq,acsq,bcsq;
-
-  NAtom = GetAtom      ( "N" );
-  OAtom = res->GetAtom ( "O" );
-  CAtom = res->GetAtom ( "C" );
-
-  if (NAtom && OAtom && CAtom)  {
-
-    abx = OAtom->x - NAtom->x;
-    aby = OAtom->y - NAtom->y;
-    abz = OAtom->z - NAtom->z;
-    absq = abx*abx + aby*aby + abz*abz;
-
-
-    if (absq<=NOmaxdist2)  {
-
-      acx = NAtom->x - CAtom->x;
-      acy = NAtom->y - CAtom->y;
-      acz = NAtom->z - CAtom->z;
-
-      bcx = CAtom->x - OAtom->x;
-      bcy = CAtom->y - OAtom->y;
-      bcz = CAtom->z - OAtom->z;
-
-      acsq = acx*acx + acy*acy + acz*acz;
-      bcsq = bcx*bcx + bcy*bcy + bcz*bcz;
-
-      return (acos((bcsq+absq-acsq)/(2.0*sqrt(bcsq*absq)))>=Pi/2.0);
-
-    }
-
-  }
-
-  return  False;
-
-}
-
-
-void  CResidue::write ( RCFile f )  {
-int  i;
-byte Version=2;
-
-  CUDData::write ( f );
-
-  f.WriteByte    ( &Version         );
-  f.WriteInt     ( &seqNum          );
-  f.WriteInt     ( &label_seq_id    );
-  f.WriteInt     ( &label_entity_id );
-  f.WriteInt     ( &index           );
-  f.WriteInt     ( &nAtoms          );
-  f.WriteByte    ( &SSE             );
-  f.WriteTerLine ( name         ,False );
-  f.WriteTerLine ( label_comp_id,False );
-  f.WriteTerLine ( label_asym_id,False );
-  f.WriteTerLine ( insCode      ,False );
-  for (i=0;i<nAtoms;i++)
-    f.WriteInt ( &(atom[i]->index) );
-
-}
-
-void  CResidue::read ( RCFile f ) {
-//   IMPORTANT: array Atom in CMMDBFile class should be
-// read prior calling this function!
-PPCAtom A;
-int     i,k;
-byte    Version;
-
-  FreeMemory ();
-
-  CUDData::read ( f );
-
-  f.ReadByte    ( &Version );
-  f.ReadInt     ( &seqNum  );
-  if (Version>1)  {
-    f.ReadInt ( &label_seq_id    );
-    f.ReadInt ( &label_entity_id );
-  }
-  f.ReadInt     ( &index   );
-  f.ReadInt     ( &nAtoms  );
-  f.ReadByte    ( &SSE     );
-  f.ReadTerLine ( name,False );
-  if (Version>1)  {
-    f.ReadTerLine ( label_comp_id,False );
-    f.ReadTerLine ( label_asym_id,False );
-  }
-  f.ReadTerLine ( insCode,False );
-  AtmLen = nAtoms;
-  A      = NULL;
-  if (chain) {
-    if (chain->model)
-      A = chain->model->GetAllAtoms();
-  }
-  if ((nAtoms>0) && (A))  {
-    atom = new PCAtom[nAtoms];
-    for (i=0;i<nAtoms;i++)  {
-      f.ReadInt ( &k );
-      atom[i] = A[k-1];
-      atom[i]->SetResidue ( this );
-      atom[i]->_setBonds  ( A );
-    }
-  } else  {
-    for (i=0;i<nAtoms;i++)
-      f.ReadInt ( &k );
-    nAtoms = 0;
-    AtmLen = 0;
-  }
-}
-
-
-MakeFactoryFunctions(CResidue)
-
diff --git a/mmdb/mmdb_atom.h b/mmdb/mmdb_atom.h
deleted file mode 100755
index 66cab38..0000000
--- a/mmdb/mmdb_atom.h
+++ /dev/null
@@ -1,739 +0,0 @@
-//  $Id: mmdb_atom.h,v 1.30 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    06.02.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Atom <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CAtom     ( atom class    )
-//       ~~~~~~~~~  CResidue  ( residue class )
-//  **** Functions: BondAngle
-//       ~~~~~~~~~~
-//
-//  Copyright (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Atom__
-#define __MMDB_Atom__
-
-
-#ifndef  __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_UDData__
-#include "mmdb_uddata.h"
-#endif
-
-#ifndef  __MMDB_Utils__
-#include "mmdb_utils.h"
-#endif
-
-
-//  ======================  CAtom  ==========================
-
-
-// constants for the WhatIsSet field
-#define  ASET_Coordinates   0x00000001
-#define  ASET_Occupancy     0x00000002
-#define  ASET_tempFactor    0x00000004
-#define  ASET_CoordSigma    0x00000010
-#define  ASET_OccSigma      0x00000020
-#define  ASET_tFacSigma     0x00000040
-#define  ASET_Anis_tFac     0x00000100
-#define  ASET_Anis_tFSigma  0x00001000
-#define  ASET_Charge        0x00000080
-#define  ASET_All           0x000FFFFF
-
-
-#define  ATOM_NoSeqNum      MinInt4
-
-extern Boolean  ignoreSegID;
-extern Boolean  ignoreElement;
-extern Boolean  ignoreCharge;
-extern Boolean  ignoreNonCoorPDBErrors;
-extern Boolean  ignoreUnmatch;
-
-
-DefineStructure(SAtomStat)
-
-struct SAtomStat  {
-
-  public :
-    int       nAtoms;          // number of atoms in statistics
-
-    realtype  xmin,ymin,zmin;  // minimums of coordinates
-    realtype  xmax,ymax,zmax;  // maximums of coordinates
-    realtype  xm  ,ym  ,zm;    // mediums  of coordinates
-    realtype  xm2 ,ym2 ,zm2;   // square mediums of coordinates
-
-    realtype  occ_min,occ_max; // minimum/maximum occupancy
-    realtype  occ_m  ,occ_m2;  // medium and square medium occupancy
-
-    realtype  tFmin,tFmax;     // minimum/maximum temperature factor
-    realtype  tFm  ,tFm2;      // medium and sq. med. temp. factor
-
-    realtype  u11_min,u11_max; // minimums and
-    realtype  u22_min,u22_max; //   maximums of
-    realtype  u33_min,u33_max; //     anisotropic
-    realtype  u12_min,u12_max; //       temperature
-    realtype  u13_min,u13_max; //         factors
-    realtype  u23_min,u23_max;
-
-    realtype  u11_m,u11_m2;    // mediums and
-    realtype  u22_m,u22_m2;    //   square mediums of
-    realtype  u33_m,u33_m2;    //     anisotropic
-    realtype  u12_m,u12_m2;    //       temperature
-    realtype  u13_m,u13_m2;    //         factors
-    realtype  u23_m,u23_m2;
-
-    word      WhatIsSet;       //   mask field
-
-    void  Init  ();
-    void  Finish();
-
-    realtype GetMaxSize();
-
-  private :
-    Boolean finished;
-
-};
-
-
-DefineStructure(SAtomBondI)
-
-struct SAtomBondI  {
-  int  index;  //!< bonded atom index
-  byte order;  //!< bond order
-};
-
-
-DefineStructure(SAtomBond)
-
-struct SAtomBond  {
-  PCAtom atom;  //!< bonded atom pointer
-  byte  order;  //!< bond order
-};
-
-
-DefineFactoryFunctions(CAtom)
-
-class CAtom : public CUDData  {
-
-  friend class CResidue;
-  friend class CModel;
-  friend class CMMDBFile;
-  friend class CMMDBCoorManager;
-  friend class CMMDBSelManager;
-
-  public :
-
-    int        serNum;         //!< serial number
-    AtomName   name;           //!< atom name (ALIGNED)
-    AtomName   label_atom_id;  //!< assigned atom name (not aligned)
-    AltLoc     altLoc; //!< alternative location indicator ("" for none)
-    SegID      segID;          //!< segment identifier
-    Element    element;        //!< element symbol (ALIGNED TO RIGHT)
-    EnergyType energyType;     //!< energy type (without spaces)
-    PCResidue  residue;        //!< reference to residue
-    realtype   x,y,z;          //!< orthogonal coordinates in angstroms
-    realtype   occupancy;      //!< occupancy
-    realtype   tempFactor;     //!< temperature factor
-    realtype   charge;         //!< charge on the atom
-    realtype   sigX,sigY,sigZ; //!< standard deviations of the coords
-    realtype   sigOcc;         //!< standard deviation of occupancy
-    realtype   sigTemp;        //!< standard deviation of temp. factor
-    realtype   u11,u22,u33;    //!< anisotropic temperature
-    realtype   u12,u13,u23;    ///    factors
-    realtype   su11,su22,su33; //!< standard deviations of
-    realtype   su12,su13,su23; ///    anisotropic temperature factors
-    Boolean    Het;            //!< indicator of het atom
-    Boolean    Ter;            //!< chain terminator
-
-    word       WhatIsSet;      //!<   mask      field
-                       ///  0x0001   atomic coordinates
-                       ///  0x0002   occupancy
-                       ///  0x0004   temperature factor
-                       ///  0x0010   coordinate standard deviations
-                       ///  0x0020   deviation of occupancy
-                       ///  0x0040   deviation of temperature factor
-                       ///  0x0100   anisotropic temperature factors
-                       ///  0x1000   anis. temp. fact-s st-d deviations
-
-    CAtom ();
-    CAtom ( PCResidue res    );
-    CAtom ( RPCStream Object );
-    ~CAtom();
-
-    void  SetResidue   ( PCResidue   res );
-    void  PDBASCIIDump ( RCFile      f   );
-    void  MakeCIF      ( PCMMCIFData CIF );
-
-    //    AddBond(...) adds a bond to the atom, that is a pointer
-    //  to the bonded atom and the bond order. nAdd_bonds allows
-    //  one to minimize the memory reallocations, if number of
-    //  bonds is known apriori: CAtom adds space for nAdd_bonds
-    //  if currently allocated space is exchausted.
-    //    Return:  <=0  - error: bond_atom is already "bonded"
-    //              >0  - Ok, returns current number of bonds
-    int   AddBond  ( PCAtom bond_atom, int bond_order,
-                                       int nAdd_bonds=1 );
-    int   GetNBonds();
-
-    //    This GetBonds(..) returns pointer to the CAtom's
-    //  internal Bond structure, IT MUST NOT BE DISPOSED.
-    void  GetBonds ( RPSAtomBond AtomBond, int & nAtomBonds );
-    void  FreeBonds();
-
-    //    This GetBonds(..) disposes AtomBondI, if it was not set
-    //  to NULL, allocates AtomBondI[nAtomBonds] and returns its
-    //  pointer. AtomBondI MUST BE DISPOSED BY APPLICATION.
-    void  GetBonds ( RPSAtomBondI AtomBondI, int & nAtomBonds );
-
-    //    This GetBonds(..) does not dispose or allocate AtomBondI.
-    //  It is assumed that length of AtomBondI is sufficient to
-    //  accomodate all bonded atoms.
-    void  GetBonds ( PSAtomBondI AtomBondI, int & nAtomBonds,
-                     int maxlength );
-
-
-    //   ConvertPDBxxxxxx() gets data from the PDB ASCII xxxxxx
-    // record (xxxxxx stands for ATOM, SIGATM, ANISOU, SIGUIJ,
-    // TER or HETATM).
-    //   These functions DO NOT check the xxxxxx keyword and
-    // do not decode the chain and residue parameters! These
-    // must be treated by the calling process, see
-    // CMMDBFile::ReadPDBAtom().
-    //   The atom reference is updated in the corresponding
-    // residue.
-    int ConvertPDBATOM   ( int ix, cpstr S );
-    int ConvertPDBSIGATM ( int ix, cpstr S );
-    int ConvertPDBANISOU ( int ix, cpstr S );
-    int ConvertPDBSIGUIJ ( int ix, cpstr S );
-    int ConvertPDBTER    ( int ix, cpstr S );
-    int ConvertPDBHETATM ( int ix, cpstr S );
-
-    int GetCIF           ( int ix, PCMMCIFLoop Loop,
-                           PCMMCIFLoop LoopAnis );
-
-    Boolean RestoreElementName();
-    Boolean MakePDBAtomName();
-
-    void  SetAtomName    ( int            ix,      // index
-                           int            sN,      // serial number
-                           const AtomName aName,   // atom name
-                           const AltLoc   aLoc, // alternative location
-                           const SegID    sID,     // segment ID
-                           const Element  eName ); // element name
-
-    //  This only renames the atom
-    void  SetAtomName    ( const AtomName atomName );
-    void  SetElementName ( const Element  elName   );
-    void  SetCharge      ( cpstr          chrg     );
-    void  SetCharge      ( realtype       chrg     );
-
-    void  SetAtomIndex   ( int ix ); // don't use in your applications!
-
-    void  MakeTer();  // converts atom into 'ter'
-
-    void  SetCoordinates ( realtype xx,  realtype yy, realtype zz,
-                           realtype occ, realtype tFac );
-
-    int   GetModelNum       ();
-    pstr  GetChainID        ();
-    pstr  GetLabelAsymID    ();
-    pstr  GetResName        ();
-    pstr  GetLabelCompID    ();
-    int   GetAASimilarity   ( const ResName resName );
-    int   GetAASimilarity   ( PCAtom  A );
-    realtype GetAAHydropathy();
-    realtype GetOccupancy   ();
-    int   GetSeqNum         ();
-    int   GetLabelSeqID     ();
-    int   GetLabelEntityID  ();
-    pstr  GetInsCode        ();
-    int   GetSSEType        ();  // works only after SSE calculations
-    pstr  GetAtomName       () { return name;    }
-    pstr  GetElementName    () { return element; }
-    pstr  GetAtomCharge     ( pstr chrg );
-
-    //   GetChainCalphas(...) is a specialized function for quick
-    // access to C-alphas of chain which includes given atom.
-    // This function works faster than an equivalent implementation
-    // through MMDB's selection procedures.
-    //    Parameters:
-    //       Calphas   - array to accept pointers on C-alpha atoms
-    //                  If Calphas!=NULL, then the function will
-    //                  delete and re-allocate it. When the array
-    //                  is no longer needed, the application MUST
-    //                  delete it:  delete[] Calphas; Deleting
-    //                  Calphas does not delete atoms from MMDB.
-    //       nCalphas   - integer to accept number of C-alpha atoms
-    //                  and the length of Calphas array.
-    //       altLoc     - alternative location indicator. By default
-    //                  (""), maximum-occupancy locations are taken.
-    void  GetChainCalphas ( PPCAtom & Calphas, int & nCalphas,
-                            cpstr altLoc = "" );
-
-    Boolean isTer         () { return Ter; }
-    Boolean isMetal       ();
-    Boolean isSolvent     ();  // works only for atom in a residue!
-    Boolean isInSelection ( int selHnd );
-    Boolean isNTerminus   ();
-    Boolean isCTerminus   ();
-
-    void  CalcAtomStatistics ( RSAtomStat AS );
-
-    realtype GetDist2 ( PCAtom a );
-    realtype GetDist2 ( PCAtom a, mat44 & tm );  // tm applies to A
-    realtype GetDist2 ( PCAtom a, mat33 & r, vect3 & t );// tm applies to A
-    realtype GetDist2 ( realtype ax, realtype ay, realtype az );
-
-    // GetCosine(a1,a2) calculates cosine of angle a1-this-a2,
-    // i.e. that between vectors [a1,this] and [this,a2].
-    realtype GetCosine ( PCAtom a1, PCAtom a2 );
-
-    PCResidue GetResidue  ();
-    PCChain   GetChain    ();
-    PCModel   GetModel    ();
-    int       GetResidueNo();
-    void *    GetCoordHierarchy();  // PCMMDBFile
-
-    //  GetAtomID(..) generates atom ID in the form
-    //     /m/c/r(rn).i/n[e]:a
-    //  where  m  - model number
-    //         c  - chain ID
-    //         r  - residue sequence number
-    //         rn - residue name
-    //         i  - insertion code
-    //         n  - atom name
-    //         e  - chemical element specification
-    //         a  - alternate location indicator
-    //  If any of the fields is undefined, it is replaced by
-    //  hyphen  '-'.
-    //    No checks on the sufficiency of string buffer AtomID
-    //  is made.
-    //    GetAtomID returns AtomID.
-    pstr  GetAtomID ( pstr AtomID );
-
-    pstr  GetAtomIDfmt ( pstr AtomID );
-
-    // -------  checking atom ID
-    // CheckID(..) returns 1 if atom is identified, and 0 otherwise.
-    //   Parameters:
-    //     aname   - atom name. It may or may not be aligned (as in
-    //               a PDB file), only first word of the name will
-    //               be taken ("CA", " CA" and " CA B" are all
-    //               considered as "CA"). aname may be set to NULL
-    //               or '*', then this parameter is ignored.
-    //     elname  - element code. It will work only if element code
-    //               is supplied (which might not be the case if
-    //               the atom was created in a tricky way). elname
-    //               should be used to distinguih between, e.g.
-    //               "Ca" and "C_alpha"). elname may be set to NULL,
-    //               or '*', then this parameter is ignored.
-    //     aloc    - the alternate location code. aloc may be set to
-    //               NULL or '*', then this parameter is ignored.
-    //  IMPORTANT: comparison is case-sensitive.
-    //  The atom is considered as identified, if all non-NULL
-    //  parameters do match. If all parameters are set NULL, any atom
-    //  is identified.
-    //  DEFAULT values correspond to 'any element' and
-    //                 'no alternate location code'
-    //  NOTE that " " is not an empty item.
-    int   CheckID ( const AtomName aname, const Element elname=NULL,
-                    const AltLoc aloc=pstr("") );
-
-    // CheckIDS(..) works exactly like CheckID(..), but it takes
-    // the only parameter, the atom ID, which is of the form:
-    //    {name} {[element]} {:altcode}
-    // Here {} means that the item may be omitted. Any item may be
-    // represented by a wildcard '*', which means 'any value'. Just
-    // absence of an item means 'empty', which makes sense only for
-    // alternate location code. Missing name or element therefore
-    // mean 'any name' or 'any element', correspondingly (same as a
-    // wildcard). There should be no spaces in ID except for leading
-    // spaces; any following space will terminate parsing.
-    // The followings are perfectly valid IDs:
-    //   CA[C]:A     (carbon C_alpha in location A)
-    //   CA[*]:A     (either C_alpha or Ca in location A)
-    //   CA:A        (same as above)
-    //   CA          (either C_alpha or Ca with no location indicator)
-    //   CA[]        (same as above)
-    //   CA[C]:      (C_alpha with no location indicator)
-    //   [C]         (any carbon with no location indicator)
-    //   [C]:*       (any carbon with any location indicator)
-    //   *[C]:*      (same as above)
-    //   :A          (any atom in location A)
-    //   *[*]:A      (same as above)
-    //   *[*]:*      (any atom)
-    //   *           (any atom with no alternate location indicator)
-    int   CheckIDS ( cpstr ID );
-
-
-    // -------  transform coordinates: x := m*x + v
-    void  Transform     ( mat33 & tm, vect3 & v );
-    void  Transform     ( mat44 & tm );
-    void  TransformCopy ( mat44 & tm,
-                         realtype & xx, realtype & yy, realtype & zz );
-    void  TransformSet  ( mat44 & tm,
-                          realtype xx, realtype yy, realtype zz );
-
-
-    // -------  user-defined data handlers
-    int   PutUDData ( int UDDhandle, int      iudd );
-    int   PutUDData ( int UDDhandle, realtype rudd );
-    int   PutUDData ( int UDDhandle, cpstr    sudd );
-
-    int   GetUDData ( int UDDhandle, int      & iudd );
-    int   GetUDData ( int UDDhandle, realtype & rudd );
-    int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
-    int   GetUDData ( int UDDhandle, pstr     & sudd );
-
-
-    int   GetIndex()  { return index; }
-
-    virtual void Copy ( PCAtom atom );  // without references in
-                                        // residues
-
-    void  SetShortBinary();  // leaves only coordinates in binary files
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    int        index;   // index in the file
-    int        nBonds;  // number of bonds in the lowest byte (!)
-    PSAtomBond Bond;    // atom bonds
-
-    void  InitAtom       ();
-    void  FreeMemory     ();
-    void  StandardPDBOut ( cpstr Record, pstr S );
-    void  GetData        ( cpstr S );
-    int   CheckData      ( cpstr S );
-    void  GetStat        ( realtype   v,
-                           realtype & v_min, realtype & v_max,
-                           realtype & v_m,   realtype & v_m2 );
-    void  _setBonds ( PPCAtom A ); // used only in CResidue
-
-};
-
-
-//  ======================  CResidue  ==========================
-
-#define ALF_NoAltCodes    0x00000000
-#define ALF_EmptyAltLoc   0x00000001
-#define ALF_NoEmptyAltLoc 0x00000002
-#define ALF_Mess          0x00000004
-#define ALF_Occupancy     0x00000008
-
-#define SSE_None          0
-#define SSE_Strand        1
-#define SSE_Bulge         2
-#define SSE_3Turn         3
-#define SSE_4Turn         4
-#define SSE_5Turn         5
-#define SSE_Helix         6
-
-
-DefineFactoryFunctions(CResidue)
-
-class CResidue : public CUDData  {
-
-  friend class CAtom;
-  friend class CChain;
-  friend class CMMDBFile;
-
-  public :
-
-    ResName  name;            //!< residue name - all spaces cut
-    ResName  label_comp_id;   //!< assigned residue name
-    ChainID  label_asym_id;   //!< assigned chain Id
-    InsCode  insCode;         //!< residue insertion code
-    PCChain  chain;           //!< reference to chain
-    PPCAtom  atom;            //!< array of atoms
-    int      seqNum;          //!< residue sequence number
-    int      label_seq_id;    //!< assigned residue sequence number
-    int      label_entity_id; //!< assigned entity id
-    int      index;           //!< index in the chain
-    int      nAtoms;          //!< number of atoms in the residue
-    byte     SSE;             //!< SSE type
-
-    CResidue ();
-    CResidue ( PCChain Chain_Owner );
-    CResidue ( PCChain Chain_Owner, const ResName resName,
-               int     sqNum,       const InsCode ins );
-    CResidue ( RPCStream Object    );
-    ~CResidue();
-
-    void  SetChain ( PCChain Chain_Owner );
-    void  SetResID ( const ResName resName, int sqNum,
-                     const InsCode ins );
-    void  SetChainID ( const ChainID chID );
-
-    void  PDBASCIIAtomDump ( RCFile f        );
-    void  MakeAtomCIF      ( PCMMCIFData CIF );
-
-    PCChain GetChain();
-    PCModel GetModel();
-
-    int   GetModelNum   ();
-    pstr  GetChainID    ();
-    pstr  GetLabelAsymID();
-    pstr  GetResName    ();
-    pstr  GetLabelCompID();
-    int   GetAASimilarity ( const ResName resName );
-    int   GetAASimilarity ( PCResidue res );
-    realtype GetAAHydropathy();
-    void  SetResName      ( const ResName resName );
-    int   GetSeqNum       ();
-    int   GetLabelSeqID   ();
-    int   GetLabelEntityID();
-    pstr  GetInsCode      ();
-    int   GetResidueNo    ();
-    int   GetCenter       ( realtype & x, realtype & y, realtype & z );
-    void * GetCoordHierarchy();  // PCMMDBFile
-
-    void  GetAtomStatistics  ( RSAtomStat AS );
-    void  CalcAtomStatistics ( RSAtomStat AS );
-
-    pstr  GetResidueID ( pstr ResidueID );
-
-    //   GetAltLocations(..) returns the number of different
-    // alternative locations in nAltLocs, the locations themselves
-    // - in aLoc and the corresponding occupancies - in occupancy.
-    //   aLoc and occupancy are allocated dynamically; it is
-    // responsibility of the application to deallocate aLoc prior
-    // calling GetAltLocations(..) if they were previously allocated.
-    // Either, the application is responsible for deallocating aLoc and
-    // occupancy after use.
-    //   occupancy[i] may return -1.0 if occupancies were not read
-    // from coordinate file.
-    //   alflag returns ALF_NoAltCodes if no alt codes was found,
-    // otherwise the output is decoded according to bits:
-    //   ALF_EmptyAltLoc   alternative locations include the
-    //                     "no alt loc indicator" ("" for
-    //                     CAtom::altLoc).
-    //                     This means that each atom that has alt locs
-    //                     different of "", also includes one marked as
-    //                     "".
-    //  ALF_NoEmptyAltLoc  alternative locations do not include the
-    //                     "no alt loc indicator" ("" for
-    //                     CAtom::altLoc).
-    //                     This means that each atom has either ""
-    //                     alt loc or at least two alt locs different
-    //                     of "".
-    //  ALF_Mess           incorrect residue: it mixes both
-    //                     ""-including and not-""-including schemes
-    //  ALF_Occupancy      warning that sum of occupancies for alt
-    //                     located atoms differ from 1.0 by more
-    //                     than 0.01.
-    void  GetAltLocations   ( int & nAltLocs, PAltLoc & aLoc,
-                              rvector & occupancy, int & alflag );
-    int   GetNofAltLocations();
-
-    Boolean isAminoacid   ();
-    Boolean isNucleotide  ();
-    int     isDNARNA      (); // 0(neither),1(DNA),2(RNA)
-    Boolean isSugar       ();
-    Boolean isSolvent     ();
-    Boolean isModRes      ();
-    Boolean isInSelection ( int selHnd );
-    Boolean isNTerminus   ();
-    Boolean isCTerminus   ();
-
-    // -------  checking residue ID
-    // CheckID(..) returns 1 if residue is identified, and 0 otherwise.
-    //   Parameters:
-    //     sname   - pointer to sequence number; if NULL then ignored.
-    //     inscode - insertion code; if NULL or '*' then ignored.
-    //     resname - residue name; if NULL or '*' then ignored.
-    //  IMPORTANT: comparison is case-sensitive.
-    //  The residue is considered as identified, if all non-NULL
-    //  parameters do match. If all parameters are set NULL, any
-    //  residue is identified.
-    //  DEFAULT values correspond to 'any residue name' and
-    //                 'no insertion code'
-    //  NOTE that " " is not an empty item.
-    int   CheckID ( int * snum, const InsCode inscode=pstr(""),
-                    const ResName resname=NULL );
-
-    // CheckIDS(..) works exactly like CheckID(..), but it takes
-    // the only parameter, the residue ID, which is of the form:
-    //    {seqnum} {(name)} {.inscode}
-    // Here {} means that the item may be omitted. Any item may be
-    // represented by a wildcard '*', which means 'any value'. Just
-    // absence of a value means 'empty', which is meaningful only for
-    // the insertion code. Missing sequence number or residue name
-    // therefore mean 'any sequence number' or 'any residue name',
-    // correspondingly (same as a wildcard).  There should be no
-    // spaces in ID except for leading spaces; any following space will
-    // terminate parsing. The followings are perfectly valid IDs:
-    //        27(ALA).A   (residue 27A ALA)
-    //        27().A      (residue 27A)
-    //        27(*).A     (same as above)
-    //        27.A        (same as above)
-    //        27          (residue 27)
-    //        27().       (same as above)
-    //        (ALA)       (any ALA without insertion code)
-    //        (ALA).      (same as above)
-    //        (ALA).*     (any ALA)
-    //        *(ALA).*    (any ALA)
-    //        .A          (any residue with insertion code A)
-    //        *(*).A      (same as above)
-    //        *(*).*      (any residue)
-    //        *           (any residue with no insertion code)
-    int  CheckIDS ( cpstr ID );
-
-
-    //  --------------------  Extracting atoms  ----------------------
-
-    int  GetNumberOfAtoms ();
-    int  GetNumberOfAtoms ( Boolean countTers );
-
-    PCAtom GetAtom ( const AtomName aname, const Element elname=NULL,
-                     const AltLoc aloc=cpstr("") );
-    PCAtom GetAtom ( int atomNo );
-
-    void GetAtomTable  ( PPCAtom & atomTable, int & NumberOfAtoms );
-
-    //   GetAtomTable1(..) returns atom table without TER atoms and
-    // without NULL atom pointers. NumberOfAtoms returns the actual
-    // number of atom pointers in atomTable.
-    //   atomTable is allocated withing the function. If it was
-    // not set to NULL before calling the function, the latter will
-    // attempt to deallocate it first.
-    //   The application is responsible for deleting atomTable,
-    // however it must not touch atom pointers, i.e. use simply
-    // "delete[] atomTable;". Never pass atomTable from GetAtomTable()
-    // into this function, unless you set it to NULL before doing that.
-    void GetAtomTable1 ( PPCAtom & atomTable, int & NumberOfAtoms );
-
-
-    //  ---------------------  Deleting atoms  -----------------------
-
-    int  DeleteAtom ( const AtomName aname, const Element elname=NULL,
-                      const AltLoc aloc=cpstr("") );
-    int  DeleteAtom ( int atomNo );
-    int  DeleteAllAtoms();
-
-    //   DeleteAltLocs() leaves only alternative location with maximal
-    // occupancy, if those are equal or unspecified, the one with
-    // "least" alternative location indicator.
-    //   The function returns the number of deleted atoms. The atom
-    // table remains untrimmed, so that nAtoms are wrong until that
-    // is done. Tables are trimmed by FinishStructEdit() or
-    // explicitely.
-    int  DeleteAltLocs ();
-
-    void TrimAtomTable ();
-
-    //  ----------------------  Adding atoms  ------------------------
-
-    //   AddAtom(..) adds atom to the residue. If residue is associated
-    // with a coordinate hierarchy, and atom 'atm' is not, the latter
-    // is checked in automatically. If atom 'atm' belongs to any
-    // coordinate hierarchy (even though that of the residue), it is
-    // *copied* rather than simply taken over, and is checked in.
-    //   If residue is not associated with a coordinate hierarchy, all
-    // added atoms will be checked in automatically once the residue
-    // is checked in.
-    int  AddAtom ( PCAtom atm );
-
-    //   InsertAtom(..) inserts atom into the specified position of
-    // the residue. If residue is associated with a coordinate
-    // hierarchy, and atom 'atm' is not, the latter is checked in
-    // automatically. If atom 'atm' belongs to any coordinate
-    // hierarchy (even though that of the residue), it is *copied*
-    // rather than simply taken over, and is checked in.
-    //   If residue is not associated with a coordinate hierarchy, all
-    // added atoms will be checked in automatically once the residue
-    // is checked in.
-    int  InsertAtom ( PCAtom atm, int position );
-
-    //   This version inserts before the atom with given name. If such
-    // name is not found, the atom is appended to the end.
-    int  InsertAtom ( PCAtom atm, const AtomName aname );
-
-    //  --------------------------------------------------------------
-
-    void  ApplyTransform ( mat44 & TMatrix );  // transforms all
-                                               // coordinates by
-                                               // multiplying with
-                                               // matrix TMatrix
-
-    void  MaskAtoms   ( PCMask Mask );
-    void  UnmaskAtoms ( PCMask Mask );
-
-
-    // -------  user-defined data handlers
-    int   PutUDData ( int UDDhandle, int      iudd );
-    int   PutUDData ( int UDDhandle, realtype rudd );
-    int   PutUDData ( int UDDhandle, cpstr    sudd );
-
-    int   GetUDData ( int UDDhandle, int      & iudd );
-    int   GetUDData ( int UDDhandle, realtype & rudd );
-    int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
-    int   GetUDData ( int UDDhandle, pstr     & sudd );
-
-
-    Boolean isMainchainHBond ( PCResidue res );
-
-    void  Copy  ( PCResidue res );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    int      AtmLen;   // length of atom array
-    Boolean  Exclude;  // used internally
-
-    void  InitResidue  ();
-    void  FreeMemory   ();
-    int   _AddAtom     ( PCAtom atm );
-    int   _ExcludeAtom ( int  kndex );  // 1: residue gets empty,
-                                        // 0 otherwise
-    void  _copy ( PCResidue res );
-    void  _copy ( PCResidue res, PPCAtom atm, int & atom_index );
-    void  ExpandAtomArray ( int nAdd );
-    void  CheckInAtoms ();
-
-};
-
-
-extern realtype  BondAngle ( PCAtom A, PCAtom B, PCAtom C );
-
-
-#endif
-
diff --git a/mmdb/mmdb_bondmngr.cpp b/mmdb/mmdb_bondmngr.cpp
deleted file mode 100755
index 69afa73..0000000
--- a/mmdb/mmdb_bondmngr.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-//  $Id: mmdb_bondmngr.cpp,v 1.21 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_bondmngr  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBBondManager ( MMDB bonds maker )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MMDB_BondMngr__
-#include "mmdb_bondmngr.h"
-#endif
-
-#ifndef  __MMDB_Graph__
-#include "mmdb_graph.h"
-#endif
-
-
-//  =====================   CMMDBBondManager   =====================
-
-CMMDBBondManager::CMMDBBondManager() : CMMDBSelManager()  {
-}
-
-CMMDBBondManager::CMMDBBondManager ( RPCStream Object )
-                : CMMDBSelManager(Object)  {
-}
-
-CMMDBBondManager::~CMMDBBondManager()  {}
-
-void  CMMDBBondManager::MakeBonds ( Boolean calc_only )  {
-UNUSED_ARGUMENT(calc_only);
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-CGraph    graph;
-PPCVertex V;
-PPCEdge   E;
-int       i, im,ic,ir, nV,nE, k1,k2;
-
-  RemoveBonds();
-
-  for (im=0;im<nModels;im++)  {
-    model = Model[im];
-    if (model)
-      for (ic=0;ic<model->nChains;ic++)  {
-        chain = model->Chain[ic];
-        if (chain)
-          for (ir=0;ir<chain->nResidues;ir++)  {
-            res = chain->Residue[ir];
-            if (res)  {
-              graph.MakeGraph   ( res,NULL );
-              graph.GetVertices ( V,nV );
-              graph.GetEdges    ( E,nE );
-              for (i=0;i<nE;i++)  {
-                k1 = V[E[i]->GetVertex1()]->GetUserID();
-                k2 = V[E[i]->GetVertex2()]->GetUserID();
-                res->atom[k1]->AddBond ( res->atom[k2],E[i]->GetType() );
-                res->atom[k2]->AddBond ( res->atom[k1],E[i]->GetType() );
-              }
-            }
-          }
-      }
-  }
-
-}
-
-void  CMMDBBondManager::RemoveBonds()  {
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])
-      Atom[i]->FreeBonds();
-}
-
-//  -------------------  Stream functions  ----------------------
-
-void  CMMDBBondManager::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CMMDBSelManager::write ( f );
-}
-
-void  CMMDBBondManager::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CMMDBSelManager::read ( f );
-}
-
-
-MakeStreamFunctions(CMMDBBondManager)
diff --git a/mmdb/mmdb_chain.cpp b/mmdb/mmdb_chain.cpp
deleted file mode 100755
index 137b5ce..0000000
--- a/mmdb/mmdb_chain.cpp
+++ /dev/null
@@ -1,2568 +0,0 @@
-//  $Id: mmdb_chain.cpp,v 1.25 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    14.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Chain  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CChainContainer ( container for in-chain classes  )
-//       ~~~~~~~~~  CContainerChain ( chain containered class template)
-//                  CDBReference    ( DBREF  records                  )
-//                  CSeqAdv         ( SEQADV records                  )
-//                  CSeqRes         ( SEQRES records                  )
-//                  CModRes         ( MODRES records                  )
-//                  CHetRec         ( HET    records                  )
-//                  CChain          ( MMDB chain class                )
-//
-//  Copyright (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MMDB_Chain__
-#include "mmdb_chain.h"
-#endif
-
-#ifndef  __MMDB_Model__
-#include "mmdb_model.h"
-#endif
-
-#ifndef  __MMDB_File__
-#include "mmdb_file.h"
-#endif
-
-#ifndef  __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-//  ==================  CProModel  ======================
-
-MakeStreamFunctions(CProModel)
-
-//  ==============  CChainContainer  ====================
-
-PCContainerClass CChainContainer::MakeContainerClass ( int ClassID )  {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template    : return
-                                 CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_DBReference : return new CDBReference ( Chain );
-    case ClassID_SeqAdv      : return new CSeqAdv      ( Chain );
-    case ClassID_ModRes      : return new CModRes      ( Chain );
-    case ClassID_Het         : return new CHetRec      ( Chain );
-  }
-}
-
-void CChainContainer::SetChain ( PCChain Chain_Owner )  {
-int i;
-  Chain = Chain_Owner;
-  for (i=0;i<length;i++)
-    if (Container[i])
-      (void)PCContainerChain(Container[i])->SetChain ( Chain );
-}
-
-cpstr CChainContainer::Get1stChainID()  {
-int i;
-  i = 0;
-  if (Container)  {
-    while ((i<length-1) && (!Container[i])) i++;
-    if (Container[i])
-          return PCContainerChain(Container[i])->chainID;
-    else  return NULL;
-  } else
-    return NULL;
-}
-
-void CChainContainer::MoveByChainID ( const ChainID chainID,
-                                      PCChainContainer ChainContainer )  {
-int i;
-  for (i=0;i<length;i++)
-    if (Container[i])  {
-      if (!strcmp(PCContainerChain(Container[i])->chainID,chainID))  {
-        ChainContainer->AddData ( Container[i] );
-        Container[i] = NULL;
-      }
-    }
-}
-
-
-MakeStreamFunctions(CChainContainer)
-
-
-//  ================  CContainerChain  ===================
-
-CContainerChain::CContainerChain ()
-                : CContainerClass()  {
-  Chain      = NULL;
-  chainID[0] = char(0);
-}
-
-CContainerChain::CContainerChain ( PCChain Chain_Owner)
-                : CContainerClass()  {
-  Chain = Chain_Owner;
-  if (Chain)  strcpy ( chainID,Chain->GetChainID() );
-        else  chainID[0] = char(0);
-}
-
-void CContainerChain::SetChain ( PCChain Chain_Owner )  {
-  Chain = Chain_Owner;
-  if (Chain)  strcpy ( chainID,Chain->GetChainID() );
-        else  strcpy ( chainID,"" );
-}
-
-MakeStreamFunctions(CContainerChain)
-
-
-//  ================  CDBReference  ===================
-
-CDBReference::CDBReference() : CContainerChain()  {
-  InitDBReference();
-}
-
-CDBReference::CDBReference( PCChain Chain_Owner )
-            : CContainerChain(Chain_Owner)  {
-  InitDBReference();
-}
-
-CDBReference::CDBReference ( PCChain Chain_Owner, cpstr S )
-            : CContainerChain(Chain_Owner)  {
-  InitDBReference();
-  ConvertPDBASCII ( S );
-}
-
-CDBReference::CDBReference ( RPCStream Object )
-            : CContainerChain(Object)  {
-  InitDBReference();
-}
-
-CDBReference::~CDBReference() {}
-
-void  CDBReference::InitDBReference()  {
-  seqBeg = 0;
-  strcpy ( insBeg     ,"-"            );
-  seqEnd = 0;
-  strcpy ( insEnd     ,"-"            );
-  strcpy ( database   ,"------"       );
-  strcpy ( dbAccession,"--------"     );
-  strcpy ( dbIdCode   ,"------------" );
-  dbseqBeg = 0;
-  strcpy ( dbinsBeg,"-" );
-  dbseqEnd = 0;
-  strcpy ( dbinsEnd,"-" );
-}
-
-void  CDBReference::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB DBREF line number N
-//  from the class' data
-  strcpy ( S,"DBREF" );
-  PadSpaces ( S,80 );
-  strcpy_n  ( &(S[7]),Chain->GetEntryID(),4 );
-  if (Chain->chainID[0])  S[12] = Chain->chainID[0];
-  PutIntIns ( &(S[14]),seqBeg,4,insBeg     );
-  PutIntIns ( &(S[20]),seqEnd,4,insEnd     );
-  strcpy_n  ( &(S[26]),database   ,6       );
-  strcpy_n  ( &(S[33]),dbAccession,8       );
-  strcpy_n  ( &(S[42]),dbIdCode   ,12      );
-  PutIntIns ( &(S[55]),dbseqBeg,5,dbinsBeg );
-  PutIntIns ( &(S[62]),dbseqEnd,5,dbinsEnd );
-}
-
-void  CDBReference::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop1,Loop2;
-int         RC1,RC2;
-
-  RC1 = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ,Loop1 );
-  RC2 = CIF->AddLoop ( CIFCAT_STRUCT_REF    ,Loop2 );
-
-  if ((RC1!=CIFRC_Ok) || (RC2!=CIFRC_Ok))  {
-    // the category was (re)created, provide tags
-    Loop1->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE            );
-    Loop1->AddLoopTag ( CIFTAG_NDB_CHAIN_ID               );
-    Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_BEG              );
-    Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE );
-    Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_END              );
-    Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE );
-    Loop1->AddLoopTag ( CIFTAG_NDB_DB_ACCESSION           );
-    Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_BEG               );
-    Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE  );
-    Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_END               );
-    Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_END_INS_CODE  );
-    Loop2->AddLoopTag ( CIFTAG_DB_NAME );
-    Loop2->AddLoopTag ( CIFTAG_DB_CODE );
-  }
-
-  Loop1->AddString  ( Chain->GetEntryID(),True );
-  Loop1->AddString  ( Chain->chainID     ,True );
-  Loop1->AddInteger ( seqBeg                   );
-  Loop1->AddString  ( insBeg             ,True );
-  Loop1->AddInteger ( seqEnd                   );
-  Loop1->AddString  ( insEnd             ,True );
-  Loop1->AddString  ( dbAccession        ,True );
-  Loop1->AddInteger ( dbseqBeg                 );
-  Loop1->AddString  ( dbinsBeg           ,True );
-  Loop1->AddInteger ( dbseqEnd                 );
-  Loop1->AddString  ( dbinsEnd           ,True );
-
-  Loop2->AddString  ( database,True );
-  Loop2->AddString  ( dbIdCode,True );
-
-}
-
-void  CDBReference::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-//  GetCIF(..) must be always run without reference to Chain,
-//  see CModel::GetCIF(..).
-PCMMCIFLoop   Loop1,Loop2;
-PCMMCIFStruct Struct2;
-pstr          F;
-int           RC,CIFMode,ref_id1,ref_id2;
-
-  Loop1 = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ );
-
-  if (!Loop1)  {
-    Signal = -1;
-    return;
-  }
-
-  if (Signal>=Loop1->GetLoopLength())  {
-    Signal = -1;
-    return;
-  }
-
-
-  //  Determine the ChainID first and store it locally. It will
-  // be used by CModel for generating chains and placing the
-  // primary structure data BEFORE reading the coordinate section.
-  CIFMode = CIF_NDB;
-  F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),Signal,RC );
-  if ((RC) || (!F))  {
-    CIFMode = CIF_PDBX;
-    F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),Signal,RC );
-  }
-  if ((!RC) && F)  {
-    strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
-    Loop1->DeleteField ( CIFName(TAG_CHAIN_ID,CIFMode),Signal );
-  } else
-    strcpy ( chainID,"" );
-
-
-  if (CIFGetInteger(seqBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG,CIFMode),
-                    Signal))  return;
-  CIFGetString ( insBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG_INS_CODE,CIFMode),
-                 Signal,sizeof(InsCode),pstr(" ") );
-
-  if (CIFGetInteger(seqEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END,CIFMode),
-                    Signal))  return;
-  CIFGetString ( insEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END_INS_CODE,CIFMode),
-                 Signal,sizeof(InsCode),pstr(" ") );
-  CIFGetString ( dbAccession,Loop1,CIFName(TAG_DB_ACCESSION,CIFMode),
-                 Signal,sizeof(DBAcCode),pstr("        ") );
-
-  if (CIFGetInteger(dbseqBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG,CIFMode),
-                    Signal))  return;
-  CIFGetString ( dbinsBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG_INS_CODE,CIFMode),
-                 Signal,sizeof(InsCode),pstr(" ") );
-
-  if (CIFGetInteger(dbseqEnd,Loop1,CIFName(TAG_DB_ALIGN_END,CIFMode),
-                    Signal))  return;
-  CIFGetString ( dbinsEnd,Loop1,CIFName(TAG_DB_ALIGN_END_INS_CODE,CIFMode),
-                 Signal,sizeof(InsCode),pstr(" ") );
-
-  Loop2 = CIF->GetLoop ( CIFCAT_STRUCT_REF );
-  if (Loop2)  {
-    CIFGetString ( database,Loop2,CIFTAG_DB_NAME,Signal,
-                   sizeof(DBName)  ,pstr("      ")       );
-    CIFGetString ( dbIdCode,Loop2,CIFTAG_DB_CODE,Signal,
-                   sizeof(DBIdCode),pstr("            ") );
-  } else if (CIFMode==CIF_PDBX)  {
-    Struct2 = CIF->GetStructure ( CIFCAT_STRUCT_REF );
-    if (Struct2 &&
-        (!CIFGetInteger(ref_id1,Loop1,CIFTAG_REF_ID,Signal)) &&
-        (!CIFGetInteger(ref_id2,Struct2,CIFTAG_ID,False)))  {
-      if (ref_id1==ref_id2)  {
-        CIFGetString ( database,Struct2,CIFTAG_DB_NAME,
-                       sizeof(DBName)  ,pstr("      ")      ,False );
-        CIFGetString ( dbIdCode,Struct2,CIFTAG_DB_CODE,
-                       sizeof(DBIdCode),pstr("            "),False );
-      }
-    }
-  }
-
-  Signal++;
-
-}
-
-
-int CDBReference::ConvertPDBASCII ( cpstr S )  {
-IDCode idCode;
-  if (Chain->chainID[0])  {
-    if (S[12]!=Chain->chainID[0])
-      return Error_WrongChainID;
-  } else if (S[12]!=' ')  {
-    Chain->chainID[0] = S[12];
-    Chain->chainID[1] = char(0);
-  } else
-    Chain->chainID[0] = char(0);
-  strcpy ( idCode,Chain->GetEntryID() );
-  if (idCode[0])  {
-    if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
-      return Error_WrongEntryID;
-  } else  {
-    GetString ( idCode,&(S[7]),4 );
-    Chain->SetEntryID ( idCode );
-  }
-  GetIntIns  ( seqBeg,insBeg,&(S[14]),4  );
-  GetIntIns  ( seqEnd,insEnd,&(S[20]),4  );
-  strcpy_ncs ( database     ,&(S[26]),6  );
-  strcpy_ncs ( dbAccession  ,&(S[33]),8  );
-  strcpy_ncs ( dbIdCode     ,&(S[42]),12 );
-  GetIntIns  ( dbseqBeg,dbinsBeg,&(S[55]),5 );
-  GetIntIns  ( dbseqEnd,dbinsEnd,&(S[62]),5 );
-  return 0;
-}
-
-void  CDBReference::Copy ( PCContainerClass DBRef )  {
-
-  CContainerChain::Copy ( DBRef );
-
-  seqBeg   = PCDBReference(DBRef)->seqBeg;
-  seqEnd   = PCDBReference(DBRef)->seqEnd;
-  dbseqBeg = PCDBReference(DBRef)->dbseqBeg;
-  dbseqEnd = PCDBReference(DBRef)->dbseqEnd;
-  strcpy ( insBeg     ,PCDBReference(DBRef)->insBeg      );
-  strcpy ( insEnd     ,PCDBReference(DBRef)->insEnd      );
-  strcpy ( database   ,PCDBReference(DBRef)->database    );
-  strcpy ( dbAccession,PCDBReference(DBRef)->dbAccession );
-  strcpy ( dbIdCode   ,PCDBReference(DBRef)->dbIdCode    );
-  strcpy ( dbinsBeg   ,PCDBReference(DBRef)->dbinsBeg    );
-  strcpy ( dbinsEnd   ,PCDBReference(DBRef)->dbinsEnd    );
-
-}
-
-void  CDBReference::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version  );
-  f.WriteInt  ( &seqBeg   );
-  f.WriteInt  ( &seqEnd   );
-  f.WriteInt  ( &dbseqBeg );
-  f.WriteInt  ( &dbseqEnd );
-  f.WriteTerLine ( insBeg     ,False );
-  f.WriteTerLine ( insEnd     ,False );
-  f.WriteTerLine ( database   ,False );
-  f.WriteTerLine ( dbAccession,False );
-  f.WriteTerLine ( dbIdCode   ,False );
-  f.WriteTerLine ( dbinsBeg   ,False );
-  f.WriteTerLine ( dbinsEnd   ,False );
-}
-
-void  CDBReference::read  ( RCFile f ) {
-byte Version;
-  f.ReadByte ( &Version  );
-  f.ReadInt  ( &seqBeg   );
-  f.ReadInt  ( &seqEnd   );
-  f.ReadInt  ( &dbseqBeg );
-  f.ReadInt  ( &dbseqEnd );
-  f.ReadTerLine ( insBeg     ,False );
-  f.ReadTerLine ( insEnd     ,False );
-  f.ReadTerLine ( database   ,False );
-  f.ReadTerLine ( dbAccession,False );
-  f.ReadTerLine ( dbIdCode   ,False );
-  f.ReadTerLine ( dbinsBeg   ,False );
-  f.ReadTerLine ( dbinsEnd   ,False );
-}
-
-MakeStreamFunctions(CDBReference)
-
-
-
-//  ================  CSeqAdv  ===================
-
-CSeqAdv::CSeqAdv() : CContainerChain()  {
-  InitSeqAdv();
-}
-
-CSeqAdv::CSeqAdv ( PCChain Chain_Owner )
-       : CContainerChain(Chain_Owner)  {
-  InitSeqAdv();
-}
-
-CSeqAdv::CSeqAdv ( PCChain Chain_Owner, cpstr S )
-       : CContainerChain(Chain_Owner)  {
-  InitSeqAdv();
-  ConvertPDBASCII ( S );
-}
-
-CSeqAdv::CSeqAdv ( RPCStream Object ) : CContainerChain(Object)  {
-  InitSeqAdv();
-}
-
-CSeqAdv::~CSeqAdv()  {
-  if (conflict)  delete[] conflict;
-}
-
-void  CSeqAdv::InitSeqAdv()  {
-  strcpy ( resName    ,"---"       );
-  seqNum = 0;
-  strcpy ( insCode    ,"-"         );
-  strcpy ( database   ,"------"    );
-  strcpy ( dbAccession,"---------" );
-  strcpy ( dbRes      ,"---"       );
-  dbSeq = 0;
-  conflict = NULL;
-  CreateCopy ( conflict,pstr(" ") );
-}
-
-void  CSeqAdv::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB SEQADV line number N
-//  from the class' data
-  strcpy     ( S,"SEQADV" );
-  PadSpaces  ( S,80 );
-  strcpy_n   ( &(S[7]) ,Chain->GetEntryID(),4 );
-  strcpy_n   ( &(S[12]),resName      ,3 );
-  if (Chain->chainID[0])  S[16] = Chain->chainID[0];
-  PutIntIns  ( &(S[18]),seqNum,4,insCode );
-  strcpy_n   ( &(S[24]),database   ,4    );
-  strcpy_n   ( &(S[29]),dbAccession,9    );
-  strcpy_n   ( &(S[39]),dbRes      ,3    );
-  PutInteger ( &(S[43]),dbSeq      ,5    );
-  strcpy_n   ( &(S[49]),conflict,IMin(strlen(conflict),21) );
-}
-
-int CSeqAdv::ConvertPDBASCII ( cpstr S )  {
-IDCode idCode;
-  if (Chain->chainID[0])  {
-    if (S[16]!=Chain->chainID[0])
-      return Error_WrongChainID;
-  } else if (S[16]!=' ')  {
-    Chain->chainID[0] = S[16];
-    Chain->chainID[1] = char(0);
-  } else
-    Chain->chainID[0] = char(0);
-  strcpy ( idCode,Chain->GetEntryID() );
-  if (idCode[0])  {
-    if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
-      return Error_WrongEntryID;
-  } else  {
-    GetString ( idCode,&(S[7]),4 );
-    Chain->SetEntryID ( idCode );
-  }
-  strcpy_ncs ( resName       ,&(S[12]),3 );
-  GetIntIns  ( seqNum,insCode,&(S[18]),4 );
-  strcpy_ncs ( database      ,&(S[24]),4 );
-  strcpy_ncs ( dbAccession   ,&(S[29]),9 );
-  strcpy_ncs ( dbRes         ,&(S[39]),3 );
-  GetInteger ( dbSeq,&(S[43]),5  );
-  CreateCopy ( conflict,&(S[49]) );
-  CutSpaces  ( conflict,SCUTKEY_END );
-  return 0;
-}
-
-
-void  CSeqAdv::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop;
-int         RC;
-
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ_DIF,Loop );
-
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE           );
-    Loop->AddLoopTag ( CIFTAG_MON_ID                    );
-    Loop->AddLoopTag ( CIFTAG_NDB_PDB_CHAIN_ID          );
-    Loop->AddLoopTag ( CIFTAG_SEQ_NUM                   );
-    Loop->AddLoopTag ( CIFTAG_NDB_PDB_INS_CODE          );
-    Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_NAME           );
-    Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_ACCESSION_CODE );
-    Loop->AddLoopTag ( CIFTAG_DB_MON_ID                 );
-    Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_SEQ_NUM        );
-    Loop->AddLoopTag ( CIFTAG_DETAILS                   );
-  }
-
-  Loop->AddString  ( Chain->GetEntryID(),True );
-  Loop->AddString  ( resName            ,True );
-  Loop->AddString  ( Chain->chainID     ,True );
-  Loop->AddInteger ( seqNum                   );
-  Loop->AddString  ( insCode            ,True );
-  Loop->AddString  ( database           ,True );
-  Loop->AddString  ( dbAccession        ,True );
-  Loop->AddString  ( dbRes              ,True );
-  Loop->AddInteger ( dbSeq                    );
-  Loop->AddString  ( conflict           ,True );
-
-}
-
-void  CSeqAdv::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-//  GetCIF(..) must be always run without reference to Chain,
-//  see CModel::GetCIF(..).
-PCMMCIFLoop   Loop;
-pstr          F;
-int           RC;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ_DIF );
-  if (!Loop)  {
-    Signal = -1;
-    return;
-  }
-
-  if (Signal>=Loop->GetLoopLength())  {
-    Signal = -1;
-    return;
-  }
-
-  //  Determine the ChainID first and store it locally. It will
-  // be used by CModel for generating chains and placing the
-  // primary structure data BEFORE reading the coordinate section.
-
-  F = Loop->GetString ( CIFTAG_NDB_PDB_CHAIN_ID,Signal,RC );
-  if ((!RC) && F)  {
-    strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
-    Loop->DeleteField ( CIFTAG_NDB_PDB_CHAIN_ID,Signal );
-  } else
-    strcpy ( chainID,"" );
-
-  CIFGetString ( resName,Loop,CIFTAG_MON_ID,Signal,sizeof(ResName),
-                 pstr("UNK") );
-
-  CIFGetIntegerD ( seqNum,Loop,CIFTAG_SEQ_NUM );
-
-  CIFGetString ( insCode,Loop,CIFTAG_NDB_PDB_INS_CODE,
-                 Signal,sizeof(InsCode),pstr(" ") );
-
-  CIFGetString ( database,Loop,CIFTAG_NDB_SEQ_DB_NAME,Signal,
-                 sizeof(DBName),pstr(" ") );
-
-  CIFGetString ( dbAccession,Loop,CIFTAG_NDB_SEQ_DB_ACCESSION_CODE,
-                 Signal,sizeof(DBAcCode),pstr(" ") );
-
-  CIFGetString ( dbRes,Loop,CIFTAG_DB_MON_ID,Signal,sizeof(ResName),
-                 pstr("   ") );
-
-  CIFGetIntegerD ( dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM );
-//  if (CIFGetInteger1(dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM,Signal))
-//    dbSeq = MinInt4;
-
-  F = Loop->GetString ( CIFTAG_DETAILS,Signal,RC );
-  if ((!RC) && F)  {
-    CreateCopy ( conflict,F );
-    Loop->DeleteField ( CIFTAG_DETAILS,Signal );
-  } else
-    CreateCopy ( conflict,pstr(" ") );
-
-  Signal++;
-
-}
-
-void  CSeqAdv::Copy ( PCContainerClass SeqAdv )  {
-
-  CContainerClass::Copy ( SeqAdv );
-
-  seqNum = PCSeqAdv(SeqAdv)->seqNum;
-  dbSeq  = PCSeqAdv(SeqAdv)->dbSeq;
-  strcpy  ( resName    ,PCSeqAdv(SeqAdv)->resName     );
-  strcpy  ( insCode    ,PCSeqAdv(SeqAdv)->insCode     );
-  strcpy  ( database   ,PCSeqAdv(SeqAdv)->database    );
-  strcpy  ( dbAccession,PCSeqAdv(SeqAdv)->dbAccession );
-  strcpy  ( dbRes      ,PCSeqAdv(SeqAdv)->dbRes       );
-  CreateCopy ( conflict,PCSeqAdv(SeqAdv)->conflict    );
-
-}
-
-void  CSeqAdv::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte    ( &Version );
-  f.WriteInt     ( &seqNum  );
-  f.WriteInt     ( &dbSeq   );
-  f.WriteTerLine ( resName    ,False );
-  f.WriteTerLine ( insCode    ,False );
-  f.WriteTerLine ( database   ,False );
-  f.WriteTerLine ( dbAccession,False );
-  f.WriteTerLine ( dbRes      ,False );
-  f.CreateWrite  ( conflict );
-}
-
-void  CSeqAdv::read  ( RCFile f ) {
-byte Version;
-  f.ReadByte    ( &Version );
-  f.ReadInt     ( &seqNum  );
-  f.ReadInt     ( &dbSeq   );
-  f.ReadTerLine ( resName    ,False );
-  f.ReadTerLine ( insCode    ,False );
-  f.ReadTerLine ( database   ,False );
-  f.ReadTerLine ( dbAccession,False );
-  f.ReadTerLine ( dbRes      ,False );
-  f.CreateRead  ( conflict );
-}
-
-MakeStreamFunctions(CSeqAdv)
-
-
-
-//  ================  CSeqRes  ===================
-
-CSeqRes::CSeqRes() : CStream()  {
-  InitSeqRes();
-}
-
-CSeqRes::CSeqRes ( RPCStream Object ) : CStream(Object)  {
-  InitSeqRes();
-}
-
-CSeqRes::~CSeqRes()  {
-  FreeMemory();
-}
-
-void  CSeqRes::SetChain ( PCChain Chain_Owner )  {
-  Chain = Chain_Owner;
-  if (Chain)  strcpy ( chainID,Chain->chainID );
-        else  strcpy ( chainID,"" );
-}
-
-void  CSeqRes::InitSeqRes()  {
-  Chain   = NULL;
-  numRes  = -1;
-  resName = NULL;
-  serNum  = 0;
-  strcpy ( chainID,"" );
-}
-
-void  CSeqRes::FreeMemory()  {
-  if (resName)  delete[] resName;
-  resName = NULL;
-  numRes  = -1;
-  serNum  = 0;
-}
-
-void  CSeqRes::PDBASCIIDump ( RCFile f )  {
-//  writes the ASCII PDB SEQRES lines into file f
-char S[100];
-int  i,k,sN;
-  if (numRes<0)  return;
-  strcpy     ( S,"SEQRES" );
-  PadSpaces  ( S,80 );
-  if (Chain->chainID[0])
-    S[11] = Chain->chainID[0];
-  PutInteger ( &(S[13]),numRes,4 );
-  if (resName)  {
-    i  = 0;
-    sN = 1;
-    while (i<numRes)  {
-      PutInteger ( &(S[8]),sN,2 );
-      k = 19;
-      while ((i<numRes) && (k<70))  {
-        if (resName[i][0])
-              strcpy_n ( &(S[k]),resName[i],3 );
-        else  strcpy_n ( &(S[k]),pstr("   "),3 );
-        i++;
-        k += 4;
-      }
-      while (k<70)  {
-        strcpy_n ( &(S[k]),pstr("   "),3 );
-        k += 4;
-      }
-      f.WriteLine ( S );
-      sN++;
-    }
-  } else  {
-    S[9] = '0';
-    strcpy_n ( &(S[19]),pstr("UNK"),3 );
-    f.WriteLine ( S );
-  }
-}
-
-int CSeqRes::ConvertPDBASCII ( cpstr S )  {
-int i,k,sN,nR;
-  if (Chain->chainID[0])  {
-    if (S[11]!=Chain->chainID[0])
-      return Error_WrongChainID;
-  } else if (S[11]!=' ')  {
-    Chain->chainID[0] = S[11];
-    Chain->chainID[1] = char(0);
-  } else
-    Chain->chainID[0] = char(0);
-  GetInteger ( sN,&(S[8]) ,2 );
-  GetInteger ( nR,&(S[13]),4 );
-  if (sN==0)  {
-    FreeMemory();
-    numRes = nR;
-  } else  {
-    serNum++;
-    if (sN!=serNum)
-      return Error_SEQRES_serNum;
-    if (sN==1)  {
-      FreeMemory();
-      resName = new ResName[nR];
-      for (i=0;i<nR;i++)
-        resName[i][0] = char(0);
-      numRes  = nR;
-      serNum  = sN;
-    } else if (nR!=numRes)
-      return Error_SEQRES_numRes;
-    i = 0;
-    while ((i<nR) && (resName[i][0]))  i++;
-    if (i>=nR)
-      return Error_SEQRES_extraRes;
-    k = 19;
-    while ((i<nR) && (k<70))  {
-      GetString ( resName[i],&(S[k]),3 );
-      if (!strcmp(resName[i],"   "))  resName[i][0] = char(0);
-                                else  i++;
-      k += 4;
-    }
-  }
-  return 0;
-}
-
-
-void  CSeqRes::MakeCIF ( PCMMCIFData CIF )  {
-//  Note that CSeqRes only adds sequence to the CIF loop common
-// to all chains. Therefore this loop should be wiped off from
-// CIF structure before putting first sequence into it.
-PCMMCIFLoop Loop;
-int         RC,i;
-
-  if (numRes<0)  return;
-
-  RC = CIF->AddLoop ( CIFCAT_NDB_POLY_SEQ_SCHEME,Loop );
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_ID     );
-    Loop->AddLoopTag ( CIFTAG_MON_ID );
-  }
-
-  if (resName)
-    for (i=0;i<numRes;i++)  {
-      Loop->AddString  ( Chain->chainID,True );
-      Loop->AddString  ( resName[i]    ,True );
-    }
-  else
-    for (i=0;i<numRes;i++)  {
-      Loop->AddString  ( Chain->GetEntryID(),True );
-      Loop->AddString  ( pstr("UNK")        ,True );
-    }
-
-}
-
-int  CSeqRes::GetCIF ( PCMMCIFData CIF )  {
-//   Tries to get sequence from the CIF structure. A sequence
-// for first met chain is extracted and then removed from
-// the CIF structure, so that sequential calls will extract
-// all sequencies. Chain ID is stored locally in chainID;
-// reference to parent chain is neither used nor checked.
-//   Returns 0 if sequence was extracted and 1 otherwise.
-PCMMCIFLoop Loop;
-ResName   * rN;
-ChainID     chID;
-pstr        F,CHAIN_ID;
-int         RC,CIFMode,i,l;
-Boolean     isMon;
-
-  FreeMemory();
-
-  CIFMode = CIF_NDB;
-  Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
-  if (!Loop)  {
-    CIFMode = CIF_PDBX;
-    Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
-    if (!Loop)  return 1;
-  }
-
-  l = Loop->GetLoopLength();
-  if (l<=0)  return 1;
-
-  rN         = new ResName[l];
-  chainID[0] = char(1);
-  numRes     = 0;
-  isMon      = False;
-  CHAIN_ID   = CIFName(TAG_SEQ_CHAIN_ID,CIFMode);
-  for (i=0;i<l;i++)  {
-    F = Loop->GetString ( CHAIN_ID,i,RC );
-    if (!RC)  {
-      if (F)  strcpy ( chID,F );
-        else  chID[0] = char(0);
-      if (chainID[0]==char(1))  strcpy ( chainID,chID );
-      if (!strcmp(chainID,chID))  {
-        CIFGetString ( rN[numRes],Loop,CIFTAG_MON_ID,i,
-                       sizeof(ResName),pstr("UNK") );
-        Loop->DeleteField ( CHAIN_ID,i );
-        if (strcmp(rN[numRes],"UNK")) isMon = True;
-        numRes++;
-      }
-    }
-  }
-
-  if (numRes==0)  {
-    numRes = -1;
-    delete[] rN;
-    return 1;
-  }
-
-  if (isMon)  {
-    resName = new ResName[numRes];
-    for (i=0;i<numRes;i++)
-      strcpy ( resName[i],rN[i] );
-  }
-
-  delete[] rN;
-
-  return 0;
-
-}
-
-void  CSeqRes::Copy ( PCSeqRes SeqRes )  {
-int i;
-
-  FreeMemory();
-
-  numRes = SeqRes->numRes;
-  serNum = SeqRes->serNum;
-
-  if (SeqRes->resName)  {
-    resName = new ResName[numRes];
-    for (i=0;i<numRes;i++)
-      strcpy ( resName[i],SeqRes->resName[i] );
-  }
-
-}
-
-void  CSeqRes::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte ( &Version );
-  f.WriteInt  ( &numRes  );
-  f.WriteInt  ( &serNum  );
-  if (resName)  i = 1;
-          else  i = 0;
-  f.WriteInt ( &i );
-  if (resName)
-    for (i=0;i<numRes;i++)
-      f.WriteTerLine ( resName[i],False );
-}
-
-void  CSeqRes::read  ( RCFile f ) {
-int  i;
-byte Version;
-  FreeMemory();
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &numRes  );
-  f.ReadInt  ( &serNum  );
-  f.ReadInt  ( &i       );
-  if (i)  {
-    resName = new ResName[numRes];
-    for (i=0;i<numRes;i++)
-      f.ReadTerLine ( resName[i],False );
-  }
-}
-
-
-MakeStreamFunctions(CSeqRes)
-
-
-
-//  ================  CModRes  ===================
-
-CModRes::CModRes() : CContainerChain()  {
-  InitModRes();
-}
-
-CModRes::CModRes ( PCChain Chain_Owner )
-       : CContainerChain(Chain_Owner)  {
-  InitModRes();
-}
-
-CModRes::CModRes ( PCChain Chain_Owner, cpstr S )
-       : CContainerChain(Chain_Owner)  {
-  InitModRes();
-  ConvertPDBASCII ( S );
-}
-
-CModRes::CModRes ( RPCStream Object ) : CContainerChain(Object)  {
-  InitModRes();
-}
-
-CModRes::~CModRes()  {
-  if (comment)  delete[] comment;
-}
-
-void  CModRes::InitModRes()  {
-  strcpy     ( resName,"---" );
-  seqNum  = 0;
-  strcpy     ( insCode,"-"   );
-  comment = NULL;
-  CreateCopy ( comment,pstr(" ") );
-  strcpy     ( stdRes ,"---" );
-}
-
-void  CModRes::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB MODRES line number N
-//  from the class' data
-  strcpy     ( S,"MODRES" );
-  PadSpaces  ( S,80 );
-  strcpy_n   ( &(S[7]) ,Chain->GetEntryID(),4  );
-  strcpy_n   ( &(S[12]),resName      ,3  );
-  if (Chain->chainID[0])  S[16] = Chain->chainID[0];
-  PutIntIns  ( &(S[18]),seqNum,4,insCode );
-  strcpy_n   ( &(S[24]),stdRes       ,3  );
-  strcpy_n   ( &(S[29]),comment,IMin(strlen(comment),41) );
-}
-
-int CModRes::ConvertPDBASCII ( cpstr S )  {
-IDCode idCode;
-  if (Chain->chainID[0])  {
-    if (S[16]!=Chain->chainID[0])
-      return Error_WrongChainID;
-  } else if (S[16]!=' ')  {
-    Chain->chainID[0] = S[16];
-    Chain->chainID[1] = char(0);
-  } else
-    Chain->chainID[0] = char(0);
-  strcpy ( idCode,Chain->GetEntryID() );
-  if (idCode[0])  {
-    if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
-      return Error_WrongEntryID;
-  } else  {
-    GetString ( idCode,&(S[7]),4 );
-    Chain->SetEntryID ( idCode );
-  }
-  GetString  ( resName       ,&(S[12]),3 );
-  GetIntIns  ( seqNum,insCode,&(S[18]),4 );
-  GetString  ( stdRes        ,&(S[24]),3 );
-  CreateCopy ( comment       ,&(S[29])   );
-  CutSpaces  ( comment,SCUTKEY_END       );
-  return 0;
-}
-
-void  CModRes::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(CIF);
-UNUSED_ARGUMENT(N);
-/*  -- apparently wrong use of _struct_conn, to be revised
-PCMMCIFLoop Loop;
-int         RC;
-
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
-
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID               );
-    Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID                 );
-    Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_COMP_ID        );
-    Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_ASYM_ID        );
-    Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_SEQ_ID         );
-    Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_LABEL_INS_CODE   );
-    Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_STANDARD_COMP_ID );
-    Loop->AddLoopTag ( CIFTAG_DETAILS                    );
-  }
-
-  Loop->AddString  ( pstr("MODRES")           );
-  Loop->AddString  ( Chain->GetEntryID(),True );
-  Loop->AddString  ( resName            ,True );
-  Loop->AddString  ( Chain->chainID     ,True );
-  Loop->AddInteger ( seqNum                   );
-  Loop->AddString  ( insCode            ,True );
-  Loop->AddString  ( stdRes             ,True );
-  Loop->AddString  ( comment            ,True );
-
-*/
-
-}
-
-void  CModRes::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-UNUSED_ARGUMENT(CIF);
-//  GetCIF(..) must be always run without reference to Chain,
-//  see CModel::GetCIF(..).
-
-/*  -- apparently wrong use of _struct_conn, to be revised
-PCMMCIFLoop   Loop;
-pstr          F;
-int           l,RC;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
-  if (!Loop)  {
-    Signal = -1;
-    return;
-  }
-
-  l = Loop->GetLoopLength();
-  while (Signal<l)  {
-    F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,Signal,RC );
-    if ((!RC) && F)  {
-      if (!strcmp(F,"MODRES"))  break;
-    }
-    Signal++;
-  }
-  if (Signal>=l)  {
-    Signal = -1;
-    return;
-  }
-
-  Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,Signal );
-
-  //  Determine the ChainID first and store it locally. It will
-  // be used by CModel for generating chains and placing the
-  // primary structure data BEFORE reading the coordinate section.
-  F = Loop->GetString ( CIFTAG_PTNR1_LABEL_ASYM_ID,Signal,RC );
-  if ((!RC) && F)  {
-    strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
-    Loop->DeleteField ( CIFTAG_PTNR1_LABEL_ASYM_ID,Signal );
-  } else
-    strcpy ( chainID,"" );
-
-
-  CIFGetString ( resName,Loop,CIFTAG_PTNR1_LABEL_COMP_ID,Signal,
-                 sizeof(ResName),pstr("UNK") );
-
-  if (CIFGetInteger(seqNum,Loop,CIFTAG_PTNR1_LABEL_SEQ_ID,Signal))
-    return;
-
-  CIFGetString ( insCode,Loop,CIFTAG_NDB_PTNR1_LABEL_INS_CODE,
-                 Signal,sizeof(InsCode),pstr(" ") );
-
-  CIFGetString ( stdRes,Loop,CIFTAG_NDB_PTNR1_STANDARD_COMP_ID,Signal,
-                 sizeof(ResName),pstr("UNK") );
-
-  F = Loop->GetString ( CIFTAG_DETAILS,Signal,RC );
-  if ((!RC) && F)  {
-    CreateCopy ( comment,F );
-    Loop->DeleteField ( CIFTAG_DETAILS,Signal );
-  } else
-    CreateCopy ( comment,pstr(" ") );
-
-  Signal++;
-
-*/
-
-  Signal = -1;
-
-}
-
-void  CModRes::Copy ( PCContainerClass ModRes )  {
-  seqNum = PCModRes(ModRes)->seqNum;
-  strcpy ( resName,PCModRes(ModRes)->resName );
-  strcpy ( insCode,PCModRes(ModRes)->insCode );
-  strcpy ( stdRes ,PCModRes(ModRes)->stdRes  );
-  CreateCopy ( comment,PCModRes(ModRes)->comment );
-}
-
-void  CModRes::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte    ( &Version );
-  f.WriteInt     ( &seqNum  );
-  f.WriteTerLine ( resName,False );
-  f.WriteTerLine ( insCode,False );
-  f.WriteTerLine ( stdRes ,False );
-  f.CreateWrite  ( comment  );
-}
-
-void  CModRes::read  ( RCFile f ) {
-byte Version;
-  f.ReadByte    ( &Version );
-  f.ReadInt     ( &seqNum  );
-  f.ReadTerLine ( resName,False );
-  f.ReadTerLine ( insCode,False );
-  f.ReadTerLine ( stdRes ,False );
-  f.CreateRead  ( comment  );
-}
-
-MakeStreamFunctions(CModRes)
-
-
-
-//  ================  CHetRec  ======================
-
-CHetRec::CHetRec() : CContainerChain()  {
-  InitHetRec();
-}
-
-CHetRec::CHetRec ( PCChain Chain_Owner )
-       : CContainerChain(Chain_Owner)  {
-  InitHetRec();
-}
-
-CHetRec::CHetRec ( PCChain Chain_Owner, cpstr S )
-       : CContainerChain(Chain_Owner)  {
-  InitHetRec();
-  ConvertPDBASCII ( S );
-}
-
-CHetRec::CHetRec ( RPCStream Object ) : CContainerChain(Object)  {
-  InitHetRec();
-}
-
-CHetRec::~CHetRec()  {
-  if (comment)  delete[] comment;
-}
-
-void  CHetRec::InitHetRec()  {
-  strcpy ( hetID  ,"---" );
-  strcpy ( insCode,"-"   );
-  seqNum      = 0;
-  numHetAtoms = 0;
-  comment     = NULL;
-  CreateCopy ( comment,pstr(" ") );
-}
-
-void  CHetRec::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB MODRES line number N
-//  from the class' data
-  strcpy     ( S,"HET" );
-  PadSpaces  ( S,80 );
-  strcpy_n   ( &(S[7]) ,hetID,3  );
-  if (Chain->chainID[0])  S[12] = Chain->chainID[0];
-  PutIntIns  ( &(S[13]),seqNum,4,insCode );
-  PutInteger ( &(S[20]),numHetAtoms,5    );
-  strcpy_n   ( &(S[30]),comment,IMin(strlen(comment),40) );
-}
-
-int  CHetRec::ConvertPDBASCII ( cpstr S )  {
-  if (Chain->chainID[0])  {
-    if (S[12]!=Chain->chainID[0])
-      return Error_WrongChainID;
-  } else if (S[12]!=' ')  {
-    Chain->chainID[0] = S[12];
-    Chain->chainID[1] = char(0);
-  } else
-    Chain->chainID[0] = char(0);
-  GetString  ( hetID         ,&(S[7]) ,3 );
-  GetIntIns  ( seqNum,insCode,&(S[13]),4 );
-  GetInteger ( numHetAtoms   ,&(S[20]),5 );
-  CreateCopy ( comment       ,&(S[30])   );
-  CutSpaces  ( comment,SCUTKEY_END       );
-  return 0;
-}
-
-void  CHetRec::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop;
-int         RC;
-
-  RC = CIF->AddLoop ( CIFCAT_NDB_NONSTANDARD_LIST,Loop );
-
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_ID              );
-    Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID    );
-    Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID     );
-    Loop->AddLoopTag ( CIFTAG_INS_CODE        );
-    Loop->AddLoopTag ( CIFTAG_NUMBER_ATOMS_NH );
-    Loop->AddLoopTag ( CIFTAG_DETAILS         );
-  }
-
-  Loop->AddString  ( hetID         ,True );
-  Loop->AddString  ( Chain->chainID,True );
-  Loop->AddInteger ( seqNum              );
-  Loop->AddString  ( insCode       ,True );
-  Loop->AddInteger ( numHetAtoms         );
-  Loop->AddString  ( comment       ,True );
-
-}
-
-void  CHetRec::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-//  GetCIF(..) must be always run without reference to Chain,
-//  see CModel::GetCIF(..).
-PCMMCIFLoop   Loop;
-pstr          F;
-int           RC;
-
-  Loop = CIF->GetLoop ( CIFCAT_NDB_NONSTANDARD_LIST );
-  if (!Loop)  {
-    Signal = -1;
-    return;
-  }
-
-  if (Signal>=Loop->GetLoopLength())  {
-    Signal = -1;
-    return;
-  }
-
-  //  Determine the ChainID first and store it locally. It will
-  // be used by CModel for generating chains and placing the
-  // primary structure data BEFORE reading the coordinate section.
-  F = Loop->GetString ( CIFTAG_AUTH_ASYM_ID,Signal,RC );
-  if ((!RC) && F)  {
-    strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
-    Loop->DeleteField ( CIFTAG_AUTH_ASYM_ID,Signal );
-  } else
-    strcpy ( chainID,"" );
-
-
-  CIFGetString ( hetID,Loop,CIFTAG_ID,Signal,sizeof(ResName),
-                 pstr("UNK") );
-
-  if (CIFGetInteger(seqNum,Loop,CIFTAG_AUTH_SEQ_ID,Signal))  return;
-
-  CIFGetString ( insCode,Loop,CIFTAG_INS_CODE,Signal,sizeof(InsCode),
-                 pstr(" ") );
-
-  if (CIFGetInteger(numHetAtoms,Loop,CIFTAG_NUMBER_ATOMS_NH,Signal))
-    return;
-
-  F = Loop->GetString ( CIFTAG_DETAILS,Signal,RC );
-  if ((!RC) && F)  {
-    CreateCopy ( comment,F );
-    Loop->DeleteField ( CIFTAG_DETAILS,Signal );
-  } else
-    CreateCopy ( comment,pstr(" ") );
-
-  Signal++;
-
-}
-
-void  CHetRec::Copy ( PCContainerClass Het )  {
-  seqNum      = PCHetRec(Het)->seqNum;
-  numHetAtoms = PCHetRec(Het)->numHetAtoms;
-  strcpy     ( hetID  ,PCHetRec(Het)->hetID   );
-  strcpy     ( insCode,PCHetRec(Het)->insCode );
-  CreateCopy ( comment,PCHetRec(Het)->comment );
-}
-
-void  CHetRec::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte    ( &Version      );
-  f.WriteInt     ( &seqNum       );
-  f.WriteInt     ( &numHetAtoms  );
-  f.WriteTerLine ( hetID  ,False );
-  f.WriteTerLine ( insCode,False );
-  f.CreateWrite  ( comment       );
-}
-
-void  CHetRec::read  ( RCFile f ) {
-byte Version;
-  f.ReadByte    ( &Version      );
-  f.ReadInt     ( &seqNum       );
-  f.ReadInt     ( &numHetAtoms  );
-  f.ReadTerLine ( hetID  ,False );
-  f.ReadTerLine ( insCode,False );
-  f.CreateRead  ( comment       );
-}
-
-MakeStreamFunctions(CHetRec)
-
-
-
-//  =====================   CChain   =======================
-
-CChain::CChain() : CUDData() {
-  InitChain();
-  SetChain ( pstr("") );
-}
-
-CChain::CChain ( PCProModel Model, const ChainID chID ) : CUDData()  {
-  InitChain();
-  SetChain ( chID );
-  if (Model)  Model->AddChain ( this );
-}
-
-CChain::CChain ( RPCStream Object ) : CUDData(Object)  {
-  InitChain();
-  SetChain ( pstr("") );
-}
-
-void  CChain::InitChain()  {
-  nResidues      = 0;
-  ResLen         = 0;
-  Residue        = NULL;
-  model          = NULL;
-  chainID[0]     = char(0);
-  prevChainID[0] = char(0);
-  nWeights       = 0;
-  Weight         = 0.0;
-  Exclude        = True;
-}
-
-void  CChain::SetChain ( const ChainID chID )  {
-  strcpy ( chainID,chID );
-  if (chID[0]==' ')  chainID[0] = char(0);
-  DBReference.SetChain ( this );
-  SeqAdv     .SetChain ( this );
-  SeqRes     .SetChain ( this );
-  ModRes     .SetChain ( this );
-  Het        .SetChain ( this );
-}
-
-void  CChain::SetChainID ( const ChainID chID )  {
-  strcpy ( chainID,chID );
-  if (chID[0]==' ')  chainID[0] = char(0);
-}
-
-CChain::~CChain()  {
-  FreeMemory();
-  if (model)  model->_ExcludeChain ( chainID );
-}
-
-void  CChain::FreeMemory()  {
-  DeleteAllResidues();
-  if (Residue)  delete[] Residue;
-  ResLen    = 0;
-  nResidues = 0;
-  Residue   = NULL;
-  FreeAnnotations();
-}
-
-void  CChain::FreeAnnotations()  {
-  DBReference.FreeContainer();
-  SeqAdv     .FreeContainer();
-  SeqRes     .FreeMemory   ();
-  ModRes     .FreeContainer();
-  Het        .FreeContainer();
-}
-
-void CChain::SetModel ( PCProModel Model )  {
-  model = Model;
-}
-
-PCMMDBManager CChain::GetCoordHierarchy()  {
-  if (model)  return model->GetCoordHierarchy();
-  return NULL;
-}
-
-void CChain::CheckInAtoms()  {
-int i;
-  if (GetCoordHierarchy())
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])
-        Residue[i]->CheckInAtoms();
-}
-
-int CChain::ConvertDBREF ( cpstr PDBString ) {
-int              RC;
-PCContainerChain ContainerChain;
-  ContainerChain = new CDBReference(this);
-  RC = ContainerChain->ConvertPDBASCII ( PDBString );
-  if (RC)  {
-    delete ContainerChain;
-    return RC;
-  }
-  DBReference.AddData ( ContainerChain );
-  return 0;
-}
-
-int CChain::ConvertSEQADV ( cpstr PDBString ) {
-int              RC;
-PCContainerChain ContainerChain;
-  ContainerChain = new CSeqAdv(this);
-  RC = ContainerChain->ConvertPDBASCII ( PDBString );
-  if (RC)  {
-    delete ContainerChain;
-    return RC;
-  }
-  SeqAdv.AddData ( ContainerChain );
-  return 0;
-}
-
-int CChain::ConvertSEQRES ( cpstr PDBString ) {
-  return SeqRes.ConvertPDBASCII ( PDBString );
-}
-
-int  CChain::ConvertMODRES ( cpstr PDBString ) {
-int              RC;
-PCContainerChain ContainerChain;
-  ContainerChain = new CModRes(this);
-  RC = ContainerChain->ConvertPDBASCII ( PDBString );
-  if (RC)  {
-    delete ContainerChain;
-    return RC;
-  }
-  ModRes.AddData ( ContainerChain );
-  return 0;
-}
-
-int  CChain::ConvertHET ( cpstr PDBString ) {
-int              RC;
-PCContainerChain ContainerChain;
-  ContainerChain = new CHetRec(this);
-  RC = ContainerChain->ConvertPDBASCII ( PDBString );
-  if (RC)  {
-    delete ContainerChain;
-    return RC;
-  }
-  Het.AddData ( ContainerChain );
-  return 0;
-}
-
-
-void  CChain::PDBASCIIDump ( RCFile f )  {
-// this function was for test purposes and is not used
-// for normal function of MMDB
-  DBReference.PDBASCIIDump ( f );
-  SeqAdv     .PDBASCIIDump ( f );
-  SeqRes     .PDBASCIIDump ( f );
-  ModRes     .PDBASCIIDump ( f );
-  Het        .PDBASCIIDump ( f );
-}
-
-void  CChain::PDBASCIIAtomDump ( RCFile f )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])
-      Residue[i]->PDBASCIIAtomDump ( f );
-}
-
-void  CChain::MakeAtomCIF ( PCMMCIFData CIF )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])
-      Residue[i]->MakeAtomCIF ( CIF );
-}
-
-
-int  CChain::GetNumberOfResidues()  {
-  return nResidues;
-}
-
-PCResidue CChain::GetResidue ( int resNo )  {
-  if ((0<=resNo) && (resNo<nResidues))
-        return Residue[resNo];
-  else  return NULL;
-}
-
-
-PCResidue CChain::GetResidueCreate ( const ResName resName,
-                                     int           seqNum,
-                                     const InsCode insCode,
-                                     Boolean       Enforce )  {
-//   Returns pointer on residue, whose name, sequence number and
-// insert code are given in resName, seqNum and insCode, respectively.
-// If such a residue is absent in the chain, one is created at
-// the end of the chain.
-int i;
-
-  // check if such a residue is already in the chain
-  if (insCode[0])  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) &&
-            (!strcmp(insCode,Residue[i]->insCode)))  {
-          if (!strcmp(resName,Residue[i]->name))
-            return Residue[i]; // it is there; just return the pointer
-          else if (!Enforce)
-            return NULL;       // duplicate seqNum and insCode!
-        }
-      }
-  } else  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) &&
-            (!Residue[i]->insCode[0]))  {
-          if (!strcmp(resName,Residue[i]->name))
-            return Residue[i]; // it is there; just return the pointer
-          else if (!Enforce)
-            return NULL;       // duplicate seqNum and insCode!
-        }
-      }
-  }
-
-  // expand the residue array, if necessary
-  if (nResidues>=ResLen)
-    ExpandResidueArray ( 100 );
-
-  // create new residue
-  Residue[nResidues] = newCResidue();
-  Residue[nResidues]->SetChain ( this );
-  Residue[nResidues]->SetResID ( resName,seqNum,insCode );
-  Residue[nResidues]->index = nResidues;
-  nResidues++;
-
-  return Residue[nResidues-1];
-
-}
-
-void  CChain::ExpandResidueArray ( int inc )  {
-PPCResidue Residue1;
-int        i;
-  ResLen  += inc;
-  Residue1 = new PCResidue[ResLen];
-  for (i=0;i<nResidues;i++)
-    Residue1[i] = Residue[i];
-  if (Residue) delete[] Residue;
-  Residue = Residue1;
-  for (i=nResidues;i<ResLen;i++)
-    Residue[i] = NULL;
-}
-
-PCResidue CChain::GetResidue ( int seqNum, const InsCode insCode )  {
-//   Returns pointer on residue, whose sequence number and
-// insert code are given in seqNum and insCode, respectively.
-// If such a residue is absent in the chain, returns NULL.
-int     i;
-Boolean isInsCode;
-  if (insCode)  isInsCode = insCode[0]!=char(0);
-          else  isInsCode = False;
-  if (isInsCode)  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) &&
-            (!strcmp(insCode,Residue[i]->insCode)))
-          return Residue[i];
-      }
-  } else  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) && (!Residue[i]->insCode[0]))
-          return Residue[i];
-      }
-  }
-  return NULL;
-}
-
-int  CChain::GetResidueNo ( int seqNum, const InsCode insCode )  {
-//   GetResidueNo(..) returns the residue number in the chain's
-// residues table. Residues are numbered as 0..nres-1 as they appear
-// in the coordinate file.
-//   If residue is not found, the function returns -1.
-int      i;
-Boolean isInsCode;
-  if (insCode)  isInsCode = insCode[0]!=char(0);
-          else  isInsCode = False;
-  if (isInsCode)  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) &&
-            (!strcmp(insCode,Residue[i]->insCode)))
-          return i;
-      }
-  } else  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) && (!Residue[i]->insCode[0]))
-          return i;
-      }
-  }
-  return -1;
-}
-
-void CChain::GetResidueTable ( PPCResidue & resTable,
-                               int & NumberOfResidues )  {
-  resTable         = Residue;
-  NumberOfResidues = nResidues;
-}
-
-int  CChain::_ExcludeResidue ( const ResName resName, int seqNum,
-                               const InsCode insCode )  {
-//   ExcludeResidue(..) excludes (but does not dispose!) a residue
-// from the chain. Returns 1 if the chain gets empty and 0 otherwise.
-int  i,k;
-
-  if (!Exclude)  return 0;
-
-  // find the residue
-  k = -1;
-  for (i=0;(i<nResidues) && (k<0);i++)
-    if ((seqNum==Residue[i]->seqNum)           &&
-        (!strcmp(insCode,Residue[i]->insCode)) &&
-        (!strcmp(resName,Residue[i]->name)))
-      k = i;
-
-  if (k>=0)  {
-    for (i=k+1;i<nResidues;i++)  {
-      Residue[i-1] = Residue[i];
-      if (Residue[i-1])
-        Residue[i-1]->index = i-1;
-    }
-    nResidues--;
-    Residue[nResidues] = NULL;
-  }
-
-  if (nResidues<=0)  return 1;
-               else  return 0;
-
-}
-
-
-
-//  ------------------  Deleting residues  --------------------------
-
-int  CChain::DeleteResidue ( int resNo )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])  {
-      Exclude = False;
-      delete Residue[resNo];
-      Residue[resNo] = NULL;
-      Exclude = True;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-int  CChain::DeleteResidue ( int seqNum, const InsCode insCode )  {
-int i;
-  if (insCode[0])  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) &&
-            (!strcmp(insCode,Residue[i]->insCode)))  {
-          Exclude = False;
-          delete Residue[i];
-          Residue[i] = NULL;
-          Exclude = True;
-          return 1;
-        }
-      }
-  } else  {
-    for (i=0;i<nResidues;i++)
-      if (Residue[i])  {
-        if ((seqNum==Residue[i]->seqNum) && (!Residue[i]->insCode[0]))  {
-          Exclude = False;
-          delete Residue[i];
-          Residue[i] = NULL;
-          Exclude = True;
-          return 1;
-        }
-      }
-  }
-  return 0;
-}
-
-
-int  CChain::DeleteAllResidues()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  {
-      delete Residue[i];
-      Residue[i] = NULL;
-      k++;
-    }
-  nResidues = 0;
-  Exclude = True;
-  return k;
-}
-
-
-int  CChain::DeleteSolvent()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  {
-      if (Residue[i]->isSolvent())  {
-        delete Residue[i];
-        Residue[i] = NULL;
-        k++;
-      }
-    }
-  Exclude = True;
-  return k;
-}
-
-
-void CChain::TrimResidueTable()  {
-int i,j;
-  Exclude = False;
-  j = 0;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  {
-      if (Residue[i]->nAtoms>0)  {
-        if (j<i)  {
-          Residue[j] = Residue[i];
-          Residue[j]->index = j;
-          Residue[i] = NULL;
-        }
-        j++;
-      } else  {
-        delete Residue[i];
-        Residue[i] = NULL;
-      }
-    }
-  nResidues = j;
-  Exclude   = True;
-}
-
-int  CChain::AddResidue ( PCResidue res )  {
-//  modify both CModel::Copy methods simultaneously!
-//
-//  Copy(PCModel,PPCAtom,int&) copies atoms into array 'atom'
-// starting from position atom_index. 'atom' should be able to
-// accept all new atoms - no checks on the length of 'atom'
-// is being made. This function should not be used in applications.
-  return InsResidue ( res,nResidues );
-}
-
-/*
-PCMMDBFile mmdbfile;
-PCChain    chain1;
-int        i;
-
-  for (i=0;i<nResidues;i++)
-    if (Residue[i]==res)  return -i;  // this residue is already there
-
-  if (res)  {
-
-    mmdbfile = PCMMDBFile(GetCoordHierarchy());
-
-    // get space for new residue
-    if (nResidues>=ResLen)
-      ExpandResidueArray ( 100 );
-
-    if (res->GetCoordHierarchy())  {
-      Residue[nResidues] = newCResidue();
-      Residue[nResidues]->SetChain ( this );
-      Residue[nResidues]->SetResID ( res->name,res->seqNum,res->insCode );
-      if (mmdbfile)  {
-        // get space for new atoms
-        mmdbfile->AddAtomArray ( res->GetNumberOfAtoms(True) );
-        Residue[nResidues]->Copy ( res,mmdbfile->Atom,mmdbfile->nAtoms );
-      } else  {
-        for (i=0;i<res->nAtoms;i++)
-          Residue[nResidues]->AddAtom ( res->atom[i] );
-      }
-    } else  {
-      Residue[nResidues] = res;
-      chain1 = res->GetChain();
-      if (chain1)
-        for (i=0;i<chain1->nResidues;i++)
-          if (chain1->Residue[i]==res)  {
-            chain1->Residue[i] = NULL;
-            break;
-          }
-      Residue[nResidues]->SetChain ( this );
-      if (mmdbfile)
-        Residue[nResidues]->CheckInAtoms();
-    }
-    nResidues++;
-
-  }
-
-  return nResidues;
-
-}
-*/
-
-int  CChain::InsResidue ( PCResidue res, int seqNum,
-                          const InsCode insCode )  {
-  return InsResidue ( res,GetResidueNo(seqNum,insCode) );
-}
-
-int  CChain::InsResidue ( PCResidue res, int pos )  {
-//   Inserts residue res onto position pos of the chain,
-// pos=0..nResidues-1 . Residues pos..nResidues-1 are
-// shifted up the chain.
-//   The function places new atoms on the top of atom
-// index. It is advisable to call
-// CMMDBFile::PDBCleanup ( PDBCLEAN_INDEX ) after all
-// insertions are done.
-PCMMDBFile mmdbfile;
-PCChain    chain1;
-int        i,pp;
-
-  pp = IMax ( 0,IMin(nResidues,pos) );
-
-  for (i=0;i<nResidues;i++)
-    if (Residue[i]==res)  return -i;  // this residue is already there
-
-  if (res)  {
-
-    mmdbfile = PCMMDBFile(GetCoordHierarchy());
-
-    // get space for new residue
-    if (nResidues>=ResLen)
-      ExpandResidueArray ( 100 );
-
-    // shift residues to the end of the chain as necessary
-    for (i=nResidues;i>pp;i--)
-      Residue[i] = Residue[i-1];
-
-    // insert the new residue
-    if (res->GetCoordHierarchy())  {
-      Residue[pp] = newCResidue();
-      Residue[pp]->SetChain ( this );
-      Residue[pp]->SetResID ( res->name,res->seqNum,res->insCode );
-      if (mmdbfile)  {
-        // get space for new atoms
-        mmdbfile->AddAtomArray ( res->GetNumberOfAtoms(True) );
-        Residue[pp]->_copy ( res,mmdbfile->Atom,mmdbfile->nAtoms );
-      } else  {
-        for (i=0;i<res->nAtoms;i++)
-          Residue[pp]->AddAtom ( res->atom[i] );
-      }
-    } else  {
-      Residue[pp] = res;
-      chain1 = res->GetChain();
-      if (chain1)
-        for (i=0;i<chain1->nResidues;i++)
-          if (chain1->Residue[i]==res)  {
-            chain1->Residue[i] = NULL;
-            break;
-          }
-      Residue[pp]->SetChain ( this );
-      if (mmdbfile)
-        Residue[pp]->CheckInAtoms();
-    }
-    nResidues++;
-
-  }
-
-  return nResidues;
-
-}
-
-
-// --------------------  Extracting atoms  -----------------------
-
-int CChain::GetNumberOfAtoms ( Boolean countTers )  {
-int i,na;
-  na = 0;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  na += Residue[i]->GetNumberOfAtoms ( countTers );
-  return na;
-}
-
-int CChain::GetNumberOfAtoms ( int seqNo, const InsCode insCode )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res)  return res->nAtoms;
-  return 0;
-}
-
-int CChain::GetNumberOfAtoms ( int resNo )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])  return Residue[resNo]->nAtoms;
-  }
-  return 0;
-}
-
-PCAtom CChain::GetAtom ( int            seqNo,
-                         const InsCode  insCode,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res) return res->GetAtom ( aname,elmnt,aloc );
-  return NULL;
-}
-
-PCAtom CChain::GetAtom ( int seqNo, const InsCode insCode,
-                         int atomNo )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res)  {
-    if ((0<=atomNo) && (atomNo<res->nAtoms))
-      return res->atom[atomNo];
-  }
-  return NULL;
-}
-
-PCAtom CChain::GetAtom ( int            resNo,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])
-      return Residue[resNo]->GetAtom ( aname,elmnt,aloc );
-  }
-  return NULL;
-}
-
-PCAtom CChain::GetAtom ( int resNo, int atomNo )  {
-PCResidue res;
-  if ((0<=resNo) && (resNo<nResidues))  {
-    res = Residue[resNo];
-    if (res)  {
-      if ((0<=atomNo) && (atomNo<res->nAtoms))
-        return res->atom[atomNo];
-    }
-  }
-  return NULL;
-}
-
-void CChain::GetAtomTable ( int seqNo, const InsCode insCode,
-                         PPCAtom & atomTable, int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  res = GetResidue ( seqNo,insCode );
-  if (res)  {
-    atomTable     = res->atom;
-    NumberOfAtoms = res->nAtoms;
-  }
-}
-
-void CChain::GetAtomTable ( int resNo, PPCAtom & atomTable,
-                            int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  if ((0<=resNo) && (resNo<nResidues))  {
-    res = Residue[resNo];
-    if (res)  {
-      atomTable     = res->atom;
-      NumberOfAtoms = res->nAtoms;
-    }
-  }
-}
-
-
-void CChain::GetAtomTable1 ( int seqNo, const InsCode insCode,
-                             PPCAtom & atomTable, int & NumberOfAtoms )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CChain::GetAtomTable1 ( int resNo, PPCAtom & atomTable,
-                             int & NumberOfAtoms )  {
-PCResidue res;
-  if ((0<=resNo) && (resNo<nResidues))
-       res = Residue[resNo];
-  else res = NULL;
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-int CChain::DeleteAtom ( int            seqNo,
-                         const InsCode  insCode,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res) return res->DeleteAtom ( aname,elmnt,aloc );
-  return 0;
-}
-
-int CChain::DeleteAtom ( int seqNo, const InsCode insCode,
-                         int atomNo )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res) return res->DeleteAtom ( atomNo );
-  return 0;
-}
-
-int CChain::DeleteAtom ( int            resNo,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])
-      return Residue[resNo]->DeleteAtom ( aname,elmnt,aloc );
-  }
-  return 0;
-}
-
-int CChain::DeleteAtom ( int resNo, int atomNo )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])
-      return Residue[resNo]->DeleteAtom ( atomNo );
-  }
-  return 0;
-}
-
-
-int CChain::DeleteAllAtoms ( int seqNo, const InsCode insCode )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res) return res->DeleteAllAtoms();
-  return 0;
-}
-
-int CChain::DeleteAllAtoms ( int resNo )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])
-      return Residue[resNo]->DeleteAllAtoms();
-  }
-  return 0;
-}
-
-int CChain::DeleteAllAtoms()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])
-      k += Residue[i]->DeleteAllAtoms();
-  return k;
-}
-
-int CChain::DeleteAltLocs()  {
-//  This function leaves only alternative location with maximal
-// occupancy, if those are equal or unspecified, the one with
-// "least" alternative location indicator.
-//  The function returns the number of deleted. All tables remain
-// untrimmed, so that explicit trimming or calling FinishStructEdit()
-// is required.
-int i,n;
-
-  n = 0;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  n += Residue[i]->DeleteAltLocs();
-
-  return n;
-
-}
-
-
-int CChain::AddAtom ( int seqNo, const InsCode insCode,
-                      PCAtom atom )  {
-PCResidue res;
-  res = GetResidue ( seqNo,insCode );
-  if (res) return res->AddAtom ( atom );
-  return 0;
-}
-
-int CChain::AddAtom ( int resNo, PCAtom atom )  {
-  if ((0<=resNo) && (resNo<nResidues))  {
-    if (Residue[resNo])
-      return Residue[resNo]->AddAtom ( atom );
-  }
-  return 0;
-}
-
-
-void  CChain::Copy ( PCChain Chain )  {
-// modify both CChain::_copy and CChain::Copy methods simultaneously!
-int i;
-
-  FreeMemory();
-
-  if (Chain)  {
-
-    CopyAnnotations ( Chain );
-
-    nResidues = Chain->nResidues;
-    ResLen    = nResidues;
-    if (nResidues>0)  {
-      Residue = new PCResidue[nResidues];
-      for (i=0;i<nResidues;i++)  {
-        Residue[i] = newCResidue();
-        Residue[i]->SetChain ( this );
-        Residue[i]->Copy ( Chain->Residue[i] );
-      }
-    }
-
-  }
-
-}
-
-void  CChain::CopyAnnotations ( PCChain Chain )  {
-  if (Chain)  {
-    strcpy ( chainID    ,Chain->chainID     );
-    strcpy ( prevChainID,Chain->prevChainID );
-    DBReference.Copy ( &(Chain->DBReference) );
-    SeqAdv     .Copy ( &(Chain->SeqAdv)      );  //  SEQADV records
-    SeqRes     .Copy ( &(Chain->SeqRes)      );  //  SEQRES data
-    ModRes     .Copy ( &(Chain->ModRes)      );  //  MODRES records
-    Het        .Copy ( &(Chain->Het)         );  //  HET    records
-  }
-}
-
-
-void  CChain::_copy ( PCChain Chain )  {
-// modify both CChain::_copy and CChain::Copy methods simultaneously!
-int i;
-
-  FreeMemory();
-
-  strcpy ( chainID    ,Chain->chainID     );
-  strcpy ( prevChainID,Chain->prevChainID );
-
-  DBReference.Copy ( &(Chain->DBReference) );
-  SeqAdv     .Copy ( &(Chain->SeqAdv)      );  //  SEQADV records
-  SeqRes     .Copy ( &(Chain->SeqRes)      );  //  SEQRES data
-  ModRes     .Copy ( &(Chain->ModRes)      );  //  MODRES records
-  Het        .Copy ( &(Chain->Het)         );  //  HET    records
-
-  nResidues = Chain->nResidues;
-  ResLen    = nResidues;
-  if (nResidues>0)  {
-    Residue = new PCResidue[nResidues];
-    for (i=0;i<nResidues;i++)  {
-      Residue[i] = newCResidue();
-      Residue[i]->SetChain ( this );
-      Residue[i]->_copy ( Chain->Residue[i] );
-    }
-  }
-
-}
-
-void  CChain::_copy ( PCChain Chain, PPCAtom atom, int & atom_index )  {
-// modify both CChain::_copy and CChain::Copy methods simultaneously!
-int i;
-
-  FreeMemory();
-
-  strcpy ( chainID    ,Chain->chainID     );
-  strcpy ( prevChainID,Chain->prevChainID );
-
-  DBReference.Copy ( &(Chain->DBReference) );
-  SeqAdv     .Copy ( &(Chain->SeqAdv)      );  //  SEQADV records
-  SeqRes     .Copy ( &(Chain->SeqRes)      );  //  SEQRES data
-  ModRes     .Copy ( &(Chain->ModRes)      );  //  MODRES records
-  Het        .Copy ( &(Chain->Het)         );  //  HET    records
-
-  nResidues = Chain->nResidues;
-  ResLen    = nResidues;
-  if (nResidues>0)  {
-    Residue = new PCResidue[nResidues];
-    for (i=0;i<nResidues;i++)
-      if (Chain->Residue[i])  {
-        Residue[i] = newCResidue();
-        Residue[i]->SetChain ( this );
-        Residue[i]->_copy ( Chain->Residue[i],atom,atom_index );
-      } else
-        Residue[i] = NULL;
-  }
-
-}
-
-/*
-void  CChain::Duplicate ( PCChain Chain )  {
-int i;
-
-  FreeMemory();
-
-  strcpy ( chainID    ,Chain->chainID     );
-  strcpy ( prevChainID,Chain->prevChainID );
-
-  DBReference.Copy ( &(Chain->DBReference) );
-  SeqAdv     .Copy ( &(Chain->SeqAdv)      );  //  SEQADV records
-  SeqRes     .Copy ( &(Chain->SeqRes)      );  //  SEQRES data
-  ModRes     .Copy ( &(Chain->ModRes)      );  //  MODRES records
-  Het        .Copy ( &(Chain->Het)         );  //  HET    records
-
-  nResidues = Chain->nResidues;
-  ResLen    = nResidues;
-  if (nResidues>0)  {
-    Residue = new PCResidue[nResidues];
-    for (i=0;i<nResidues;i++)  {
-      Residue[i] = newCResidue();
-      Residue[i]->SetChain ( this );
-      Residue[i]->Duplicate ( Chain->Residue[i] );
-    }
-  }
-
-}
-*/
-
-cpstr  CChain::GetEntryID()  {
-  if (model)  return model->GetEntryID();
-        else  return pstr("");
-}
-
-void  CChain::SetEntryID ( const IDCode idCode )  {
-  if (model) model->SetEntryID ( idCode );
-}
-
-int   CChain::GetModelNum()  {
-  if (model)  return model->GetSerNum();
-  return 0;
-}
-
-cpstr  CChain::GetChainID ( pstr ChID )  {
-  ChID[0] = char(0);
-  if (model)
-       sprintf ( ChID,"/%i/",model->GetSerNum() );
-  else strcpy  ( ChID,"/-/" );
-  strcat ( ChID,chainID );
-  return ChID;
-}
-
-
-void  CChain::GetAtomStatistics  ( RSAtomStat AS )  {
-  AS.Init();
-  CalcAtomStatistics ( AS );
-  AS.Finish();
-}
-
-void  CChain::CalcAtomStatistics ( RSAtomStat AS )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])
-      Residue[i]->CalcAtomStatistics ( AS );
-}
-
-void  CChain::ApplyTransform ( mat44 & TMatrix )  {
-// transforms all coordinates by multiplying with matrix TMatrix
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  Residue[i]->ApplyTransform ( TMatrix );
-}
-
-Boolean CChain::isSolventChain()  {
-// returns True if chain contains only solvent molecules
-Boolean B,P;
-int     i;
-  B = True;
-  P = False;
-  for (i=0;(i<nResidues) && B;i++)
-    if (Residue[i])  {
-      P = True;
-      B = Residue[i]->isSolvent();
-    }
-  return (B && P);
-}
-
-Boolean CChain::isInSelection ( int selHnd )  {
-PCMMDBFile mmdbfile = (PCMMDBFile)GetCoordHierarchy();
-PCMask     Mask;
-  if (mmdbfile)  {
-    Mask = mmdbfile->GetSelMask ( selHnd );
-    if (Mask)  return CheckMask ( Mask );
-  }
-  return False;
-}
-
-Boolean CChain::isAminoacidChain()  {
-// returns True if chain contains at least one aminoacid residue
-Boolean B,P;
-int     i;
-  B = False;
-  P = False;
-  for (i=0;(i<nResidues) && (!B);i++)
-    if (Residue[i])  {
-      P = True;
-      B = Residue[i]->isAminoacid();
-    }
-  return (B && P);
-}
-
-Boolean CChain::isNucleotideChain()  {
-// returns True if chain contains at least one nucleotide residue
-Boolean B,P;
-int     i;
-  B = False;
-  P = False;
-  for (i=0;(i<nResidues) && (!B);i++)
-    if (Residue[i])  {
-      P = True;
-      B = Residue[i]->isNucleotide();
-    }
-  return (B && P);
-}
-
-int  CChain::CheckID ( const ChainID chID )  {
-  if (chID)  {
-    if (!strcmp(chID,chainID))  return 1;
-  }
-  return 0;
-}
-
-int  CChain::CheckIDS ( cpstr CID )  {
-ChainID  chn;
-InsCode  inscode;
-ResName  resname;
-AtomName atm;
-Element  elm;
-AltLoc   aloc;
-int      mdl,sn,rc;
-
-  rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
-                       atm,elm,aloc,NULL );
-  if (rc>=0)  {
-    if (!strcmp(chn,chainID))  return 1;
-  }
-  return 0;
-
-}
-
-int  CChain::GetNumberOfDBRefs()  {
-  return  DBReference.Length();
-}
-
-PCDBReference  CChain::GetDBRef ( int dbRefNo )  {
-  return  (PCDBReference)DBReference.GetContainerClass ( dbRefNo );
-}
-
-
-void  CChain::MaskAtoms ( PCMask Mask )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  Residue[i]->MaskAtoms ( Mask );
-}
-
-void  CChain::MaskResidues ( PCMask Mask )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  Residue[i]->SetMask ( Mask );
-}
-
-void  CChain::UnmaskAtoms ( PCMask Mask )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  Residue[i]->UnmaskAtoms ( Mask );
-}
-
-void  CChain::UnmaskResidues ( PCMask Mask )  {
-int i;
-  for (i=0;i<nResidues;i++)
-    if (Residue[i])  Residue[i]->RemoveMask ( Mask );
-}
-
-
-
-
-// -------  user-defined data handlers
-
-int  CChain::PutUDData ( int UDDhandle, int iudd )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::putUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CChain::PutUDData ( int UDDhandle, realtype rudd )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::putUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CChain::PutUDData ( int UDDhandle, cpstr sudd )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::putUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CChain::GetUDData ( int UDDhandle, int & iudd )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::getUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CChain::GetUDData ( int UDDhandle, realtype & rudd )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::getUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CChain::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::getUDData ( UDDhandle,sudd,maxLen );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CChain::GetUDData ( int UDDhandle, pstr & sudd )  {
-  if (UDDhandle & UDRF_CHAIN)
-        return  CUDData::getUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-
-//  -------------------------------------------------------------------
-
-DefineClass(CSortResidues)
-
-class CSortResidues : public CQuickSort  {
-  public :
-    CSortResidues() : CQuickSort() {}
-    int  Compare ( int i, int j );
-    void Swap    ( int i, int j );
-    void Sort    ( PPCResidue res, int nresidues );
-};
-
-int CSortResidues::Compare ( int i, int j )  {
-int diff;
-  diff = ((PPCResidue)data)[i]->seqNum - ((PPCResidue)data)[j]->seqNum;
-  if (diff==0)
-    diff = strcmp( (PPCResidue(data))[i]->insCode,
-                   (PPCResidue(data))[j]->insCode );
-  if (diff>0)  return  1;
-  if (diff<0)  return -1;
-  return 0;
-}
-
-void CSortResidues::Swap ( int i, int j )  {
-PCResidue res;
-  res = ((PPCResidue)data)[i];
-  ((PPCResidue)data)[i] = ((PPCResidue)data)[j];
-  ((PPCResidue)data)[j] = res;
-}
-
-void CSortResidues::Sort ( PPCResidue res, int nresidues )  {
-  CQuickSort::Sort ( &(res[0]),nresidues );
-}
-
-void  CChain::SortResidues()  {
-CSortResidues SR;
-  TrimResidueTable();
-  SR.Sort ( Residue,nResidues );
-}
-
-int  CChain::GetNofModResidues()  {
-  return ModRes.Length();
-}
-
-PCModRes  CChain::GetModResidue ( int modResNo )  {
-  return  PCModRes(ModRes.GetContainerClass(modResNo));
-}
-
-void  CChain::write ( RCFile f )  {
-int  i;
-byte Version=1;
-
-  f.WriteByte ( &Version );
-
-  CUDData::write ( f );
-
-  f.WriteTerLine ( chainID    ,False );
-  f.WriteTerLine ( prevChainID,False );
-
-  DBReference.write ( f );  //  Database reference
-  SeqAdv     .write ( f );  //  SEQADV records
-  SeqRes     .write ( f );  //  SEQRES data
-  ModRes     .write ( f );  //  MODRES records
-  Het        .write ( f );  //  HET    records
-
-  f.WriteInt ( &nResidues );
-  for (i=0;i<nResidues;i++)
-    Residue[i]->write ( f );
-
-}
-
-void  CChain::read ( RCFile f )  {
-//   The Atom array in CMMDBFile must be already read
-// prior to calling this function!
-int  i;
-byte Version;
-
-  FreeMemory();
-
-  f.ReadByte ( &Version );
-
-  CUDData::read ( f );
-
-  f.ReadTerLine ( chainID    ,False );
-  f.ReadTerLine ( prevChainID,False );
-
-  DBReference.read ( f );   //  Database reference
-  SeqAdv     .read ( f );   //  SEQADV records
-  SeqRes     .read ( f );   //  SEQRES data
-  ModRes     .read ( f );   //  MODRES records
-  Het        .read ( f );   //  HET    records
-
-  SetChain ( chainID );
-
-  f.ReadInt ( &nResidues );
-  ResLen = nResidues;
-  if (nResidues>0)  {
-    Residue = new PCResidue[nResidues];
-    for (i=0;i<nResidues;i++)  {
-      Residue[i] = newCResidue();
-      Residue[i]->SetChain ( this );
-      Residue[i]->read ( f );
-    }
-  }
-
-}
-
-
-MakeFactoryFunctions(CChain)
-
-
-
-// ===================================================================
-
-  /*
-void  TestChain() {
-//  reads from 'in.chain', writes into
-//  'out.chain' and 'abin.chain'
-CFile    f;
-char     S[81];
-PCChain  Chain;
-
-  Chain = newCChain();
-
-  f.assign ( "in.chain",True );
-  if (f.reset()) {
-    while (!f.FileEnd()) {
-      f.ReadLine ( S,sizeof(S) );
-      Chain->ConvertPDBString ( S );
-    }
-    f.shut();
-  } else {
-    printf ( " Can't open input file 'in.chain' \n" );
-    delete Chain;
-    return;
-  }
-
-  f.assign ( "out.chain",True );
-  if (f.rewrite()) {
-    Chain->PDBASCIIDump ( f );
-    f.shut();
-  } else {
-    printf ( " Can't open output file 'out.chain' \n" );
-    delete Chain;
-    return;
-  }
-
-
-  f.assign ( "mmdb.chain.bin",False );
-  if (f.rewrite()) {
-    Chain->write ( f );
-    f.shut();
-  } else {
-    printf ( "  Can't open binary chain file for writing.\n" );
-    delete Chain;
-    return;
-  }
-
-  delete Chain;
-  printf ( "   Chain deleted.\n" );
-
-  Chain = newCChain();
-  if (f.reset()) {
-    Chain->read ( f );
-    f.shut();
-  } else {
-    printf ( "  Can't open binary chain file for reading.\n" );
-    delete Chain;
-    return;
-  }
-
-  f.assign ( "abin.chain",True );
-  if (f.rewrite()) {
-    Chain->PDBASCIIDump ( f );
-    f.shut();
-  } else
-    printf ( " Can't open output file 'abin.chain' \n" );
-
-  delete Chain;
-
-}
-  */
diff --git a/mmdb/mmdb_chain.h b/mmdb/mmdb_chain.h
deleted file mode 100755
index bd095d8..0000000
--- a/mmdb/mmdb_chain.h
+++ /dev/null
@@ -1,674 +0,0 @@
-//  $Id: mmdb_chain.h,v 1.22 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Chain <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CProModel       ( a virtue of CModel              )
-//       ~~~~~~~~~  CChainContainer ( container of in-chain classes   )
-//                  CContainerChain ( chain containered class template)
-//                  CDBReference    ( DBREF  records                  )
-//                  CSeqAdv         ( SEQADV records                  )
-//                  CSeqRes         ( SEQRES records                  )
-//                  CModRes         ( MODRES records                  )
-//                  CHetRec         ( HET    records                  )
-//                  CChain          ( chain class                     )
-//
-//  Copyright (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Chain__
-#define __MMDB_Chain__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_Utils__
-#include "mmdb_utils.h"
-#endif
-
-#ifndef  __MMDB_Atom__
-#include "mmdb_atom.h"
-#endif
-
-
-//  ====================  CProModel  ======================
-
-//    This class is a virtue needed only for defining certain
-// functions of CModel, which are used by CChain and
-// CResidue
-
-DefineClass(CProModel);
-DefineStreamFunctions(CProModel);
-
-DefineClass(CMMDBManager);
-
-class CProModel : public CUDData  {
-
-  friend class CChain;
-
-  public :
-
-    CProModel  () : CUDData () {}
-    CProModel  ( RPCStream Object ) : CUDData ( Object ) {} 
-    ~CProModel () {}
-
-    virtual cpstr GetEntryID () { return ""; }
-    virtual void  SetEntryID ( const IDCode ) {}
-
-    virtual int   AddChain ( PCChain ) { return 0; }
-
-    // returns pointer to CMMDBFile
-    virtual PCMMDBManager GetCoordHierarchy() { return NULL; }
-
-    //  GetNumberOfModels() returns TOTAL number of models
-    virtual int GetNumberOfModels() { return 0;    }
-
-    //  GetNumberOfAllAtoms() returns TOTAL number of atoms in
-    // all models
-    virtual int GetNumberOfAllAtoms() { return 0;    }
-
-    //  returns pointer to the general Atom array
-    virtual PPCAtom     GetAllAtoms() { return NULL; }
-
-    virtual int  GetSerNum       () { return 0; }
-
-    virtual void ExpandAtomArray ( int )  {}
-    virtual void AddAtomArray    ( int )  {}
-
-  protected :
-
-    virtual int  _ExcludeChain ( const ChainID ) { return 0; }
-
-};
-
-
-
-//  ====================  CChainContainer  ======================
-
-DefineClass(CChainContainer);
-DefineStreamFunctions(CChainContainer);
-
-class CChainContainer : public CClassContainer  {
-
-  public :
-
-    CChainContainer  () : CClassContainer () {}
-    CChainContainer  ( RPCStream Object )
-                        : CClassContainer ( Object ) {} 
-    ~CChainContainer () {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-    void  SetChain ( PCChain Chain_Owner ); // must be set before using
-                                            // the Container
-    
-    // special functions used in CModel::GetCIF(..)
-    cpstr Get1stChainID ();
-    void  MoveByChainID ( const ChainID chainID,
-                          PCChainContainer ChainContainer );
-
-  protected :
-    PCChain Chain;
-
-};
-
-
-//  ==================  CContainerChain  =====================
-
-DefineClass(CContainerChain);
-DefineStreamFunctions(CContainerChain);
-
-class CContainerChain : public CContainerClass {
-
-  friend class CChainContainer;
-
-  public :
-
-    CContainerChain ();
-    CContainerChain ( PCChain Chain_Owner );
-    CContainerChain ( RPCStream Object    ) : CContainerClass(Object){}
-
-    void SetChain   ( PCChain Chain_Owner );
-
-  protected :
-    PCChain Chain;
-    ChainID chainID;  // just a copy of Chain->chainID
-
-};
-
-
-//  ==================  CDBReference  ========================
-
-DefineClass(CDBReference);
-DefineStreamFunctions(CDBReference);
-
-class CDBReference : public CContainerChain  {
-
-  public :
-
-    int      seqBeg;      // initial seq num of the PDB seq-ce segment
-    InsCode  insBeg;      // initial ins code of the PDB seq-ce segm-t
-    int      seqEnd;      // ending seq number of the PDB seq-ce segm-t
-    InsCode  insEnd;      // ending ins code of the PDB seq-ce segment
-    DBName   database;    // sequence database name
-    DBAcCode dbAccession; // sequence database accession code
-    DBIdCode dbIdCode;    // sequence database identification code
-    int      dbseqBeg;    // initial seq number of the database segment
-    InsCode  dbinsBeg;    // ins code of initial residue of the segment
-    int      dbseqEnd;    // ending seq number of the database segment
-    InsCode  dbinsEnd;   // ins code of the ending residue of the seg-t
-    
-    CDBReference ();
-    CDBReference ( PCChain Chain_Owner );
-    CDBReference ( PCChain Chain_Owner, cpstr S );
-    CDBReference ( RPCStream Object );
-    ~CDBReference();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_DBReference; }
-
-    void  Copy  ( PCContainerClass DBRef );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitDBReference();
-
-};
-
-
-//  ====================  CSeqAdv  ===========================
-
-DefineClass(CSeqAdv);
-DefineStreamFunctions(CSeqAdv);
-
-class CSeqAdv : public CContainerChain  {
-
-  public :
- 
-    ResName  resName;     // residue name in conflict
-    int      seqNum;      // residue sequence number
-    InsCode  insCode;     // residue insertion code
-    DBName   database;    // sequence database name
-    DBAcCode dbAccession; // sequence database accession code
-    ResName  dbRes;       // sequence database residue name
-    int      dbSeq;       // sequence database sequence number
-    pstr     conflict;    // conflict comment
-    
-    CSeqAdv ();
-    CSeqAdv ( PCChain Chain_Owner );
-    CSeqAdv ( PCChain Chain_Owner, cpstr S );
-    CSeqAdv ( RPCStream Object );
-    ~CSeqAdv();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    int   ConvertPDBASCII ( cpstr S );
-
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-
-    int   GetClassID      () { return ClassID_SeqAdv; }
-
-    void  Copy  ( PCContainerClass SeqAdv );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitSeqAdv();
-
-};
-
-
-//  ==================  CSeqRes  ========================
-
-DefineClass(CSeqRes);
-DefineStreamFunctions(CSeqRes);
-
-class CSeqRes : public CStream  {
-
-  friend class CModel;
-  friend class CChain;
-
-  public :
- 
-    int       numRes;   // number of residues in the chain
-    PResName  resName;  // residue names
-    
-    CSeqRes ();
-    CSeqRes ( RPCStream Object );
-    ~CSeqRes();
-
-    void  SetChain        ( PCChain Chain_Owner );
-    void  PDBASCIIDump    ( RCFile f );
-    int   ConvertPDBASCII ( cpstr  S );
-
-    void  MakeCIF         ( PCMMCIFData CIF );
-    int   GetCIF          ( PCMMCIFData CIF );
-
-    void  Copy  ( PCSeqRes SeqRes );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    PCChain Chain;
-    ChainID chainID;
-    int     serNum;
-
-    void InitSeqRes();
-    void FreeMemory();
-
-};
-
-
-//  ==================  CModRes  ========================
-
-DefineClass(CModRes);
-DefineStreamFunctions(CModRes);
-
-class CModRes : public CContainerChain  {
-
-  public :
- 
-    ResName  resName;     // residue name used
-    int      seqNum;      // residue sequence number
-    InsCode  insCode;     // residue insertion code
-    ResName  stdRes;      // standard residue name
-    pstr     comment;     // description of the residue modification
-    
-    CModRes ();
-    CModRes ( PCChain Chain_Owner );
-    CModRes ( PCChain Chain_Owner, cpstr S );
-    CModRes ( RPCStream Object );
-    ~CModRes();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_ModRes; }
-
-    void  Copy  ( PCContainerClass ModRes );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitModRes();
-
-};
-
-
-//  ==================  CHetRec  ===========================
-
-DefineClass(CHetRec);
-DefineStreamFunctions(CHetRec);
-
-class CHetRec : public CContainerChain  {
-
-  public :
- 
-    ResName  hetID;       // Het identifier (right-justified)
-    int      seqNum;      // sequence number
-    InsCode  insCode;     // insertion code
-    int      numHetAtoms; // number of HETATM records for the
-                          // group present in the entry
-    pstr     comment;     // text describing Het group
-    
-    CHetRec ();
-    CHetRec ( PCChain Chain_Owner );
-    CHetRec ( PCChain Chain_Owner, cpstr S );
-    CHetRec ( RPCStream Object );
-    ~CHetRec();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_Het; }
-
-    void  Copy  ( PCContainerClass Het );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitHetRec();
-
-};
-
-
-//  =================  CChain  =======================
-
-DefineFactoryFunctions(CChain);
-
-class CChain : public CUDData  {
-
-  friend class CDBReference;
-  friend class CSeqAdv;
-  friend class CSeqRes;
-  friend class CModRes;
-  friend class CHetRec;
-  friend class CResidue;
-  friend class CAtom;
-  friend class CModel;
-  friend class CMMDBFile;
-  friend class CMMDBSelManager;
-  friend class CMMDBBondManager;
-  friend class CMMDBCoorManager;
-  friend class CMMDBManager;
-
-  public :
-
-    CChainContainer DBReference; // database reference
-    CChainContainer SeqAdv;      // SEQADV records
-    CSeqRes         SeqRes;      // Sequence residues, SEQRES records
-    CChainContainer ModRes;      // modification descriptions
-    CChainContainer Het;         // non-standard residues descriptions
-
-    CChain ();  // SetModel() MUST be used after this constructor!
-    CChain ( PCProModel Model, const ChainID chID );
-    CChain ( RPCStream Object );
-    ~CChain();
-
-    void FreeAnnotations();
-
-    void SetModel ( PCProModel    Model );
-    void SetChain ( const ChainID chID  );
-
-    PCMMDBManager GetCoordHierarchy();   // PCMMDBFile
-
-    //   ConvertXXXXX(..) functions do not check for record name
-    // and assume that PDBString is at least 81 symbols long
-    // (including the terminating null).
-    int  ConvertDBREF  ( cpstr PDBString );
-    int  ConvertSEQADV ( cpstr PDBString );
-    int  ConvertSEQRES ( cpstr PDBString );
-    int  ConvertMODRES ( cpstr PDBString );
-    int  ConvertHET    ( cpstr PDBString );
-
-    // This function should be used for testing purposes only.
-    // A full PDB ASCII dump for all models and chains involved
-    // is done by CMMDBFile class. 
-    void  PDBASCIIDump     ( RCFile f );
-
-    void  PDBASCIIAtomDump ( RCFile      f   );
-    void  MakeAtomCIF      ( PCMMCIFData CIF );
-
-
-    //  -----------------  Extracting residues  -------------------------
-
-    int GetNumberOfResidues(); // returns number of res-s in the chain
-    PCResidue GetResidue   ( int resNo ); // returns resNo-th residue
-                                          // in the chain;
-                                          // 0<=resNo<nResidues
-
-    //   GetResidue(..) returns pointer on residue, whose sequence
-    // number and insert code are given in seqNum and insCode,
-    // respectively. If such a residue is absent in the chain,
-    // returns NULL.
-    PCResidue GetResidue ( int seqNum, const InsCode insCode );
-
-    //   GetResidueNo(..) returns the residue number in the chain's
-    // residues table. Residues are numbered as 0..nres-1 as they
-    // appear in the coordinate file.
-    //   If residue is not found, the function returns -1.
-    int  GetResidueNo ( int seqNum, const InsCode insCode );
-
-    void GetResidueTable ( PPCResidue & resTable,
-                           int & NumberOfResidues );
-
-    //   GetResidueCreate(..) returns pointer on residue, whose name,
-    // sequence number and insertion code are given by resName, seqNum
-    // and insCode, respectively. If such a residue is absent in the
-    // chain, one is created at the end of chain.
-    //   If a residue with given sequence number and insertion code
-    // is present in the chain but has a different name, the function
-    // returns NULL unless Enforce is set True. In the latter case,
-    // a new residue is still created at the end of chain, but there
-    // is no guarantee that any function operating on the sequence
-    // number and insertion code will work properly.
-    PCResidue GetResidueCreate ( const ResName resName, int seqNum,
-                             const InsCode insCode, Boolean Enforce );
-
-
-    //  ------------------  Deleting residues  ----------------------
-
-    int  DeleteResidue ( int resNo ); // returns num of deleted res-s
-    int  DeleteResidue ( int seqNum, const InsCode insCode );
-    int  DeleteAllResidues();
-    int  DeleteSolvent    ();
-    void TrimResidueTable ();  // do not forget to call after all dels
-
-    //  -------------------  Adding residues  -----------------------
-
-    //   AddResidue(..) adds residue to the chain, InsResidue inserts
-    // the residue on the specified position of the chain (other
-    // residues are shifted up to the end of chain). Position in the
-    // chain may be specified by a serial number (that is position in
-    // the residue table) or by seqNum and insCode of one of the
-    // chain's residues (the new residue is then inserted before that
-    // one). If the chain is associated with a coordinate hierarchy,
-    // and residue 'res' is not, the latter is checked in
-    // automatically. If residue 'res' belongs to any coordinate
-    // hierarchy (even though that of the residue), it is *copied*
-    // rather than simply taken over, and is checked in.
-    //   If the chain is not associated with a coordinate hierarchy,
-    // all added residues will be checked in automatically once the
-    // chain is checked in.
-    int  AddResidue ( PCResidue res );
-    int  InsResidue ( PCResidue res, int pos );
-    int  InsResidue ( PCResidue res, int seqNum,
-                      const InsCode insCode );
-
-    //  --------------------  Extracting atoms  ---------------------
-
-    int  GetNumberOfAtoms ( Boolean countTers );
-    int  GetNumberOfAtoms ( int seqNo, const InsCode insCode );
-    int  GetNumberOfAtoms ( int resNo );
-
-    PCAtom GetAtom ( int            seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    PCAtom GetAtom ( int seqNo, const InsCode insCode, int atomNo );
-    PCAtom GetAtom ( int            resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    PCAtom GetAtom ( int resNo, int atomNo );
-
-    void GetAtomTable ( int seqNo, const InsCode insCode,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int resNo,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-
-    //   GetAtomTable1(..) returns atom table without TER atoms and
-    // without NULL atom pointers. NumberOfAtoms returns the actual
-    // number of atom pointers in atomTable.
-    //   atomTable is allocated withing the function. If it was
-    // not set to NULL before calling the function, the latter will
-    // attempt to deallocate it first.
-    //   The application is responsible for deleting atomTable,
-    // however it must not touch atom pointers, i.e. use simply
-    // "delete[] atomTable;". Never pass atomTable from
-    // GetAtomTable(..) into this function, unless you set it to NULL
-    // before doing that.
-    void GetAtomTable1 ( int seqNo, const InsCode insCode,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int resNo,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-
-    //  ---------------------  Deleting atoms  ----------------------
-
-    int DeleteAtom ( int            seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int           seqNo,
-                     const InsCode insCode,
-                     int           atomNo );
-    int DeleteAtom ( int            resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int resNo, int atomNo );
-
-    int DeleteAllAtoms ( int seqNo, const InsCode insCode );
-    int DeleteAllAtoms ( int resNo );
-    int DeleteAllAtoms ();
-
-    //  DeleteAltLocs() leaves only alternative location with maximal
-    // occupancy, if those are equal or unspecified, the one with
-    // "least" alternative location indicator.
-    //  The function returns the number of deleted. All tables remain
-    // untrimmed, so that explicit trimming or calling
-    // FinishStructEdit() is required.
-    int DeleteAltLocs();
-
-    //  ----------------------  Adding atoms  -----------------------
-
-    int AddAtom ( int seqNo, const InsCode insCode, PCAtom atom );
-    int AddAtom ( int resNo, PCAtom atom );
-
-    //  -------------------------------------------------------------
-
-    void  ApplyTransform ( mat44 & TMatrix );  // transforms all
-                                         // coordinates by multiplying
-                                         // with matrix TMatrix
-
-    int   GetModelNum();
-    PCModel GetModel () { return (PCModel)model; }
-    cpstr GetChainID () { return chainID; }
-    void  SetChainID ( const ChainID chID );
-    cpstr GetChainID ( pstr  ChID );  // returns /m/c
-
-    void  GetAtomStatistics  ( RSAtomStat AS );
-    void  CalcAtomStatistics ( RSAtomStat AS );
-
-    int   CheckID    ( const ChainID chID );
-    int   CheckIDS   ( cpstr CID  );
-
-    cpstr GetEntryID ();
-    void  SetEntryID ( const IDCode idCode );
-
-    int   GetNumberOfDBRefs ();
-    PCDBReference  GetDBRef ( int dbRefNo );  // 0..nDBRefs-1
-
-    void  MaskAtoms      ( PCMask Mask );
-    void  MaskResidues   ( PCMask Mask );
-    void  UnmaskAtoms    ( PCMask Mask );
-    void  UnmaskResidues ( PCMask Mask );
-
-    void  SortResidues   ();
-
-    int       GetNofModResidues();
-    PCModRes  GetModResidue    ( int modResNo );  // 0.. on
-
-    Boolean   isSolventChain   ();
-    Boolean   isInSelection    ( int selHnd );
-    Boolean   isAminoacidChain ();
-    Boolean   isNucleotideChain();
-
-
-    // -------  user-defined data handlers
-    int   PutUDData ( int UDDhandle, int      iudd );
-    int   PutUDData ( int UDDhandle, realtype rudd );
-    int   PutUDData ( int UDDhandle, cpstr    sudd );
-
-    int   GetUDData ( int UDDhandle, int      & iudd );
-    int   GetUDData ( int UDDhandle, realtype & rudd );
-    int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
-    int   GetUDData ( int UDDhandle, pstr     & sudd );
-
-    void  Copy            ( PCChain Chain );
-    void  CopyAnnotations ( PCChain Chain );
-
-    void  write ( RCFile f );    // writes header to PDB binary file
-    void  read  ( RCFile f );    // reads header from PDB binary file
-
-  protected :
-
-    ChainID         chainID;     // chain ID
-    ChainID         prevChainID; // if chain is renamed, its original
-                                 // name may be saved here.
-    PCProModel      model;       // pointer to model class
-
-    int             nWeights;    // used externally for sorting
-    realtype        Weight;      //   chains
-
-    int             nResidues;   // number of residues
-    PPCResidue      Residue;     // array of residues
-
-    Boolean         Exclude;     // used internally
-
-    void  InitChain ();
-    void  FreeMemory();
-
-    void  ExpandResidueArray ( int inc );
-    //   _ExcludeResidue(..) excludes (but does not dispose!) a residue
-    // from the chain. Returns 1 if the chain gets empty and 0
-    // otherwise.
-    int   _ExcludeResidue ( const ResName resName, int seqNum,
-                            const InsCode insCode );
-    void  _copy ( PCChain Chain );
-    void  _copy ( PCChain Chain, PPCAtom atom, int & atom_index );
-    void  CheckInAtoms();
-
-  private :
-    int  ResLen;      // length of Residue array
-
-};
-
-
-extern void  TestChain();  //  reads from 'in.chain', writes into 
-                           //  'out.chain' and 'abin.chain'
-
-#endif
-
diff --git a/mmdb/mmdb_cifdefs.cpp b/mmdb/mmdb_cifdefs.cpp
deleted file mode 100755
index 48ed20f..0000000
--- a/mmdb/mmdb_cifdefs.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-//  $Id: mmdb_cifdefs.cpp,v 1.19 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.12.00   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_Defs <implementation>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//      CIF Definitions
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-
-// ------------------------------------------------------------------
-
-pstr CIFName ( int NameID, int Mode )  {
-//  Gives CIF name according to CIF Mode.
-
-  switch (Mode)  {
-
-    case CIF_NDB :
-
-      switch (NameID)  {
-        case CAT_POLY_SEQ_SCHEME        :
-                  return CIFCAT_NDB_POLY_SEQ_SCHEME;
-        case TAG_ID_CODE                :
-                  return CIFTAG_NDB_PDB_ID_CODE;
-        case TAG_CHAIN_ID               :
-                  return CIFTAG_NDB_CHAIN_ID;
-        case TAG_SEQ_ALIGN_BEG          :
-                  return CIFTAG_SEQ_ALIGN_BEG;
-        case TAG_SEQ_ALIGN_BEG_INS_CODE :
-                  return CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE;
-        case TAG_SEQ_ALIGN_END          :
-                  return CIFTAG_SEQ_ALIGN_END;
-        case TAG_SEQ_ALIGN_END_INS_CODE :
-                  return CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE;
-        case TAG_DB_ACCESSION           :
-                  return CIFTAG_NDB_DB_ACCESSION;
-        case TAG_DB_ALIGN_BEG           :
-                  return CIFTAG_DB_ALIGN_BEG;
-        case TAG_DB_ALIGN_BEG_INS_CODE  :
-                  return CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE;
-        case TAG_DB_ALIGN_END           :
-                  return CIFTAG_DB_ALIGN_END;
-        case TAG_DB_ALIGN_END_INS_CODE  :
-                  return CIFTAG_NDB_DB_ALIGN_END_INS_CODE;
-        case TAG_SEQ_CHAIN_ID           :
-                  return CIFTAG_ID;
-        default : return pstr("ERROR_IN_CIF_NAME_1");
-      }
-
-    case CIF_PDBX :
-
-      switch (NameID)  {
-        case CAT_POLY_SEQ_SCHEME        :
-                  return CIFCAT_PDBX_POLY_SEQ_SCHEME;
-        case TAG_ID_CODE                :
-                  return CIFTAG_PDBX_PDB_ID_CODE;
-        case TAG_CHAIN_ID               :
-                  return CIFTAG_PDBX_STRAND_ID;
-        case TAG_SEQ_ALIGN_BEG          :
-                  return CIFTAG_SEQ_ALIGN_BEG;
-        case TAG_SEQ_ALIGN_BEG_INS_CODE :
-                  return CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE;
-        case TAG_SEQ_ALIGN_END          :
-                  return CIFTAG_SEQ_ALIGN_END;
-        case TAG_SEQ_ALIGN_END_INS_CODE :
-                  return CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE;
-        case TAG_DB_ACCESSION           :
-                  return CIFTAG_PDBX_DB_ACCESSION;
-        case TAG_DB_ALIGN_BEG           :
-                  return CIFTAG_DB_ALIGN_BEG;
-        case TAG_DB_ALIGN_BEG_INS_CODE  :
-                  return CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE;
-        case TAG_DB_ALIGN_END           :
-                  return CIFTAG_DB_ALIGN_END;
-        case TAG_DB_ALIGN_END_INS_CODE  :
-                  return CIFTAG_PDBX_DB_ALIGN_END_INS_CODE;
-        case TAG_SEQ_CHAIN_ID           :
-                  return CIFTAG_ASYM_ID;
-        default : return pstr("ERROR_IN_CIF_NAME_2");
-      }
-
-    default : return pstr("ERROR_IN_CIF_NAME_3");
-
-  }
-
-}
-
diff --git a/mmdb/mmdb_cifdefs.h b/mmdb/mmdb_cifdefs.h
deleted file mode 100755
index 045ee77..0000000
--- a/mmdb/mmdb_cifdefs.h
+++ /dev/null
@@ -1,327 +0,0 @@
-//  $Id: mmdb_cifdefs.h,v 1.21 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    06.02.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_Defs <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//      CIF Definitions
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_CIFDefs__
-#define __MMDB_CIFDefs__
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-// ------------------------------------------------------------------
-
-//  Mode IDs
-
-#define CIF_NDB   0
-#define CIF_PDBX  1
-
-
-//  CIF IDs for mode-dependent CIF names
-
-
-#define CAT_POLY_SEQ_SCHEME              1
-
-#define TAG_CHAIN_ID                   101
-#define TAG_DB_ACCESSION               102
-#define TAG_DB_ALIGN_BEG               103
-#define TAG_DB_ALIGN_BEG_INS_CODE      104
-#define TAG_DB_ALIGN_END               105
-#define TAG_DB_ALIGN_END_INS_CODE      106
-#define TAG_ID_CODE                    107
-#define TAG_SEQ_CHAIN_ID               108
-#define TAG_SEQ_ALIGN_BEG              109
-#define TAG_SEQ_ALIGN_BEG_INS_CODE     110
-#define TAG_SEQ_ALIGN_END              111
-#define TAG_SEQ_ALIGN_END_INS_CODE     112
-
-//  CIFName(..) gives CIF name according to CIF Mode.
-extern pstr CIFName ( int NameID, int Mode );
-
-// ------------------------------------------------------------------
-
-
-#define CIFCAT_ATOM_SITE                   pstr("_atom_site")
-#define CIFCAT_ATOM_SITE_ANISOTROP         pstr("_atom_site_anisotrop")
-#define CIFCAT_ATOM_SITES                  pstr("_atom_sites")
-#define CIFCAT_AUDIT_AUTHOR                pstr("_audit_author")
-#define CIFCAT_CELL                        pstr("_cell")
-#define CIFCAT_CHEM_COMP                   pstr("_chem_comp")
-#define CIFCAT_CITATION                    pstr("_citation")
-#define CIFCAT_DATABASE                    pstr("_database")
-#define CIFCAT_DATABASE_PDB_CAVEAT         pstr("_database_pdb_caveat")
-#define CIFCAT_DATABASE_PDB_MATRIX         pstr("_database_pdb_matrix")
-#define CIFCAT_DATABASE_PDB_REV            pstr("_database_pdb_rev")
-#define CIFCAT_DATABASE_PDB_TVECT          pstr("_database_pdb_tvect")
-#define CIFCAT_ENTITY                      pstr("_entity")
-#define CIFCAT_EXPTL                       pstr("_exptl")
-#define CIFCAT_NDB_DATABASE_REMARK         pstr("_ndb_database_remark")
-#define CIFCAT_NDB_NONSTANDARD_LIST        pstr("_ndb_nonstandard_list")
-#define CIFCAT_NDB_POLY_SEQ_SCHEME         pstr("_ndb_poly_seq_scheme")
-#define CIFCAT_PDBX_POLY_SEQ_SCHEME        pstr("_pdbx_poly_seq_scheme")
-#define CIFCAT_SPRSDE                      pstr("_ndb_database_pdb_obs_spr")
-#define CIFCAT_STRUCT                      pstr("_struct")
-#define CIFCAT_STRUCT_ASYM                 pstr("_struct_asym")
-#define CIFCAT_STRUCT_CONF                 pstr("_struct_conf")
-#define CIFCAT_STRUCT_CONN                 pstr("_struct_conn")
-#define CIFCAT_STRUCT_LINKR                cpstr("_struct_linkr")
-#define CIFCAT_STRUCT_KEYWORDS             pstr("_struct_keywords")
-#define CIFCAT_STRUCT_NCS_OPER             pstr("_struct_ncs_oper")
-#define CIFCAT_STRUCT_REF                  pstr("_struct_ref")
-#define CIFCAT_STRUCT_REF_SEQ              pstr("_struct_ref_seq")
-#define CIFCAT_STRUCT_REF_SEQ_DIF          pstr("_struct_ref_seq_dif")
-#define CIFCAT_STRUCT_SHEET                pstr("_struct_sheet")
-#define CIFCAT_STRUCT_SHEET_RANGE          pstr("_struct_sheet_range")
-#define CIFCAT_STRUCT_SHEET_ORDER          pstr("_struct_sheet_order")
-#define CIFCAT_STRUCT_SHEET_HBOND          pstr("_struct_sheet_hbond")
-#define CIFCAT_SYMMETRY                    pstr("_symmetry")
-#define CIFCAT_OBSLTE                      pstr("_ndb_database_pdb_obs_spr")
-
-
-#define CIFTAG_ANGLE_ALPHA                    pstr("angle_alpha")
-#define CIFTAG_ANGLE_BETA                     pstr("angle_beta")
-#define CIFTAG_ANGLE_GAMMA                    pstr("angle_gamma")
-#define CIFTAG_ASYM_ID                        pstr("asym_id")
-#define CIFTAG_ATOM_TYPE_SYMBOL               pstr("atom_type_symbol")
-#define CIFTAG_AUTH_ASYM_ID                   pstr("auth_asym_id")
-#define CIFTAG_AUTH_ATOM_ID                   pstr("auth_atom_id")
-#define CIFTAG_AUTH_COMP_ID                   pstr("auth_comp_id")
-#define CIFTAG_AUTH_SEQ_ID                    pstr("auth_seq_id")
-#define CIFTAG_B_ISO_OR_EQUIV                 pstr("B_iso_or_equiv")
-#define CIFTAG_B_ISO_OR_EQUIV_ESD             pstr("B_iso_or_equiv_esd")
-#define CIFTAG_BEG_LABEL_ASYM_ID              pstr("beg_label_asym_id")
-#define CIFTAG_BEG_LABEL_COMP_ID              pstr("beg_label_comp_id")
-#define CIFTAG_BEG_LABEL_SEQ_ID               pstr("beg_label_seq_id")
-#define CIFTAG_CARTN_X                        pstr("cartn_x")
-#define CIFTAG_CARTN_X_ESD                    pstr("cartn_x_esd")
-#define CIFTAG_CARTN_Y                        pstr("cartn_y")
-#define CIFTAG_CARTN_Y_ESD                    pstr("cartn_y_esd")
-#define CIFTAG_CARTN_Z                        pstr("cartn_z")
-#define CIFTAG_CARTN_Z_ESD                    pstr("cartn_z_esd")
-#define CIFTAG_PDBX_FORMAL_CHARGE             pstr("pdbx_formal_charge")
-#define CIFTAG_CODE                           pstr("code")
-#define CIFTAG_CODE_NDB                       pstr("code_NDB")
-#define CIFTAG_CODE_PDB                       pstr("code_PDB")
-#define CIFTAG_CONF_TYPE_ID                   pstr("conf_type_id")
-#define CIFTAG_CONN_TYPE_ID                   pstr("conn_type_id")
-#define CIFTAG_DATE                           pstr("date")
-#define CIFTAG_DATE_ORIGINAL                  pstr("date_original")
-#define CIFTAG_DB_ALIGN_BEG                   pstr("db_align_beg")
-#define CIFTAG_DB_ALIGN_END                   pstr("db_align_end")
-#define CIFTAG_DB_CODE                        pstr("db_code")
-#define CIFTAG_DB_MON_ID                      pstr("db_mon_id")
-#define CIFTAG_DB_NAME                        pstr("db_name")
-#define CIFTAG_DETAILS                        pstr("details")
-#define CIFTAG_END_LABEL_ASYM_ID              pstr("end_label_asym_id")
-#define CIFTAG_END_LABEL_COMP_ID              pstr("end_label_comp_id")
-#define CIFTAG_END_LABEL_SEQ_ID               pstr("end_label_seq_id")
-#define CIFTAG_ENTITY_ID                      pstr("entity_id")
-#define CIFTAG_ENTRY_ID                       pstr("entry_id")
-#define CIFTAG_FORMULA                        pstr("formula")
-#define CIFTAG_FRACT_TRANSF_MATRIX11          pstr("fract_transf_matrix[1][1]")
-#define CIFTAG_FRACT_TRANSF_MATRIX12          pstr("fract_transf_matrix[1][2]")
-#define CIFTAG_FRACT_TRANSF_MATRIX13          pstr("fract_transf_matrix[1][3]")
-#define CIFTAG_FRACT_TRANSF_MATRIX21          pstr("fract_transf_matrix[2][1]")
-#define CIFTAG_FRACT_TRANSF_MATRIX22          pstr("fract_transf_matrix[2][2]")
-#define CIFTAG_FRACT_TRANSF_MATRIX23          pstr("fract_transf_matrix[2][3]")
-#define CIFTAG_FRACT_TRANSF_MATRIX31          pstr("fract_transf_matrix[3][1]")
-#define CIFTAG_FRACT_TRANSF_MATRIX32          pstr("fract_transf_matrix[3][2]")
-#define CIFTAG_FRACT_TRANSF_MATRIX33          pstr("fract_transf_matrix[3][3]")
-#define CIFTAG_FRACT_TRANSF_VECTOR1           pstr("fract_transf_vector[1]")
-#define CIFTAG_FRACT_TRANSF_VECTOR2           pstr("fract_transf_vector[2]")
-#define CIFTAG_FRACT_TRANSF_VECTOR3           pstr("fract_transf_vector[3]")
-#define CIFTAG_GROUP_PDB                      pstr("group_PDB" )
-#define CIFTAG_ID                             pstr("id")
-#define CIFTAG_INS_CODE                       pstr("ins_code")
-#define CIFTAG_LABEL_ALT_ID                   pstr("label_alt_id")
-#define CIFTAG_LABEL_ATOM_ID                  pstr("label_atom_id")
-#define CIFTAG_LABEL_ASYM_ID                  pstr("label_asym_id")
-#define CIFTAG_LABEL_COMP_ID                  pstr("label_comp_id")
-#define CIFTAG_LABEL_ENTITY_ID                pstr("label_entity_id")
-#define CIFTAG_LABEL_SEQ_ID                   pstr("label_seq_id")
-#define CIFTAG_LENGTH_A                       pstr("length_a")
-#define CIFTAG_LENGTH_B                       pstr("length_b")
-#define CIFTAG_LENGTH_C                       pstr("length_c")
-#define CIFTAG_MATRIX11                       pstr("matrix[1][1]")
-#define CIFTAG_MATRIX12                       pstr("matrix[1][2]")
-#define CIFTAG_MATRIX13                       pstr("matrix[1][3]")
-#define CIFTAG_MATRIX21                       pstr("matrix[2][1]")
-#define CIFTAG_MATRIX22                       pstr("matrix[2][2]")
-#define CIFTAG_MATRIX23                       pstr("matrix[2][3]")
-#define CIFTAG_MATRIX31                       pstr("matrix[3][1]")
-#define CIFTAG_MATRIX32                       pstr("matrix[3][2]")
-#define CIFTAG_MATRIX33                       pstr("matrix[3][3]")
-#define CIFTAG_METHOD                         pstr("method")
-#define CIFTAG_MOD_TYPE                       pstr("mod_type")
-#define CIFTAG_MON_ID                         pstr("mon_id")
-#define CIFTAG_NAME                           pstr("name")
-#define CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB     pstr("ndb_beg_label_ins_code_pdb")
-#define CIFTAG_NDB_CHAIN_ID                   pstr("ndb_chain_id")
-#define CIFTAG_NDB_COMPONENT_NO               pstr("ndb_component_no")
-#define CIFTAG_NDB_DESCRIPTOR                 pstr("ndb_descriptor")
-#define CIFTAG_NDB_DB_ACCESSION               pstr("ndb_db_accession")
-#define CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE      pstr("ndb_db_align_beg_ins_code")
-#define CIFTAG_NDB_DB_ALIGN_END_INS_CODE      pstr("ndb_db_align_end_ins_code")
-#define CIFTAG_NDB_END_LABEL_INS_CODE_PDB     pstr("ndb_end_label_ins_code_pdb")
-//#define CIFTAG_NDB_INS_CODE                   pstr("ndb_ins_code")
-#define CIFTAG_PDBX_PDB_INS_CODE              pstr("pdbx_PDB_ins_code")
-#define CIFTAG_NDB_HELIX_CLASS_PDB            pstr("ndb_helix_class_pdb")
-#define CIFTAG_NDB_KEYWORDS                   pstr("ndb_keywords")
-#define CIFTAG_NDB_LABEL_ALT_ID               pstr("ndb_label_alt_id")
-#define CIFTAG_NDB_LABEL_ATOM_ID              pstr("ndb_label_atom_id")
-#define CIFTAG_NDB_LABEL_ASYM_ID              pstr("ndb_label_asym_id")
-#define CIFTAG_NDB_LABEL_COMP_ID              pstr("ndb_label_comp_id")
-#define CIFTAG_NDB_LABEL_INS_CODE             pstr("ndb_label_ins_code")
-#define CIFTAG_NDB_LABEL_SEQ_NUM              pstr("ndb_label_seq_num")
-#define CIFTAG_NDB_LENGTH                     pstr("ndb_length")
-#define CIFTAG_NDB_MODEL                      pstr("ndb_model")
-#define CIFTAG_NDB_PDB_CHAIN_ID               pstr("ndb_pdb_chain_id")
-#define CIFTAG_NDB_PDB_ID                     pstr("ndb_pdb_id")
-#define CIFTAG_NDB_PDB_ID_CODE                pstr("ndb_pdb_id_code")
-#define CIFTAG_NDB_PDB_INS_CODE               pstr("ndb_pdb_ins_code")
-#define CIFTAG_NDB_PTNR1_LABEL_INS_CODE       pstr("ndb_ptnr1_label_ins_code")
-#define CIFTAG_NDB_PTNR1_STANDARD_COMP_ID     pstr("ndb_ptnr1_standard_comp_id")
-#define CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID  pstr("ndb_range_1_beg_label_comp_id")
-#define CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID  pstr("ndb_range_1_beg_label_asym_id")
-#define CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE pstr("ndb_range_1_beg_label_ins_code")
-#define CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID  pstr("ndb_range_1_end_label_comp_id")
-#define CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID  pstr("ndb_range_1_end_label_asym_id")
-#define CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE pstr("ndb_range_1_end_label_ins_code")
-#define CIFTAG_NDB_SEQ_ALIGN_BEG              pstr("ndb_seq_align_beg")
-#define CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE     pstr("ndb_seq_align_beg_ins_code")
-#define CIFTAG_NDB_SEQ_ALIGN_END              pstr("ndb_seq_align_end")
-#define CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE     pstr("ndb_seq_align_end_ins_code")
-#define CIFTAG_NDB_SEQ_DB_NAME                pstr("ndb_seq_db_name")
-#define CIFTAG_NDB_SEQ_DB_ACCESSION_CODE      pstr("ndb_seq_db_accession_code")
-#define CIFTAG_NDB_SEQ_DB_SEQ_NUM             pstr("ndb_seq_db_seq_num")
-#define CIFTAG_NDB_SYNONYMS                   pstr("ndb_synonyms")
-#define CIFTAG_NUM                            pstr("num")
-#define CIFTAG_NUMBER_ATOMS_NH                pstr("number_atoms_nh")
-#define CIFTAG_NUMBER_STRANDS                 pstr("number_strands")
-#define CIFTAG_OCCUPANCY                      pstr("occupancy")
-#define CIFTAG_OCCUPANCY_ESD                  pstr("occupancy_esd")
-#define CIFTAG_ORIGX11                        pstr("origx[1][1]")
-#define CIFTAG_ORIGX12                        pstr("origx[1][2]")
-#define CIFTAG_ORIGX13                        pstr("origx[1][3]")
-#define CIFTAG_ORIGX21                        pstr("origx[2][1]")
-#define CIFTAG_ORIGX22                        pstr("origx[2][2]")
-#define CIFTAG_ORIGX23                        pstr("origx[2][3]")
-#define CIFTAG_ORIGX31                        pstr("origx[3][1]")
-#define CIFTAG_ORIGX32                        pstr("origx[3][2]")
-#define CIFTAG_ORIGX33                        pstr("origx[3][3]")
-#define CIFTAG_ORIGX_VECTOR1                  pstr("origx_vector[1]")
-#define CIFTAG_ORIGX_VECTOR2                  pstr("origx_vector[2]")
-#define CIFTAG_ORIGX_VECTOR3                  pstr("origx_vector[3]")
-#define CIFTAG_PDB_ID                         pstr("pdb_id")
-#define CIFTAG_PDB_MON_ID                     pstr("pdb_mon_id")
-#define CIFTAG_PDB_STRAND_ID                  pstr("pdb_strand_id")
-#define CIFTAG_PDBX_DB_ACCESSION              pstr("pdbx_db_accession")
-#define CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE     pstr("pdbx_db_align_beg_ins_code")
-#define CIFTAG_PDBX_DB_ALIGN_END_INS_CODE     pstr("pdbx_db_align_end_ins_code")
-#define CIFTAG_PDBX_PDB_ID_CODE               pstr("pdbx_PDB_id_code")
-#define CIFTAG_PDBX_PDB_INS_CODE              pstr("pdbx_PDB_ins_code")
-#define CIFTAG_PDBX_PDB_MODEL_NUM             pstr("pdbx_PDB_model_num")
-#define CIFTAG_PDBX_STRAND_ID                 pstr("pdbx_strand_id")
-#define CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID      pstr("range_1_beg_label_atom_id")
-#define CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID       pstr("range_1_beg_label_seq_id")
-#define CIFTAG_RANGE_1_END_LABEL_ATOM_ID      pstr("range_1_end_label_atom_id")
-#define CIFTAG_RANGE_1_END_LABEL_SEQ_ID       pstr("range_1_end_label_seq_id")
-#define CIFTAG_RANGE_ID_1                     pstr("range_id_1")
-#define CIFTAG_RANGE_ID_2                     pstr("range_id_2")
-#define CIFTAG_RCSB_RECORD_REVISED_1          pstr("rcsb_record_revised_1")
-#define CIFTAG_RCSB_RECORD_REVISED_2          pstr("rcsb_record_revised_2")
-#define CIFTAG_RCSB_RECORD_REVISED_3          pstr("rcsb_record_revised_3")
-#define CIFTAG_RCSB_RECORD_REVISED_4          pstr("rcsb_record_revised_4")
-#define CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE    pstr("pdbx_seq_align_beg_ins_code")
-#define CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE    pstr("pdbx_seq_align_end_ins_code")
-#define CIFTAG_PTNR1_LABEL_ASYM_ID            pstr("ptnr1_label_asym_id")
-#define CIFTAG_PTNR1_LABEL_COMP_ID            pstr("ptnr1_label_comp_id")
-#define CIFTAG_PTNR1_LABEL_SEQ_ID             pstr("ptnr1_label_seq_id")
-#define CIFTAG_REF_ID                         pstr("ref_id")
-#define CIFTAG_REPLACES                       pstr("replaces")
-#define CIFTAG_REPLACE_PDB_ID                 pstr("replace_pdb_id")
-#define CIFTAG_SEGMENT_ID                     pstr("segment_id")
-#define CIFTAG_SEQ_ALIGN_BEG                  pstr("seq_align_beg")
-#define CIFTAG_SEQ_ALIGN_END                  pstr("seq_align_end")
-#define CIFTAG_SEQ_NUM                        pstr("seq_num")
-#define CIFTAG_SENSE                          pstr("sense")
-#define CIFTAG_SHEET_ID                       pstr("sheet_id")
-#define CIFTAG_SOURCE                         pstr("source")
-#define CIFTAG_SPACE_GROUP_NAME_H_M           pstr("space_group_name_H-M")
-#define CIFTAG_TEXT                           pstr("text")
-#define CIFTAG_TITLE                          pstr("title")
-#define CIFTAG_TYPE                           pstr("type")
-#define CIFTAG_TYPE_SYMBOL                    pstr("type_symbol")
-#define CIFTAG_VECTOR1                        pstr("vector[1]")
-#define CIFTAG_VECTOR2                        pstr("vector[2]")
-#define CIFTAG_VECTOR3                        pstr("vector[3]")
-#define CIFTAG_U11                            pstr("u[1][1]")
-#define CIFTAG_U11_ESD                        pstr("u[1][1]_esd")
-#define CIFTAG_U12                            pstr("u[1][2]")
-#define CIFTAG_U12_ESD                        pstr("u[1][2]_esd")
-#define CIFTAG_U13                            pstr("u[1][3]")
-#define CIFTAG_U13_ESD                        pstr("u[1][3]_esd")
-#define CIFTAG_U22                            pstr("u[2][2]")
-#define CIFTAG_U22_ESD                        pstr("u[2][2]_esd")
-#define CIFTAG_U23                            pstr("u[2][3]")
-#define CIFTAG_U23_ESD                        pstr("u[2][3]_esd")
-#define CIFTAG_U33                            pstr("u[3][3]")
-#define CIFTAG_U33_ESD                        pstr("u[3][3]_esd")
-#define CIFTAG_Z_PDB                          pstr("z_pdb")
-
-#define CIFTAG_CONN_PTNR1_AUTH_ATOM_ID        pstr("ptnr1_auth_atom_id")
-#define CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID    pstr("pdbx_ptnr1_auth_alt_id")
-#define CIFTAG_CONN_PTNR1_AUTH_COMP_ID        pstr("ptnr1_auth_comp_id")
-#define CIFTAG_CONN_PTNR1_AUTH_ASYM_ID        pstr("ptnr1_auth_asym_id")
-#define CIFTAG_CONN_PTNR1_AUTH_SEQ_ID         pstr("ptnr1_auth_seq_id")
-#define CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE   pstr("pdbx_ptnr1_PDB_ins_code")
-#define CIFTAG_CONN_DIST                      pstr("link_dist")
-#define CIFTAG_CONN_PTNR2_AUTH_ATOM_ID        pstr("ptnr2_auth_atom_id")
-#define CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID    pstr("pdbx_ptnr2_auth_alt_id")
-#define CIFTAG_CONN_PTNR2_AUTH_COMP_ID        pstr("ptnr2_auth_comp_id")
-#define CIFTAG_CONN_PTNR2_AUTH_ASYM_ID        pstr("ptnr2_auth_asym_id")
-#define CIFTAG_CONN_PTNR2_AUTH_SEQ_ID         pstr("ptnr2_auth_seq_id")
-#define CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE   pstr("pdbx_ptnr2_PDB_ins_code")
-#define CIFTAG_CONN_PTNR1_SYMMETRY            pstr("ptnr1_symmetry")
-#define CIFTAG_CONN_PTNR2_SYMMETRY            pstr("ptnr2_symmetry")
-#define CIFTAG_CONN_NAME                      pstr("link_name")
-
-
-#endif
-
diff --git a/mmdb/mmdb_coormngr.cpp b/mmdb/mmdb_coormngr.cpp
deleted file mode 100755
index 8ec1900..0000000
--- a/mmdb/mmdb_coormngr.cpp
+++ /dev/null
@@ -1,4360 +0,0 @@
-//  $Id: mmdb_coormngr.cpp,v 1.28 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    26.01.09   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_coormngr  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CBrick           ( space brick                  )
-//       ~~~~~~~~~  CMBrick          ( "multiple" space brick       )
-//                  CMMDBCoorManager ( MMDB atom coordinate manager )
-//
-//  Copyright (C) E. Krissinel 2000-2009
-//
-//  =================================================================
-//
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __LinAlg__
-#include "linalg_.h"
-#endif
-
-#ifndef  __MMDB_CoorMngr__
-#include "mmdb_coormngr.h"
-#endif
-
-#ifndef  __MMDB_Tables__
-#include "mmdb_tables.h"
-#endif
-
-
-// ===========================  CBrick  ==============================
-
-CBrick::CBrick()  {
-  InitBrick();
-}
-
-CBrick::~CBrick()  {
-  Clear();
-}
-
-void  CBrick::InitBrick()  {
-  Atom        = NULL;
-  id          = NULL;
-  nAtoms      = 0;
-  nAllocAtoms = 0;
-}
-
-void  CBrick::Clear()  {
-  if (Atom)  delete[] Atom;
-  FreeVectorMemory ( id,0 );
-  Atom        = NULL;
-  nAtoms      = 0;
-  nAllocAtoms = 0;
-}
-
-void  CBrick::AddAtom ( PCAtom A, int atomid )  {
-int     i;
-PPCAtom Atom1;
-ivector id1;
-  if (nAtoms>=nAllocAtoms)  {
-    nAllocAtoms = nAtoms+10;
-    Atom1       = new PCAtom[nAllocAtoms];
-    GetVectorMemory ( id1,nAllocAtoms,0 );
-    for (i=0;i<nAtoms;i++)  {
-      Atom1[i] = Atom[i];
-      id1  [i] = id  [i];
-    }
-    for (i=nAtoms;i<nAllocAtoms;i++)  {
-      Atom1[i] = NULL;
-      id1  [i] = -1;
-    }
-    if (Atom)  delete[] Atom;
-    FreeVectorMemory ( id,0 );
-    Atom = Atom1;
-    id   = id1;
-  }
-  Atom[nAtoms] = A;
-  id  [nAtoms] = atomid;
-  nAtoms++;
-}
-
-
-// ===========================  CMBrick  =============================
-
-CMBrick::CMBrick ( int nStructures )  {
-  InitMBrick ( nStructures );
-}
-
-CMBrick::~CMBrick()  {
-  Clear();
-}
-
-void  CMBrick::InitMBrick ( int nStructures )  {
-int i;
-  nStruct = nStructures;
-  Atom   = new PPCAtom[nStruct];
-  id     = new ivector[nStruct];
-  GetVectorMemory ( nAtoms,nStruct,0 );
-  GetVectorMemory ( nAllocAtoms,nStruct,0 );
-  for (i=0;i<nStruct;i++)  {
-    Atom       [i] = NULL;
-    id         [i] = NULL;
-    nAtoms     [i] = 0;
-    nAllocAtoms[i] = 0;
-  }
-}
-
-void  CMBrick::Clear()  {
-int i;
-  if (Atom)  {
-    for (i=0;i<nStruct;i++)
-      if (Atom[i])  delete[] Atom[i];
-    delete[] Atom;
-    Atom = NULL;
-  }
-  FreeMatrixMemory ( id,nStruct,0,0 );
-  FreeVectorMemory ( nAtoms,0 );
-  FreeVectorMemory ( nAllocAtoms,0 );
-  nStruct = 0;
-}
-
-void  CMBrick::AddAtom ( PCAtom A, int structNo, int atomid )  {
-int     i,natoms,nalloc;
-PPCAtom Atom0,Atom1;
-ivector id0,id1;
-  natoms = nAtoms     [structNo];
-  nalloc = nAllocAtoms[structNo];
-  Atom0  = Atom       [structNo];
-  id0    = id         [structNo];
-  if (natoms>=nalloc)  {
-    nalloc = natoms+10;
-    Atom1 = new PCAtom[nalloc];
-    GetVectorMemory ( id1,nalloc,0 );
-    for (i=0;i<natoms;i++)  {
-      Atom1[i] = Atom0[i];
-      id1  [i] = id0  [i];
-    }
-    for (i=natoms;i<nalloc;i++)  {
-      Atom1[i] = NULL;
-      id1  [i] = -1;
-    }
-    if (Atom0)  delete[] Atom0;
-    FreeVectorMemory ( id0,0 );
-    Atom[structNo] = Atom1;
-    id  [structNo] = id1;
-    nAllocAtoms[structNo] = nalloc;
-    Atom0 = Atom1;
-    id0   = id1;
-  }
-  Atom0 [natoms]   = A;
-  id0   [natoms]   = atomid;
-  nAtoms[structNo] = natoms+1;
-}
-
-
-
-//  ====================  CGenSym  ========================
-
-CGenSym::CGenSym() : CSymOps()  {
-  InitGenSym();
-}
-
-CGenSym::CGenSym ( RPCStream Object ) : CSymOps(Object)  {
-  InitGenSym();
-}
-
-CGenSym::~CGenSym()  {}  // virtual FreeMmeory is called by ~CSymOps()
-
-void CGenSym::InitGenSym()  {
-  chID1    = NULL;
-  chID2    = NULL;
-  nChains  = NULL;
-  nOpAlloc = 0;
-}
-
-void CGenSym::FreeMemory()  {
-int i;
-  for (i=0;i<nOpAlloc;i++)  {
-    if (chID1[i]) delete[] chID1[i];
-    if (chID2[i]) delete[] chID2[i];
-  }
-  if (chID1) delete[] chID1;
-  if (chID2) delete[] chID2;
-  FreeVectorMemory ( nChains,0 );
-  nOpAlloc = 0;
-  CSymOps::FreeMemory();
-}
-
-int CGenSym::AddSymOp ( cpstr XYZOperation )  {
-int        RC,i;
-PChainID * ch1ID;
-PChainID * ch2ID;
-ivector    nChains1;
-
-  RC = CSymOps::AddSymOp ( XYZOperation );
-  if (Nops>nOpAlloc)  {
-    ch1ID = new PChainID[Nops];
-    ch2ID = new PChainID[Nops];
-    GetVectorMemory ( nChains1,Nops,0 );
-    for (i=0;i<nOpAlloc;i++)  {
-      ch1ID[i]    = chID1[i];
-      ch2ID[i]    = chID2[i];
-      nChains1[i] = nChains[i];
-    }
-    for (i=nOpAlloc;i<Nops;i++)  {
-      ch1ID[i]    = NULL;
-      ch2ID[i]    = NULL;
-      nChains1[i] = 0;
-    }
-    if (chID1)  delete[] chID1;
-    if (chID2)  delete[] chID2;
-    FreeVectorMemory ( nChains,0 );
-    chID1    = ch1ID;
-    chID2    = ch2ID;
-    nChains  = nChains1;
-    nOpAlloc = Nops;
-  }
-  return RC;
-}
-
-int  CGenSym::AddRenChain ( int Nop, const ChainID ch1,
-                                     const ChainID ch2 )  {
-int      i;
-PChainID c1,c2;
-  if ((0<=Nop) && (Nop<Nops))  {
-    c1 = new ChainID[nChains[Nop]+1];
-    c2 = new ChainID[nChains[Nop]+1];
-    for (i=0;i<nChains[Nop];i++)  {
-      strcpy ( c1[i],chID1[Nop][i] );
-      strcpy ( c2[i],chID2[Nop][i] );
-    }
-    strcpy ( c1[nChains[Nop]],ch1 );
-    strcpy ( c2[nChains[Nop]],ch2 );
-    if (chID1[Nop])  delete[] chID1[Nop];
-    if (chID2[Nop])  delete[] chID2[Nop];
-    chID1[Nop] = c1;
-    chID2[Nop] = c2;
-    nChains[Nop]++;
-    return SYMOP_Ok;
-  } else
-    return SYMOP_NoSymOps;
-}
-
-void CGenSym::Copy ( PCSymOps GenSym )  {
-int i,j;
-  CSymOps::Copy ( GenSym );
-  if (Nops>0)  {
-    nOpAlloc = Nops;
-    chID1 = new PChainID[Nops];
-    chID2 = new PChainID[Nops];
-    GetVectorMemory ( nChains,Nops,0 );
-    for (i=0;i<Nops;i++)  {
-      nChains[i] = PCGenSym(GenSym)->nChains[i];
-      if (nChains[i]<=0)  {
-        chID1[i] = NULL;
-        chID2[i] = NULL;
-      } else  {
-        chID1[i] = new ChainID[nChains[i]];
-        chID2[i] = new ChainID[nChains[i]];
-        for (j=0;j<nChains[i];j++)  {
-          strcpy ( chID1[i][j],PCGenSym(GenSym)->chID1[i][j] );
-          strcpy ( chID2[i][j],PCGenSym(GenSym)->chID2[i][j] );
-        }
-      }
-    }
-  }
-}
-
-void  CGenSym::write ( RCFile f )  {
-int  i,j;
-byte Version=1;
-  f.WriteByte ( &Version  );
-  CSymOps::write ( f );
-  f.WriteInt ( &nOpAlloc );
-  for (i=0;i<nOpAlloc;i++)  {
-    f.WriteInt ( &(nChains[i]) );
-    for (j=0;j<nChains[i];j++)  {
-      f.WriteTerLine ( chID1[i][j],False );
-      f.WriteTerLine ( chID2[i][j],False );
-    }
-  }
-}
-
-void  CGenSym::read ( RCFile f )  {
-int  i,j;
-byte Version;
-  f.ReadByte ( &Version  );
-  CSymOps::read ( f );
-  f.ReadInt ( &nOpAlloc );
-  if (nOpAlloc>0)  {
-    chID1 = new PChainID[nOpAlloc];
-    chID2 = new PChainID[nOpAlloc];
-    GetVectorMemory ( nChains,nOpAlloc,0 );
-    for (i=0;i<nOpAlloc;i++)  {
-      f.ReadInt ( &(nChains[i]) );
-      if (nChains[i]>0)  {
-        chID1[i] = new ChainID[nChains[i]];
-        chID2[i] = new ChainID[nChains[i]];
-        for (j=0;j<nChains[i];j++)  {
-          f.ReadTerLine ( chID1[i][j],False );
-          f.ReadTerLine ( chID2[i][j],False );
-        }
-      } else  {
-        chID1[i] = NULL;
-        chID2[i] = NULL;
-      }
-    }
-  }
-}
-
-
-MakeStreamFunctions(CGenSym)
-
-
-
-// =======================  CContactIndex  ==========================
-
-void SContact::Copy ( RSContact c )  {
-  id1   = c.id1;
-  id2   = c.id2;
-  group = c.group;
-  dist  = c.dist;
-}
-
-void SContact::Swap ( RSContact c )  {
-int      ib;
-long     lb;
-realtype rb;
-  ib = id1;     id1   = c.id1;     c.id1   = ib;
-  ib = id2;     id2   = c.id2;     c.id2   = ib;
-  lb = group;   group = c.group;   c.group = lb;
-  rb = dist;    dist  = c.dist;    c.dist  = rb;
-}
-
-DefineClass(CContactIndex)
-
-class CContactIndex  {
-
-  friend class CMMDBSelManager;
-
-  public :
-
-    CContactIndex ( PSContact contact,
-                    int       maxlen,
-                    int       ncontacts,
-                    int       max_alloc );
-    ~CContactIndex();
-
-    void AddContact ( int id1, int id2,   realtype dist, int group  );
-    void GetIndex   ( RPSContact contact, int & ncontacts );
-
-  protected :
-
-    PSContact contact_index; // contact index
-    int       max_index;     // if <=0 then dynamical index
-                             // otherwise fixed by max_index
-    int       n_contacts;    // number of contacts
-    int       alloc_index;   // physical length of contact_index
-                             // when dynamical
-    int       alloc_max;     // physical limit on allocation
-
-};
-
-
-CContactIndex::CContactIndex ( PSContact contact,
-                               int       maxlen,
-                               int       ncontacts,
-                               int       max_alloc )  {
-  contact_index = contact;
-  max_index     = maxlen;
-  if (!contact_index)  n_contacts = 0;
-                 else  n_contacts = IMax(0,ncontacts);
-  alloc_index = n_contacts;
-  alloc_max   = n_contacts + max_alloc;
-}
-
-CContactIndex::~CContactIndex() {
-  if (contact_index)  delete[] contact_index;
-  contact_index = NULL;
-  n_contacts    = 0;
-  alloc_index   = 0;
-}
-
-void CContactIndex::AddContact ( int id1, int id2, realtype dist,
-                                 int group )  {
-PSContact cont1;
-int       i;
-
-  if ((alloc_max<=0) || (n_contacts<alloc_max))  {
-    if (max_index>0)  {
-      if (n_contacts<max_index)  {
-        contact_index[n_contacts].id1   = id1;
-        contact_index[n_contacts].id2   = id2;
-        contact_index[n_contacts].dist  = dist;
-        contact_index[n_contacts].group = group;
-      }
-    } else  {
-      if (n_contacts>=alloc_index)  {
-        alloc_index = n_contacts+IMax(alloc_index/4+10,10);
-        if ((alloc_max>0) && (alloc_index>alloc_max))
-          alloc_index = alloc_max;
-        cont1 = new SContact[alloc_index];
-        for (i=0;i<n_contacts;i++)
-          cont1[i].Copy ( contact_index[i] );
-        if (contact_index)  delete[] contact_index;
-        contact_index = cont1;
-      }
-      contact_index[n_contacts].id1   = id1;
-      contact_index[n_contacts].id2   = id2;
-      contact_index[n_contacts].dist  = dist;
-      contact_index[n_contacts].group = group;
-    }
-    n_contacts++;
-  }
-}
-
-void  CContactIndex::GetIndex ( RPSContact contact, int & ncontacts )  {
-  contact       = contact_index;
-  ncontacts     = n_contacts;
-  contact_index = NULL;
-  n_contacts    = 0;
-  alloc_index   = 0;
-}
-
-
-// ========================  CMContact  =============================
-
-CMContact::CMContact ( int nStructures )  {
-int i;
-  nStruct = nStructures;
-  if (nStruct>0)  {
-    Atom = new PPCAtom[nStruct];
-    id   = new ivector[nStruct];
-    GetVectorMemory ( nAtoms,nStruct,0 );
-    GetVectorMemory ( nAlloc,nStruct,0 );
-    for (i=0;i<nStruct;i++)  {
-      Atom  [i] = NULL;
-      id    [i] = NULL;
-      nAtoms[i] = 0;
-      nAlloc[i] = 0;
-    }
-  } else  {
-    Atom   = NULL;
-    nAtoms = NULL;
-    nAlloc = NULL;
-  }
-}
-
-CMContact::~CMContact()  {
-int i;
-  if (Atom)  {
-    for (i=0;i<nStruct;i++)
-      if (Atom[i])  delete[] Atom[i];
-    delete[] Atom;
-    Atom = NULL;
-  }
-  FreeMatrixMemory ( id,nStruct,0,0 );
-  FreeVectorMemory ( nAtoms,0 );
-  FreeVectorMemory ( nAlloc,0 );
-  nStruct = 0;
-}
-
-void CMContact::AddContact ( PCAtom A, int structNo, int atomid )  {
-PPCAtom A1,A2;
-ivector id1,id2;
-int     nat,nal,i;
-  A1  = Atom  [structNo];
-  id1 = id    [structNo];
-  nat = nAtoms[structNo];
-  nal = nAlloc[structNo];
-  if (nat>=nal)  {
-    nal = nat+10;
-    A2  = new PCAtom[nal];
-    GetVectorMemory ( id2,nal,0 );
-    for (i=0;i<nat;i++)  {
-      A2 [i] = A1 [i];
-      id2[i] = id1[i];
-    }
-    for (i=nat;i<nal;i++)  {
-      A2 [i] = NULL;
-      id2[i] = 0;
-    }
-    if (A1)  delete[] A1;
-    FreeVectorMemory ( id1,0 );
-    Atom[structNo] = A2;
-    id  [structNo] = id2;
-    A1  = A2;
-    id1 = id2;
-    nAlloc[structNo] = nal;
-  }
-  A1 [nat] = A;
-  id1[nat] = atomid;
-  nAtoms[structNo] = nat+1;
-}
-
-
-void  DeleteMContacts ( PPCMContact & mcontact, int nContacts )  {
-int i;
-  if (mcontact)  {
-    for (i=0;i<nContacts;i++)
-      if (mcontact[i])  delete mcontact[i];
-    delete[] mcontact;
-    mcontact = NULL;
-  }
-}
-
-
-//  ====================   CMMDBCoorManager   =====================
-
-CMMDBCoorManager::CMMDBCoorManager() : CMMDBFile()  {
-  InitMMDBCoorManager();
-}
-
-CMMDBCoorManager::CMMDBCoorManager ( RPCStream Object )
-                : CMMDBFile(Object)  {
-  InitMMDBCoorManager();
-}
-
-CMMDBCoorManager::~CMMDBCoorManager()  {
-  RemoveBricks ();
-  RemoveMBricks();
-}
-
-void  CMMDBCoorManager::ResetManager()  {
-  CMMDBFile::ResetManager();
-  RemoveBricks       ();
-  RemoveMBricks      ();
-  InitMMDBCoorManager();
-}
-
-void  CMMDBCoorManager::InitMMDBCoorManager()  {
-
-  CoorIDCode  = CID_Ok;
-
-  brick_size  = 6.0;  // angstroms
-  xbrick_0    = 0.0;
-  ybrick_0    = 0.0;
-  zbrick_0    = 0.0;
-  nbrick_x    = 0;
-  nbrick_y    = 0;
-  nbrick_z    = 0;
-  Brick       = NULL;
-
-  mbrick_size = 6.0;  // angstroms
-  xmbrick_0   = 0.0;
-  ymbrick_0   = 0.0;
-  zmbrick_0   = 0.0;
-  nmbrick_x   = 0;
-  nmbrick_y   = 0;
-  nmbrick_z   = 0;
-  MBrick      = NULL;
-
-}
-
-
-int  CMMDBCoorManager::SetDefaultCoorID ( cpstr CID )  {
-  return DefPath.SetPath ( CID );
-}
-
-PCModel CMMDBCoorManager::GetFirstDefinedModel()  {
-PCModel mdl;
-int     i;
-  mdl = NULL;
-  for (i=0;(i<nModels) && (!mdl);i++)
-    mdl = Model[i];
-  return mdl;
-}
-
-int CMMDBCoorManager::GetFirstModelNum()  {
-PCModel mdl;
-int     i;
-  mdl = NULL;
-  for (i=0;(i<nModels) && (!mdl);i++)
-    mdl = Model[i];
-  if (mdl)  return mdl->GetSerNum();
-  return 1;
-}
-
-
-PCModel CMMDBCoorManager::GetModel ( int modelNo )  {
-  if ((modelNo>=1) && (modelNo<=nModels))
-        return Model[modelNo-1];
-  else  return NULL;
-}
-
-PCModel CMMDBCoorManager::GetModel ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & APATH_WC_ModelNo))  {
-    CoorIDCode = CID_WrongPath;
-    return NULL;
-  }
-
-  if ((modno>=1) && (modno<=nModels))
-        return Model[modno-1];
-  else  return NULL;
-
-}
-
-void CMMDBCoorManager::GetModelTable ( PPCModel & modelTable,
-                                       int & NumberOfModels )  {
-  NumberOfModels = nModels;
-  modelTable     = Model;
-}
-
-int CMMDBCoorManager::DeleteModel ( int modelNo )  {
-  if ((modelNo>=1) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      Exclude = False;
-      delete Model[modelNo-1];
-      Model[modelNo-1] = NULL;
-      Exclude = True;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteModel ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & APATH_WC_ModelNo))  {
-    CoorIDCode = CID_WrongPath;
-    return 0;
-  }
-
-  if ((modno>=1) && (modno<=nModels))  {
-    if (Model[modno-1])  {
-      Exclude = False;
-      delete Model[modno-1];
-      Model[modno-1] = NULL;
-      Exclude = True;
-      return 1;
-    }
-  }
-
-  return 0;
-
-}
-
-
-int CMMDBCoorManager::DeleteSolvent()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  {
-      k += Model[i]->DeleteSolvent();
-      Model[i]->TrimChainTable();
-      if (Model[i]->nChains<=0)  {
-        delete Model[i];
-        Model[i] = NULL;
-      }
-    }
-  Exclude = True;
-  return k;
-}
-
-
-//  ----------------  Adding/Inserting models  ---------------
-
-int  CMMDBCoorManager::AddModel ( PCModel model )  {
-PPCModel model1;
-int      i,nnat,nat1;
-
-  for (i=0;i<nModels;i++)
-    if (Model[i]==model)  return -i;
-
-  nnat = model->GetNumberOfAtoms ( True );
-  AddAtomArray ( nnat );         // get space for new atoms
-
-  if (model->GetCoordHierarchy())  {
-    SwitchModel ( nModels+1 ); // get one more model at the end
-    nat1 = nAtoms;
-    Model[nModels-1]->_copy ( model,Atom,nat1 );
-    Model[nModels-1]->serNum = nModels;
-    nAtoms = nat1;
-  } else  {
-    model1 = new PCModel[nModels+1];
-    for (i=0;i<nModels;i++)
-      model1[i] = Model[i];
-    if (Model)  delete[] Model;
-    Model = model1;
-    Model[nModels] = model;
-    Model[nModels]->SetMMDBManager ( PCMMDBManager(this),nModels+1 );
-    Model[nModels]->CheckInAtoms();
-    nModels++;
-  }
-
-  return nModels;
-
-}
-
-int  CMMDBCoorManager::InsModel ( PCModel model, int modelNo )  {
-  AddModel     ( model );
-  RotateModels ( modelNo,nModels,1 );
-  return nModels;
-}
-
-void CMMDBCoorManager::RotateModels ( int modelNo1, int modelNo2,
-                                      int rotdir )  {
-PCModel model;
-PPCAtom A;
-int     m1,m2,i11,i12,i21,i22,nat,i,k;
-
-  m1 = IMax ( 0,modelNo1-1 );
-  m2 = IMin ( nModels,modelNo2) - 1;
-  if (m1>m2)  ISwap ( m1,m2 );
-
-  if (m1!=m2)  {
-
-    if (Model[m1] && Model[m2])  {
-      Model[m1]->GetAIndexRange ( i11,i12 );
-      Model[m2]->GetAIndexRange ( i21,i22 );
-      if ((i11<i12) && (i21<i22) && (i12<i22))  {
-        i11--;    i12--;
-        i21--;    i22--;
-        if (rotdir<0)  {
-          //  rotate anticlockwise
-          nat = i12-i11+1;
-          A = new PCAtom[nat];
-          k = 0;
-          for (i=i11;i<=i12;i++)
-            A[k++] = Atom[i];
-          k = i11;
-          for (i=i12+1;i<=i22;i++)  {
-            Atom[k] = Atom[i];
-            if (Atom[k])  Atom[k]->index = k+1;
-            k++;
-          }
-          for (i=0;i<nat;i++)  {
-            Atom[k] = A[i];
-            if (Atom[k])  Atom[k]->index = k+1;
-            k++;
-          }
-        } else  {
-          //  rotate anticlockwise
-          nat = i22-i21+1;
-          A = new PCAtom[nat];
-          k = 0;
-          for (i=i21;i<=i22;i++)
-            A[k++] = Atom[i];
-          k = i22;
-          for (i=i21-1;i>=i11;i--)  {
-            Atom[k] = Atom[i];
-            if (Atom[k])  Atom[k]->index = k+1;
-            k--;
-          }
-          for (i=nat-1;i>=0;i--)  {
-            Atom[k] = A[i];
-            if (Atom[k])  Atom[k]->index = k+1;
-            k--;
-          }
-        }
-        delete[] A;
-      }
-    }
-
-    if (rotdir<0)  {
-      //  rotate anticlockwise
-      model = Model[m1];
-      for (i=m1;i<m2;i++)  {
-        Model[i] = Model[i+1];
-        Model[i]->serNum = i+1;
-      }
-      Model[m2] = model;
-      Model[m2]->serNum = m2+1;
-    } else  {
-      //  rotate clockwise
-      model = Model[m2];
-      for (i=m2;i>m1;i--)  {
-        Model[i] = Model[i-1];
-        Model[i]->serNum = i+1;
-      }
-      Model[m1] = model;
-      Model[m1]->serNum = m1+1;
-    }
-
-  }
-
-}
-
-
-void CMMDBCoorManager::SwapModels ( int modelNo1, int modelNo2 )  {
-PCModel model;
-PPCAtom A;
-int     m1,m2,i11,i12,i21,i22,i,k,n;
-
-  n = 0;  // tp depress "uninitialized" warning
-
-  m1 = IMax ( 0,modelNo1-1 );
-  m2 = IMin ( nModels,modelNo2) - 1;
-  if (m1>m2)  ISwap ( m1,m2 );
-
-  if (m1!=m2)  {
-
-    if (Model[m1])
-      Model[m1]->GetAIndexRange ( i11,i12 );
-    else  {
-      n = m1;
-      while ((!Model[n]) && (n<m2))  n++;
-      if (n<m2)  {
-        Model[n]->GetAIndexRange ( i11,i12 );
-        i12 = i11-1;
-      } else
-        n = -1;
-    }
-
-    if (n>=0)  {
-      if (Model[m2])
-        Model[m2]->GetAIndexRange ( i21,i22 );
-      else  {
-        n = m2;
-        while ((!Model[n]) && (m1<n))  n--;
-        if (m1<n)  {
-          Model[n]->GetAIndexRange ( i21,i22 );
-          i22 = i21-1;
-        } else
-          n = -1;
-      }
-    }
-
-    if (n>=0)  {
-
-      i11--;    i12--;
-      i21--;    i22--;
-
-      A = new PCAtom[AtmLen];
-      k = 0;
-
-      for (i=0     ;i<i11   ;i++)  A[k++] = Atom[i];
-      for (i=i21   ;i<=i22  ;i++)  A[k++] = Atom[i];
-      for (i=i12+1 ;i<i21   ;i++)  A[k++] = Atom[i];
-      for (i=i11   ;i<=i12  ;i++)  A[k++] = Atom[i];
-
-      for (i=0     ;i<nAtoms;i++)  if (A[i]) A[i]->index = i+1;
-      for (i=nAtoms;i<AtmLen;i++)  A[i]   = NULL;
-
-      if (Atom)  delete[] Atom;
-      Atom = A;
-
-    }
-
-    model     = Model[m2];
-    Model[m2] = Model[m1];
-    Model[m1] = model;
-
-    Model[m1]->serNum = m1+1;
-    Model[m2]->serNum = m2+1;
-
-  }
-
-}
-
-
-
-
-PCChain CMMDBCoorManager::GetChain ( int modelNo, const ChainID chainID )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetChain ( chainID );
-  }
-  return NULL;
-}
-
-PCChain CMMDBCoorManager::GetChain ( int modelNo, int chainNo )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetChain ( chainNo );
-  }
-  return NULL;
-}
-
-PCChain CMMDBCoorManager::GetChain ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID)))  {
-    CoorIDCode = CID_WrongPath;
-    return NULL;
-  }
-  return GetChain ( modno,chname );
-
-}
-
-void  CMMDBCoorManager::GetChainTable ( int modelNo,
-                                        PPCChain & chainTable,
-                                        int & NumberOfChains )  {
-  chainTable     = NULL;
-  NumberOfChains = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      chainTable     = Model[modelNo-1]->Chain;
-      NumberOfChains = Model[modelNo-1]->nChains;
-    }
-  }
-}
-
-void  CMMDBCoorManager::GetChainTable ( cpstr CID,
-                                        PPCChain & chainTable,
-                                        int & NumberOfChains )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  chainTable     = NULL;
-  NumberOfChains = 0;
-  CoorIDCode     = CID_Ok;
-
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & APATH_WC_ModelNo))  {
-    CoorIDCode = CID_WrongPath;
-    return;
-  }
-
-  if ((0<modno) && (modno<=nModels))  {
-    if (Model[modno-1])  {
-      chainTable     = Model[modno-1]->Chain;
-      NumberOfChains = Model[modno-1]->nChains;
-    }
-  }
-}
-
-
-int CMMDBCoorManager::DeleteChain ( int modelNo, const ChainID chID )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteChain ( chID );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteChain ( int modelNo, int chainNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteChain ( chainNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllChains ( int modelNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllChains();
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllChains()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  k += Model[i]->DeleteAllChains();
-  return k;
-}
-
-int CMMDBCoorManager::AddChain ( int modelNo, PCChain chain )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddChain ( chain );
-  }
-  return 0;
-}
-
-
-PCResidue CMMDBCoorManager::GetResidue ( int           modelNo,
-                                         const ChainID chainID,
-                                         int           seqNo,
-                                         const InsCode insCode )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
-  }
-  return NULL;
-}
-
-PCResidue CMMDBCoorManager::GetResidue ( int modelNo, int chainNo,
-                                         int seqNo,
-                                         const InsCode insCode )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
-  }
-  return NULL;
-}
-
-PCResidue CMMDBCoorManager::GetResidue ( int modelNo,
-                                         const ChainID chainID,
-                                         int resNo )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetResidue ( chainID,resNo );
-  }
-  return NULL;
-}
-
-PCResidue CMMDBCoorManager::GetResidue ( int modelNo, int chainNo,
-                                         int resNo )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetResidue ( chainNo,resNo );
-  }
-  return NULL;
-}
-
-PCResidue CMMDBCoorManager::GetResidue ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
-                       APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
-    CoorIDCode = CID_WrongPath;
-    return NULL;
-  }
-  return GetResidue ( modno,chname,sn,ic );
-
-}
-
-
-int CMMDBCoorManager::GetResidueNo ( int           modelNo,
-                                     const ChainID chainID,
-                                     int           seqNo,
-                                     const InsCode insCode )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetResidueNo ( chainID,seqNo,insCode );
-  }
-  return -3;
-}
-
-int CMMDBCoorManager::GetResidueNo ( int modelNo, int chainNo,
-                                     int seqNo,
-                                     const InsCode insCode )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->GetResidueNo ( chainNo,seqNo,insCode );
-  }
-  return -3;
-}
-
-void CMMDBCoorManager::GetResidueTable ( PPCResidue & resTable,
-                                         int & NumberOfResidues )  {
-//    resTable has to be NULL or it will be reallocated. The
-//  application is responsible for deallocating the resTable (but not
-//  of its residues!). This does not apply to other GetResidueTable
-//  functions.
-PPCChain   chain;
-PPCResidue res;
-int        i,j,k,n,nChains,nResidues;
-
-  if (resTable)  {
-    delete[] resTable;
-    resTable = NULL;
-  }
-
-  NumberOfResidues = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  {
-      Model[i]->GetChainTable ( chain,nChains );
-      for (j=0;j<Model[i]->nChains;j++)
-        if (chain[j])  {
-          chain[j]->GetResidueTable ( res,nResidues );
-          NumberOfResidues += nResidues;
-        }
-    }
-
-  if (NumberOfResidues>0)  {
-    resTable = new PCResidue[NumberOfResidues];
-    k = 0;
-    for (i=0;i<nModels;i++)
-      if (Model[i])  {
-        Model[i]->GetChainTable ( chain,nChains );
-        for (j=0;j<Model[i]->nChains;j++)
-          if (chain[j])  {
-            chain[j]->GetResidueTable ( res,nResidues );
-            for (n=0;n<nResidues;n++)
-              if (res[n])  resTable[k++] = res[n];
-          }
-      }
-    NumberOfResidues = k;
-  }
-
-}
-
-void CMMDBCoorManager::GetResidueTable ( int modelNo,
-                                         const ChainID chainID,
-                                         PPCResidue & resTable,
-                                         int & NumberOfResidues )  {
-PCChain chain;
-  resTable         = NULL;
-  NumberOfResidues = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      chain = Model[modelNo-1]->GetChain ( chainID );
-      if (chain)  {
-        resTable         = chain->Residue;
-        NumberOfResidues = chain->nResidues;
-      }
-    }
-  }
-}
-
-void CMMDBCoorManager::GetResidueTable ( int modelNo, int chainNo,
-                                         PPCResidue & resTable,
-                                         int & NumberOfResidues )  {
-PCChain chain;
-  resTable         = NULL;
-  NumberOfResidues = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      chain = Model[modelNo-1]->GetChain ( chainNo );
-      if (chain)  {
-        resTable         = chain->Residue;
-        NumberOfResidues = chain->nResidues;
-      }
-    }
-  }
-}
-
-void CMMDBCoorManager::GetResidueTable ( cpstr CID,
-                                         PPCResidue & resTable,
-                                         int & NumberOfResidues )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-PCChain  chain;
-
-  resTable         = NULL;
-  NumberOfResidues = 0;
-  CoorIDCode       = CID_Ok;
-
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID)))  {
-    CoorIDCode = CID_WrongPath;
-    return;
-  }
-
-  if ((0<modno) && (modno<=nModels))  {
-    if (Model[modno-1])  {
-      chain = Model[modno-1]->GetChain ( chname );
-      if (chain)  {
-        resTable         = chain->Residue;
-        NumberOfResidues = chain->nResidues;
-      }
-    }
-  }
-
-}
-
-
-int CMMDBCoorManager::DeleteResidue ( int           modelNo,
-                                      const ChainID chainID,
-                                      int           seqNo,
-                                      const InsCode insCode )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteResidue ( chainID,seqNo,insCode );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteResidue ( int           modelNo,
-                                      const ChainID chainID,
-                                      int           resNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteResidue ( chainID,resNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteResidue ( int modelNo, int chainNo,
-                                      int seqNo,
-                                      const InsCode insCode )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteResidue ( chainNo,seqNo,insCode );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteResidue ( int modelNo, int chainNo,
-                                      int resNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteResidue ( chainNo,resNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllResidues ( int modelNo,
-                                          const ChainID chainID )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllResidues ( chainID );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllResidues ( int modelNo, int chainNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllResidues ( chainNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllResidues ( int modelNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllResidues();
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllResidues()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  k += Model[i]->DeleteAllResidues();
-  return k;
-}
-
-int CMMDBCoorManager::AddResidue ( int modelNo, const ChainID chainID,
-                                   PCResidue res )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddResidue ( chainID,res );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::AddResidue ( int modelNo, int chainNo,
-                                   PCResidue res )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddResidue ( chainNo,res );
-  }
-  return 0;
-}
-
-
-
-int  CMMDBCoorManager::GetNumberOfChains ( int modelNo )  {
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return  Model[modelNo-1]->nChains;
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfChains ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & APATH_WC_ModelNo))  {
-    CoorIDCode = CID_WrongPath;
-    return 0;
-  }
-
-  if ((0<modno) && (modno<=nModels))  {
-    if (Model[modno-1])
-      return  Model[modno-1]->nChains;
-  }
-
-  return 0;
-
-}
-
-int  CMMDBCoorManager::GetNumberOfResidues ( int modelNo,
-                                             const ChainID chainID )  {
-PCChain chain;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      chain = Model[modelNo-1]->GetChain ( chainID );
-      if (chain)  return chain->nResidues;
-    }
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfResidues ( int modelNo, int chainNo )  {
-PCChain chain;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      if ((0<=chainNo) && (chainNo<Model[modelNo-1]->nChains))  {
-        chain = Model[modelNo-1]->Chain[chainNo];
-        if (chain)  return chain->nResidues;
-      }
-    }
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfResidues ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-PCChain  chain;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID)))  {
-    CoorIDCode = CID_WrongPath;
-    return 0;
-  }
-
-  if ((0<modno) && (modno<=nModels))  {
-    if (Model[modno-1])  {
-      chain = Model[modno-1]->GetChain ( chname );
-      if (chain)  return chain->nResidues;
-    }
-  }
-
-  return 0;
-
-}
-
-
-int  CMMDBCoorManager::GetNumberOfAtoms ( int           modelNo,
-                                          const ChainID chainID,
-                                          int           seqNo,
-                                          const InsCode insCode )  {
-PCChain   chain;
-PCResidue res;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      chain = Model[modelNo-1]->GetChain ( chainID );
-      if (chain)  {
-        res = chain->GetResidue ( seqNo,insCode );
-        if (res)  return res->nAtoms;
-      }
-    }
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfAtoms ( int modelNo, int chainNo,
-                                          int seqNo,
-                                          const InsCode insCode )  {
-PCChain   chain;
-PCResidue res;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      if ((0<=chainNo) && (chainNo<Model[modelNo-1]->nChains))  {
-        chain = Model[modelNo-1]->Chain[chainNo];
-        if (chain)  {
-          res = chain->GetResidue ( seqNo,insCode );
-          if (res)  return res->nAtoms;
-        }
-      }
-    }
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfAtoms ( int           modelNo,
-                                          const ChainID chainID,
-                                          int           resNo )  {
-PCChain   chain;
-PCResidue res;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      chain = Model[modelNo-1]->GetChain ( chainID );
-      if (chain)  {
-        if ((0<=resNo) && (resNo<chain->nResidues))  {
-          res = chain->Residue[resNo];
-          if (res)  return res->nAtoms;
-        }
-      }
-    }
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfAtoms ( int modelNo, int chainNo,
-                                          int resNo )  {
-PCChain   chain;
-PCResidue res;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      if ((0<=chainNo) && (chainNo<Model[modelNo-1]->nChains))  {
-        chain = Model[modelNo-1]->Chain[chainNo];
-        if (chain)  {
-          if ((0<=resNo) && (resNo<chain->nResidues))  {
-            res = chain->Residue[resNo];
-            if (res)  return res->nAtoms;
-          }
-        }
-      }
-    }
-  }
-  return 0;
-}
-
-int  CMMDBCoorManager::GetNumberOfAtoms ( cpstr CID )  {
-// returns number of atoms in residues identified by CID
-int       modno,sn,rc;
-ChainID   chname;
-InsCode   ic;
-ResName   resname;
-AtomName  aname;
-Element   elname;
-AltLoc    aloc;
-PCChain   chain;
-PCResidue res;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
-                       APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
-    CoorIDCode = CID_WrongPath;
-    return 0;
-  }
-
-  if ((0<modno) && (modno<=nModels))  {
-    if (Model[modno-1])  {
-      chain = Model[modno-1]->GetChain ( chname );
-      if (chain)  {
-        res = chain->GetResidue ( sn,ic );
-        if (res)  return res->nAtoms;
-      }
-    }
-  }
-
-  return 0;
-
-}
-
-
-// --------------------  Extracting atoms  -----------------------
-
-PCAtom  CMMDBCoorManager::GetAtom (
-                   int            modelNo, // model serial number 1...
-                   const ChainID  chID,    // chain ID
-                   int            seqNo,   // residue sequence number
-                   const InsCode  insCode, // residue insertion code
-                   const AtomName aname,   // atom name
-                   const Element  elmnt,   // chemical element code or '*'
-                   const AltLoc   aloc     // alternate location indicator
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  chn = mdl->GetChain ( chID );
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  res = chn->GetResidue ( seqNo,insCode );
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  atm = res->GetAtom ( aname,elmnt,aloc );
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int           modelNo, // model serial number 1...
-                     const ChainID chID,    // chain ID
-                     int           seqNo,   // residue sequence number
-                     const InsCode insCode, // residue insertion code
-                     int           atomNo   // atom number 0..
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  chn = mdl->GetChain ( chID );
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  res = chn->GetResidue ( seqNo,insCode );
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  if ((0<=atomNo) && (atomNo<res->nAtoms))
-        atm = res->atom[atomNo];
-  else  atm = NULL;
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int            modelNo, // model serial number 1...
-                     const ChainID  chID,    // chain ID
-                     int            resNo,   // residue number 0..
-                     const AtomName aname,   // atom name
-                     const Element  elmnt,   // chemical element code or '*'
-                     const AltLoc   aloc     // alternate location indicator
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  chn = mdl->GetChain ( chID );
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  if ((0<=resNo) && (resNo<chn->nResidues))
-        res = chn->Residue[resNo];
-  else  res = NULL;
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  atm = res->GetAtom ( aname,elmnt,aloc );
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int           modelNo, // model serial number 1...
-                     const ChainID chID,    // chain ID
-                     int           resNo,   // residue number 0..
-                     int           atomNo   // atom number 0..
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  chn = mdl->GetChain ( chID );
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  if ((0<=resNo) && (resNo<chn->nResidues))
-        res = chn->Residue[resNo];
-  else  res = NULL;
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  if ((0<=atomNo) && (atomNo<res->nAtoms))
-        atm = res->atom[atomNo];
-  else  atm = NULL;
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int            modelNo, // model serial number 1...
-                     int            chNo,    // chain number 0..
-                     int            seqNo,   // residue sequence number
-                     const InsCode  insCode, // residue insertion code
-                     const AtomName aname,   // atom name
-                     const Element  elmnt,   // chemical element code or '*'
-                     const AltLoc   aloc     // alternate location indicator
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  if ((0<=chNo) && (chNo<mdl->nChains))
-        chn = mdl->Chain[chNo];
-  else  chn = NULL;
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  res = chn->GetResidue ( seqNo,insCode );
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  atm = res->GetAtom ( aname,elmnt,aloc );
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int           modelNo, // model serial number 1...
-                     int           chNo,    // chain number 0...
-                     int           seqNo,   // residue sequence number
-                     const InsCode insCode, // residue insertion code
-                     int           atomNo   // atom number 0...
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  if ((0<=chNo) && (chNo<mdl->nChains))
-        chn = mdl->Chain[chNo];
-  else  chn = NULL;
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  res = chn->GetResidue ( seqNo,insCode );
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  if ((0<=atomNo) && (atomNo<res->nAtoms))
-        atm = res->atom[atomNo];
-  else  atm = NULL;
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int            modelNo, // model serial number 1...
-                     int            chNo,    // chain number 0...
-                     int            resNo,   // residue number 0...
-                     const AtomName aname,   // atom name
-                     const Element  elmnt,   // chemical element code or '*'
-                     const AltLoc   aloc     // alternate location indicator
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  if ((0<=chNo) && (chNo<mdl->nChains))
-        chn = mdl->Chain[chNo];
-  else  chn = NULL;
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  if ((0<=resNo) && (resNo<chn->nResidues))
-        res = chn->Residue[resNo];
-  else  res = NULL;
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  atm = res->GetAtom ( aname,elmnt,aloc );
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-PCAtom CMMDBCoorManager::GetAtom (
-                     int modelNo, // model serial number 1...
-                     int chNo,    // chain number 0...
-                     int resNo,   // residue number 0...
-                     int atomNo   // atom number 0...
-                 )  {
-PCModel   mdl;
-PCChain   chn;
-PCResidue res;
-PCAtom    atm;
-
-  if ((1<=modelNo) && (modelNo<=nModels))
-        mdl = Model[modelNo-1];
-  else  mdl = NULL;
-  if (!mdl)  {
-    CoorIDCode = CID_NoModel;
-    return NULL;
-  }
-
-  if ((0<=chNo) && (chNo<mdl->nChains))
-        chn = mdl->Chain[chNo];
-  else  chn = NULL;
-  if (!chn)  {
-    CoorIDCode = CID_NoChain;
-    return NULL;
-  }
-
-  if ((0<=resNo) && (resNo<chn->nResidues))
-        res = chn->Residue[resNo];
-  else  res = NULL;
-  if (!res)  {
-    CoorIDCode = CID_NoResidue;
-    return NULL;
-  }
-
-  if ((0<=atomNo) && (atomNo<res->nAtoms))
-        atm = res->atom[atomNo];
-  else  atm = NULL;
-  if (!atm)  CoorIDCode = CID_NoAtom;
-       else  CoorIDCode = CID_Ok;
-
-  return atm;
-
-}
-
-
-PCAtom CMMDBCoorManager::GetAtom ( cpstr CID )  {
-int      modno,sn,rc;
-ChainID  chname;
-InsCode  ic;
-ResName  resname;
-AtomName aname;
-Element  elname;
-AltLoc   aloc;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & APATH_Incomplete))  {
-    CoorIDCode = CID_WrongPath;
-    return NULL;
-  }
-
-  return GetAtom ( modno,chname,sn,ic,aname,elname,aloc );
-
-}
-
-
-void CMMDBCoorManager::GetAtomTable ( PPCAtom & atomTable,
-                                      int & NumberOfAtoms )  {
-  atomTable     = Atom;
-  NumberOfAtoms = nAtoms;
-}
-
-void CMMDBCoorManager::GetAtomTable ( int           modelNo,
-                                      const ChainID chainID,
-                                      int           seqNo,
-                                      const InsCode insCode,
-                                      PPCAtom &     atomTable,
-                                      int &         NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      res = Model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
-      if (res)  {
-        atomTable     = res->atom;
-        NumberOfAtoms = res->nAtoms;
-      }
-    }
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable ( int           modelNo,
-                                      int           chainNo,
-                                      int           seqNo,
-                                      const InsCode insCode,
-                                      PPCAtom &     atomTable,
-                                      int &         NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      res = Model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
-      if (res)  {
-        atomTable     = res->atom;
-        NumberOfAtoms = res->nAtoms;
-      }
-    }
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable ( int           modelNo,
-                                      const ChainID chainID,
-                                      int           resNo,
-                                      PPCAtom &     atomTable,
-                                      int &         NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      res = Model[modelNo-1]->GetResidue ( chainID,resNo );
-      if (res)  {
-        atomTable     = res->atom;
-        NumberOfAtoms = res->nAtoms;
-      }
-    }
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable ( int modelNo, int chainNo,
-                                      int resNo, PPCAtom & atomTable,
-                                      int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])  {
-      res = Model[modelNo-1]->GetResidue ( chainNo,resNo );
-      if (res)  {
-        atomTable     = res->atom;
-        NumberOfAtoms = res->nAtoms;
-      }
-    }
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable ( cpstr CID,
-                                      PPCAtom & atomTable,
-                                      int & NumberOfAtoms )  {
-int       modno,sn,rc;
-ChainID   chname;
-InsCode   ic;
-ResName   resname;
-AtomName  aname;
-Element   elname;
-AltLoc    aloc;
-PCResidue res;
-
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
-                       APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
-    CoorIDCode = CID_WrongPath;
-    return;
-  }
-
-  res = GetResidue ( modno,chname,sn,ic );
-  if (res)  {
-    atomTable     = res->atom;
-    NumberOfAtoms = res->nAtoms;
-  }
-
-}
-
-
-void CMMDBCoorManager::GetAtomTable1 ( PPCAtom & atomTable,
-                                       int & NumberOfAtoms )  {
-int i,j;
-  if (atomTable)  delete[] atomTable;
-  if (nAtoms>0)  {
-    atomTable = new PCAtom[nAtoms];
-    j = 0;
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        if (!Atom[i]->Ter)
-          atomTable[j++] = Atom[i];
-      }
-    NumberOfAtoms = j;
-  } else  {
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable1 ( int           modelNo,
-                                       const ChainID chainID,
-                                       int           seqNo,
-                                       const InsCode insCode,
-                                       PPCAtom &     atomTable,
-                                       int &         NumberOfAtoms )  {
-PCResidue res;
-  res = NULL;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      res = Model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
-  }
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable1 ( int           modelNo,
-                                       int           chainNo,
-                                       int           seqNo,
-                                       const InsCode insCode,
-                                       PPCAtom &     atomTable,
-                                       int &         NumberOfAtoms )  {
-PCResidue res;
-  res = NULL;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      res = Model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
-  }
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable1 ( int           modelNo,
-                                       const ChainID chainID,
-                                       int           resNo,
-                                       PPCAtom &     atomTable,
-                                       int &         NumberOfAtoms )  {
-PCResidue res;
-  res = NULL;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      res = Model[modelNo-1]->GetResidue ( chainID,resNo );
-  }
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable1 ( int modelNo, int chainNo,
-                                       int resNo,
-                                       PPCAtom & atomTable,
-                                       int & NumberOfAtoms )  {
-PCResidue res;
-  res = NULL;
-  if ((0<modelNo) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      res = Model[modelNo-1]->GetResidue ( chainNo,resNo );
-  }
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CMMDBCoorManager::GetAtomTable1 ( cpstr CID, PPCAtom & atomTable,
-                                       int & NumberOfAtoms )  {
-int       modno,sn,rc;
-ChainID   chname;
-InsCode   ic;
-ResName   resname;
-AtomName  aname;
-Element   elname;
-AltLoc    aloc;
-PCResidue res;
-
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-
-  CoorIDCode = CID_Ok;
-  rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
-                       aname,elname,aloc,&DefPath );
-  if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
-                       APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
-    CoorIDCode = CID_WrongPath;
-    return;
-  }
-
-  res = GetResidue ( modno,chname,sn,ic );
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-
-}
-
-
-
-int CMMDBCoorManager::DeleteAtom ( int            modelNo,
-                                   const ChainID  chID,
-                                   int            seqNo,
-                                   const InsCode  insCode,
-                                   const AtomName aname,
-                                   const Element  elmnt,
-                                   const AltLoc   aloc )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chID,seqNo,insCode,
-                                            aname,elmnt,aloc );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int           modelNo,
-                                   const ChainID chID,
-                                   int           seqNo,
-                                   const InsCode insCode,
-                                   int           atomNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chID,seqNo,insCode,atomNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int            modelNo,
-                                   const ChainID  chID,
-                                   int            resNo,
-                                   const AtomName aname,
-                                   const Element  elmnt,
-                                   const AltLoc   aloc )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chID,resNo,
-                                            aname,elmnt,aloc );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int           modelNo,
-                                   const ChainID chID,
-                                   int           resNo,
-                                   int           atomNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chID,resNo,atomNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int modelNo, int chNo, int seqNo,
-                                   const InsCode  insCode,
-                                   const AtomName aname,
-                                   const Element  elmnt,
-                                   const AltLoc   aloc )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chNo,seqNo,insCode,
-                                            aname,elmnt,aloc );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int modelNo, int chNo, int seqNo,
-                                   const InsCode insCode, int atomNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chNo,seqNo,insCode,atomNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int modelNo, int chNo, int resNo,
-                                   const AtomName aname,
-                                   const Element  elmnt,
-                                   const AltLoc   aloc )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chNo,resNo,
-                                            aname,elmnt,aloc );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAtom ( int modelNo, int chNo, int resNo,
-                                   int atomNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAtom ( chNo,resNo,atomNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int           modelNo,
-                                       const ChainID chID,
-                                       int           seqNo,
-                                       const InsCode insCode )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms ( chID,seqNo,insCode );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int modelNo, const ChainID chID,
-                                       int resNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms ( chID,resNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int modelNo, const ChainID chID )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms ( chID );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int modelNo, int chNo, int seqNo,
-                                       const InsCode insCode )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms ( chNo,seqNo,insCode );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int modelNo, int chNo,
-                                       int resNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms ( chNo,resNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int modelNo, int chNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms ( chNo );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms ( int modelNo )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->DeleteAllAtoms();
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::DeleteAllAtoms()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  k += Model[i]->DeleteAllAtoms();
-  return k;
-}
-
-
-/*
-int CMMDBCoorManager::DeleteAltLocs()  {
-//  This function leaves only alternative location with maximal
-// occupancy, if those are equal or unspecified, the one with
-// "least" alternative location indicator.
-//  The function returns the number of deleted atoms and optimizes
-// the atom index.
-ChainID  chID;
-ResName  rName;
-InsCode  iCode;
-AtomName aname;
-AltLoc   aLoc,aL;
-realtype occupancy,occ;
-int      seqNum;
-int      i,j,k,i1,i2,n;
-
-  k = 0;
-  n = 0;
-  i = 0;
-  while (i<nAtoms)  {
-
-    if (Atom[i])  {
-      seqNum    = Atom[i]->GetSeqNum   ();
-      occupancy = Atom[i]->GetOccupancy();
-      strcpy ( chID ,Atom[i]->GetChainID() );
-      strcpy ( rName,Atom[i]->GetResName() );
-      strcpy ( iCode,Atom[i]->GetInsCode() );
-      strcpy ( aname,Atom[i]->name   );
-      strcpy ( aLoc ,Atom[i]->altLoc );
-      j  = i+1;
-      i1 = -1;
-      i2 = i;
-      while (j<nAtoms)
-        if (Atom[j])  {
-          if ((Atom[j]->GetSeqNum()==seqNum)         &&
-              (!strcmp(Atom[j]->name,aname))         &&
-              (!strcmp(Atom[j]->GetInsCode(),iCode)) &&
-              (!strcmp(Atom[j]->GetResName(),rName)) &&
-              (!strcmp(Atom[j]->GetChainID(),chID )))  {
-            occ = Atom[j]->GetOccupancy();
-            if (occ>occupancy)  {
-              occupancy = occ;
-              i1 = j;
-            }
-            if (aLoc[0])  {
-              strcpy ( aL,Atom[j]->altLoc );
-              if (!aL[0])  {
-                aLoc[0] = char(0);
-                i2 = j;
-              } else if (strcmp(aL,aLoc)<0)  {
-                strcpy ( aLoc,aL );
-                i2 = j;
-              }
-            }
-            j++;
-          } else
-            break;
-        } else
-          j++;
-      if (i1<0)  {
-        if (Atom[i]->WhatIsSet & ASET_Occupancy)  i1 = i;
-                                            else  i1 = i2;
-      }
-      while (i<j)  {
-        if (Atom[i])  {
-          if (i!=i1)  {
-            delete Atom[i];
-            Atom[i] = NULL;
-            n++;
-          } else  {
-            if (k<i)  {
-              Atom[k] = Atom[i];
-              Atom[k]->index = k+1;
-            }
-            k++;
-          }
-        }
-        i++;
-      }
-
-    } else
-      i++;
-
-  }
-
-  nAtoms = k;
-  return n;
-
-}
-*/
-
-int CMMDBCoorManager::DeleteAltLocs()  {
-//  This function leaves only alternative location with maximal
-// occupancy, if those are equal or unspecified, the one with
-// "least" alternative location indicator.
-//  The function returns the number of deleted atoms. All tables
-// remain untrimmed, so that explicit trimming or calling
-// FinishStructEdit() at some point is required.
-int i,n;
-
-  n = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  n += Model[i]->DeleteAltLocs();
-
-  return n;
-
-}
-
-int CMMDBCoorManager::AddAtom ( int           modelNo,
-                                const ChainID chID,
-                                int           seqNo,
-                                const InsCode insCode,
-                                PCAtom atom )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddAtom ( chID,seqNo,insCode,atom );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::AddAtom ( int modelNo, const ChainID chID,
-                                int resNo, PCAtom atom )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddAtom ( chID,resNo,atom );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::AddAtom ( int modelNo, int chNo,
-                                int seqNo, const InsCode insCode,
-                                PCAtom atom )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddAtom ( chNo,seqNo,insCode,atom );
-  }
-  return 0;
-}
-
-int CMMDBCoorManager::AddAtom ( int modelNo, int chNo,
-                                int resNo, PCAtom atom )  {
-  if ((modelNo>0) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return Model[modelNo-1]->AddAtom ( chNo,resNo,atom );
-  }
-  return 0;
-}
-
-
-void  CMMDBCoorManager::RemoveBricks()  {
-int i,j,k;
-  if (Brick)  {
-    for (i=0;i<nbrick_x;i++)
-      if (Brick[i])  {
-        for (j=0;j<nbrick_y;j++)
-          if (Brick[i][j])  {
-            for (k=0;k<nbrick_z;k++)
-              if (Brick[i][j][k])  delete Brick[i][j][k];
-            delete[] Brick[i][j];
-          }
-        delete[] Brick[i];
-      }
-    delete[] Brick;
-  }
-  Brick = NULL;
-  nbrick_x = 0;
-  nbrick_y = 0;
-  nbrick_z = 0;
-}
-
-void  CMMDBCoorManager::GetBrickCoor ( PCAtom A,
-                                       int & nx, int & ny, int & nz ) {
-  nx = (int)floor((A->x-xbrick_0)/brick_size);
-  ny = (int)floor((A->y-ybrick_0)/brick_size);
-  nz = (int)floor((A->z-zbrick_0)/brick_size);
-  if ((ny<0) || (nz<0) || (nx>=nbrick_x) ||
-      (ny>=nbrick_y) || (nz>=nbrick_z))  nx = -1;
-}
-
-void  CMMDBCoorManager::GetBrickCoor ( realtype x, realtype y,
-                                       realtype z, int & nx,
-                                       int & ny, int & nz ) {
-  nx = (int)floor((x-xbrick_0)/brick_size);
-  ny = (int)floor((y-ybrick_0)/brick_size);
-  nz = (int)floor((z-zbrick_0)/brick_size);
-  if ((ny<0) || (nz<0) || (nx>=nbrick_x) ||
-      (ny>=nbrick_y) || (nz>=nbrick_z))  nx = -1;
-}
-
-void  CMMDBCoorManager::GetBrickDimension (
-                      int & nxmax, int & nymax, int & nzmax )  {
-  if (!Brick)  {
-    nxmax = 0;  nymax = 0;  nzmax = 0;
-  } else  {
-    nxmax = nbrick_x;
-    nymax = nbrick_y;
-    nzmax = nbrick_z;
-  }
-}
-
-PCBrick CMMDBCoorManager::GetBrick ( int nx, int ny, int nz )  {
-  if (!Brick)  return NULL;
-  if ((nx>=0) && (nx<nbrick_x) &&
-      (ny>=0) && (ny<nbrick_y) &&
-      (nz>=0) && (nz<nbrick_z))  {
-    if (!Brick[nx])     return NULL;
-    if (!Brick[nx][ny]) return NULL;
-    return Brick[nx][ny][nz];
-  }
-  return NULL;
-}
-
-void  CMMDBCoorManager::MakeBricks ( PPCAtom  atmvec,  int avlen,
-                                     realtype Margin,
-                                     realtype BrickSize )  {
-//    Makes bricking for atoms contained in vector atmvec of length
-// avlen, with brick size BrickSize (in angstroms). The previous
-// bricking, if there was any, is removed.
-int      i,j, nx,ny,nz, alen;
-realtype x1,x2, y1,y2, z1,z2, dx,dy,dz;
-PPCAtom  A;
-
-  RemoveBricks();
-
-  brick_size = BrickSize;
-
-  if (atmvec)  {
-    A    = atmvec;
-    alen = avlen;
-  } else  {
-    A    = Atom;
-    alen = nAtoms;
-  }
-
-  if (alen>0)  {
-    //  find the range of coordinates
-    x1 = MaxReal;
-    x2 = -x1;
-    y1 = MaxReal;
-    y2 = -y1;
-    z1 = MaxReal;
-    z2 = -z1;
-    for (i=0;i<alen;i++)
-      if (A[i])  {
-        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-          if (A[i]->x<x1)  x1 = A[i]->x;
-          if (A[i]->x>x2)  x2 = A[i]->x;
-          if (A[i]->y<y1)  y1 = A[i]->y;
-          if (A[i]->y>y2)  y2 = A[i]->y;
-          if (A[i]->z<z1)  z1 = A[i]->z;
-          if (A[i]->z>z2)  z2 = A[i]->z;
-        }
-      }
-    if (x1<MaxReal)  {
-      x1 -= Margin; x2 += Margin;
-      y1 -= Margin; y2 += Margin;
-      z1 -= Margin; z2 += Margin;
-      dx = x2-x1;  nbrick_x = mround(dx/brick_size+0.0001)+1;
-      dy = y2-y1;  nbrick_y = mround(dy/brick_size+0.0001)+1;
-      dz = z2-z1;  nbrick_z = mround(dz/brick_size+0.0001)+1;
-      xbrick_0 = x1 - (nbrick_x*brick_size-dx)/2.0;
-      ybrick_0 = y1 - (nbrick_y*brick_size-dy)/2.0;
-      zbrick_0 = z1 - (nbrick_z*brick_size-dz)/2.0;
-      for (i=0;i<alen;i++)
-        if (A[i])  {
-          if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-            GetBrickCoor ( A[i],nx,ny,nz );
-            if (nx>=0)  {
-              if (!Brick)  {
-                Brick = new PPPCBrick[nbrick_x];
-                for (j=0;j<nbrick_x;j++)
-                  Brick[j] = NULL;
-              }
-              if (!Brick[nx])  {
-                Brick[nx] = new PPCBrick[nbrick_y];
-                for (j=0;j<nbrick_y;j++)
-                  Brick[nx][j] = NULL;
-              }
-              if (!Brick[nx][ny])  {
-                Brick[nx][ny] = new PCBrick[nbrick_z];
-                for (j=0;j<nbrick_z;j++)
-                  Brick[nx][ny][j] = NULL;
-              }
-              if (!Brick[nx][ny][nz])
-                Brick[nx][ny][nz] = new CBrick();
-              Brick[nx][ny][nz]->AddAtom ( A[i],i );
-            } else
-              printf ( " error in "
-                       "CMMDBCoorManager::MakeBricks!!!\n" );
-          }
-        }
-    }
-  }
-
-}
-
-
-void  CMMDBCoorManager::RemoveMBricks()  {
-int i,j,k;
-  if (MBrick)  {
-    for (i=0;i<nmbrick_x;i++)
-      if (MBrick[i])  {
-        for (j=0;j<nmbrick_y;j++)
-          if (MBrick[i][j])  {
-            for (k=0;k<nmbrick_z;k++)
-              if (MBrick[i][j][k])  delete MBrick[i][j][k];
-            delete[] MBrick[i][j];
-          }
-        delete[] MBrick[i];
-      }
-    delete[] MBrick;
-  }
-  MBrick = NULL;
-  nmbrick_x = 0;
-  nmbrick_y = 0;
-  nmbrick_z = 0;
-}
-
-void  CMMDBCoorManager::GetMBrickCoor ( PCAtom A,
-                                     int & nx, int & ny, int & nz )  {
-  nx = (int)floor((A->x-xmbrick_0)/mbrick_size);
-  ny = (int)floor((A->y-ymbrick_0)/mbrick_size);
-  nz = (int)floor((A->z-zmbrick_0)/mbrick_size);
-  if ((ny<0) || (nz<0) || (nx>=nmbrick_x) ||
-      (ny>=nmbrick_y)  || (nz>=nmbrick_z))  nx = -nx-1;
-}
-
-void  CMMDBCoorManager::GetMBrickCoor (
-                                realtype x, realtype y, realtype z,
-                                int   & nx, int   & ny, int   & nz )  {
-  nx = (int)floor((x-xmbrick_0)/mbrick_size);
-  ny = (int)floor((y-ymbrick_0)/mbrick_size);
-  nz = (int)floor((z-zmbrick_0)/mbrick_size);
-  if ((ny<0) || (nz<0) || (nx>=nmbrick_x) ||
-        (ny>=nmbrick_y) || (nz>=nmbrick_z))  nx = -nx-1;
-}
-
-void  CMMDBCoorManager::GetMBrickDimension (
-                      int & nxmax, int & nymax, int & nzmax )  {
-  if (!Brick)  {
-    nxmax = 0;  nymax = 0;  nzmax = 0;
-  } else  {
-    nxmax = nmbrick_x;
-    nymax = nmbrick_y;
-    nzmax = nmbrick_z;
-  }
-}
-
-PCMBrick CMMDBCoorManager::GetMBrick ( int nx, int ny, int nz )  {
-  if (!MBrick)  return NULL;
-  if ((nx>=0) && (nx<nmbrick_x) &&
-      (ny>=0) && (ny<nmbrick_y) &&
-      (nz>=0) && (nz<nmbrick_z))  {
-    if (!MBrick[nx])     return NULL;
-    if (!MBrick[nx][ny]) return NULL;
-    return MBrick[nx][ny][nz];
-  }
-  return NULL;
-}
-
-void  CMMDBCoorManager::MakeMBricks ( PPCAtom * atmvec,  ivector avlen,
-                                      int nStructures, realtype Margin,
-                                      realtype BrickSize )  {
-//    Makes bricking for atoms contained in vectors atmvec with lengths
-// given in avlen, with brick size BrickSize (in angstroms).
-// The previous bricking, if there was any, is removed.
-int      i,j,k, nx,ny,nz;
-realtype x1,x2, y1,y2, z1,z2, dx,dy,dz;
-PCAtom   A;
-
-  RemoveMBricks();
-
-  mbrick_size = BrickSize;
-
-  //  find the range of coordinates
-  x1 = MaxReal;
-  x2 = -x1;
-  y1 = MaxReal;
-  y2 = -y1;
-  z1 = MaxReal;
-  z2 = -z1;
-  for (i=0;i<nStructures;i++)
-    for (j=0;j<avlen[i];j++)  {
-      A = atmvec[i][j];
-      if (A)  {
-        if ((!A->Ter) && (A->WhatIsSet & ASET_Coordinates))  {
-          if (A->x<x1)  x1 = A->x;
-          if (A->x>x2)  x2 = A->x;
-          if (A->y<y1)  y1 = A->y;
-          if (A->y>y2)  y2 = A->y;
-          if (A->z<z1)  z1 = A->z;
-          if (A->z>z2)  z2 = A->z;
-        }
-      }
-    }
-  if (x1<MaxReal)  {
-    x1 -= Margin; x2 += Margin;
-    y1 -= Margin; y2 += Margin;
-    z1 -= Margin; z2 += Margin;
-    dx = x2-x1;  nmbrick_x = mround(dx/mbrick_size+0.0001)+1;
-    dy = y2-y1;  nmbrick_y = mround(dy/mbrick_size+0.0001)+1;
-    dz = z2-z1;  nmbrick_z = mround(dz/mbrick_size+0.0001)+1;
-    xmbrick_0 = x1 - (nmbrick_x*mbrick_size-dx)/2.0;
-    ymbrick_0 = y1 - (nmbrick_y*mbrick_size-dy)/2.0;
-    zmbrick_0 = z1 - (nmbrick_z*mbrick_size-dz)/2.0;
-    /*
-    MBrick = new PPPCMBrick[nmbrick_x];
-    for (i=0;i<nmbrick_x;i++)  {
-      MBrick[i] = new PPCMBrick[nmbrick_y];
-      for (j=0;j<nmbrick_y;j++)  {
-        MBrick[i][j] = new PCMBrick[nmbrick_z];
-        for (k=0;k<nmbrick_z;k++)
-          MBrick[i][j][k] = new CMBrick(nStructures);
-      }
-    }
-    */
-    for (i=0;i<nStructures;i++)
-      for (j=0;j<avlen[i];j++)  {
-        A = atmvec[i][j];
-        if (A)  {
-          if ((!A->Ter) && (A->WhatIsSet & ASET_Coordinates))  {
-            GetMBrickCoor ( A,nx,ny,nz );
-            if (nx>=0)  {
-              if (!MBrick)  {
-                MBrick = new PPPCMBrick[nmbrick_x];
-                for (k=0;k<nmbrick_x;k++)
-                  MBrick[k] = NULL;
-              }
-              if (!MBrick[nx])  {
-                MBrick[nx] = new PPCMBrick[nmbrick_y];
-                for (k=0;k<nmbrick_y;k++)
-                  MBrick[nx][k] = NULL;
-              }
-              if (!MBrick[nx][ny])  {
-                MBrick[nx][ny] = new PCMBrick[nmbrick_z];
-                for (k=0;k<nmbrick_z;k++)
-                  MBrick[nx][ny][k] = NULL;
-              }
-              if (!MBrick[nx][ny][nz])
-                MBrick[nx][ny][nz] = new CMBrick(nStructures);
-              MBrick[nx][ny][nz]->AddAtom ( A,i,j );
-            } else
-              printf ( " error in "
-                       "CMMDBCoorManager::MakeMBricks!!!\n" );
-          }
-        }
-      }
-  }
-
-}
-
-
-int  CMMDBCoorManager::GenerateSymMates ( PCGenSym GenSym )  {
-//
-//   The function generates symmetry mates according to symmetry
-// operations found in GenSym. Results of first symmetry operation
-// (number 0) always replaces the existing set of atoms, others
-// are added as additional sets.
-//   If GenSym is set to NULL, the function generates all
-// symmetry mates for the unit cell taking the symmetry information
-// from Cryst.SymOps.
-//   The newly generated chains are added to each model. These
-// chains have many-character chain names, composed as 'x_n',
-// where 'x' is the original name and 'n' is a unique number, which
-// coincides with the symmetry operation (order) number; number '_0'
-// (for the very first symmetry operatyion) is missing. Another
-// side effect is the disorder in atoms' serial numbers.
-//   The hierarchy should therefore be cleaned after
-// generating the symmetry mates. An appropriate way to do
-// that is to issue the following call:
-//
-//   PDBCleanup ( PDBCLEAN_TER | PDBCLEAN_ALTCODE_STRONG |
-//                PDBCLEAN_CHAIN_STRONG | PDBCLEAN_SERIAL );
-//
-PPCMMDBCoorManager Mate;
-int                i,j,k,n,nMates,nMates1,nAtoms1;
-PPCAtom            Atom1;
-PPCModel           Model1;
-
-  if (GenSym)  nMates = GenSym->GetNofSymOps();
-         else  nMates = Cryst.GetNumberOfSymOps();
-  if (nMates<=0)  return GSM_NoSymOps;
-
-  if (!Cryst.areMatrices())       return GSM_NoTransfMatrices;
-  if (!Cryst.isCellParameters())  return GSM_NoCell;
-
-  nMates1 = nMates-1;
-  if (nMates1>0)  {
-
-    //  Generate symmetry mates in parallel hierarchies
-    Mate = new PCMMDBCoorManager[nMates1];
-    for (i=0;i<nMates1;i++)  {
-      Mate[i] = new CMMDBCoorManager();
-      Mate[i]->Copy ( this );
-      Mate[i]->ApplySymTransform ( i+1,GenSym );
-    }
-
-    //  apply 1st symmetry operation:
-    if (GenSym)  ApplySymTransform ( 0,GenSym );
-
-    //  Gather all symmetry mates in 'this' hierarchy
-    nAtoms1 = nMates*nAtoms;        // new number of atoms
-    Atom1   = new PCAtom[nAtoms1];  // new array of atoms
-
-    if (nModels>0)  Model1 = new PCModel[nModels];  // new array of
-              else  Model1 = NULL;                  // models
-
-    k = 0;  // index of collected atoms
-    for (i=0;i<nModels;i++)
-      if (Model[i])  {
-        Model1[i] = newCModel();
-        Model1[i]->SetMMDBManager ( PCMMDBManager(this),i+1 );
-        for (j=0;j<Model[i]->nChains;j++)
-          Model1[i]->MoveChain ( Model[i]->Chain[j],Atom,Atom1,k,0 );
-        for (n=0;n<nMates1;n++)
-          for (j=0;j<Model[i]->nChains;j++)
-            Model1[i]->MoveChain ( Mate[n]->Model[i]->Chain[j],
-                                   Mate[n]->Atom,Atom1,k,n+1 );
-      } else
-        Model1[i] = NULL;
-
-    if (Model) delete[] Model;
-    Model = Model1;
-
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  delete Atom[i];  // should never happen
-    if (Atom)  delete[] Atom;
-    Atom   = Atom1;
-    AtmLen = nAtoms1;   // length of Atom array
-    nAtoms = k;
-
-    //  Dispose parallel hierarchies
-    for (i=0;i<nMates1;i++)
-      delete Mate[i];
-    delete[] Mate;
-
-  } else  {
-    //  just apply the only symmetry operation:
-    if (GenSym)  ApplySymTransform ( 0,GenSym );
-  }
-
-  return GSM_Ok;
-
-}
-
-void  CMMDBCoorManager::ApplyTransform ( mat44 & TMatrix )  {
-// simply transforms all coordinates by multiplying with matrix TMatrix
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])  {
-      if (!Atom[i]->Ter)  Atom[i]->Transform ( TMatrix );
-    }
-}
-
-void  CMMDBCoorManager::ApplySymTransform ( int      SymOpNo,
-                                            PCGenSym GenSym )  {
-//    This procedure applies the symmetry operation number SymOpNo
-// (starting from 0 on) and renames chains as specified in
-// GenSym.
-//    The chains don't have to be renamed. The number of chains
-// to be renamed is obtained as GenSym->nChains[SymOpNo], their
-// old names - as GenSym->chID1[SymOpNo][j], and their new names
-// - as GenSym->chID2[SymOpNo][j],  0<=j<GenSym->nChains[SymOpNo].
-mat44    tmat;
-int      i,j,k,nChn;
-PPCChain chain;
-  if (Cryst.GetTMatrix(tmat,SymOpNo,0,0,0,PCSymOps(GenSym))
-       ==SYMOP_Ok)  {
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        if (!Atom[i]->Ter)  Atom[i]->Transform ( tmat );
-      }
-    if (GenSym)
-      for (i=0;i<nModels;i++)
-        if (Model[i])  {
-          Model[i]->GetChainTable ( chain,nChn );
-          for (j=0;j<GenSym->nChains[SymOpNo];j++)
-            for (k=0;k<nChn;k++)
-              if (!strcmp(chain[k]->chainID,GenSym->chID1[SymOpNo][j]))
-                chain[k]->SetChainID ( GenSym->chID2[SymOpNo][j] );
-        }
-  }
-}
-
-
-void  GetEulerRotMatrix ( mat33 & erm,
-                          realtype alpha,
-                          realtype beta,
-                          realtype gamma )  {
-//  Calculates the Euler rotation matrix for rotation:
-//                   1) about z-axis by angle alpha (0..2*Pi)
-//                   2) about new y-axis by angle beta (0..Pi)
-//                   3) about new z-axis by angle gamma (0..2*Pi)
-realtype ca,cb,cg, sa,sb,sg;
-
-  ca = cos(alpha);
-  sa = sin(alpha);
-  cb = cos(beta);
-  sb = sin(beta);
-  cg = cos(gamma);
-  sg = sin(gamma);
-
-  erm[0][0] =  ca*cb*cg - sa*sg;
-  erm[0][1] =  cb*cg*sa + ca*sg;
-  erm[0][2] = -cg*sb;
-
-  erm[1][0] = -cg*sa - ca*cb*sg;
-  erm[1][1] =  ca*cg - cb*sa*sg;
-  erm[1][2] =  sb*sg;
-
-  erm[2][0] =  ca*sb;
-  erm[2][1] =  sa*sb;
-  erm[2][2] =  cb;
-
-}
-
-
-
-void  GetEulerTMatrix ( mat44 & erm,
-                        realtype alpha,
-                        realtype beta,
-                        realtype gamma,
-                        realtype x0,
-                        realtype y0,
-                        realtype z0 )  {
-//  Calculates the Euler rotation-translation matrix for rotation:
-//                   1) about z-axis by angle alpha
-//                   2) about new y-axis by angle beta
-//                   3) about new z-axis by angle gamma
-//  Point (x0,y0,z0) is the center of rotation.
-mat33 m;
-
-  m[0][0] = 1.0;
-  GetEulerRotMatrix ( m,alpha,beta,gamma );
-
-  erm[0][0] = m[0][0];  erm[0][1] = m[0][1];  erm[0][2] = m[0][2];
-  erm[1][0] = m[1][0];  erm[1][1] = m[1][1];  erm[1][2] = m[1][2];
-  erm[2][0] = m[2][0];  erm[2][1] = m[2][1];  erm[2][2] = m[2][2];
-  erm[3][0] = 0.0;      erm[3][1] = 0.0;      erm[3][2] = 0.0;
-
-  erm[3][3] = 1.0;
-
-  erm[0][3] = x0 - m[0][0]*x0 - m[0][1]*y0 - m[0][2]*z0;
-  erm[1][3] = y0 - m[1][0]*x0 - m[1][1]*y0 - m[1][2]*z0;
-  erm[2][3] = z0 - m[2][0]*x0 - m[2][1]*y0 - m[2][2]*z0;
-
-}
-
-
-void  EulerRotation ( PPCAtom  A,
-                      int      nA,
-                      realtype alpha,
-                      realtype beta,
-                      realtype gamma,
-                      realtype x0,
-                      realtype y0,
-                      realtype z0 )  {
-//  Euler rotation:  1) about z-axis by angle alpha
-//                   2) about new y-axis by angle beta
-//                   3) about new z-axis by angle gamma
-//  Point (x0,y0,z0) is the center of rotation.
-mat33    m;
-realtype x,y,z;
-int      i;
-
-  m[0][0] = 1.0;
-  GetEulerRotMatrix ( m,alpha,beta,gamma );
-
-  for (i=0;i<nA;i++)
-    if (A[i])  {
-      if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-        x = A[i]->x - x0;
-        y = A[i]->y - y0;
-        z = A[i]->z - z0;
-        A[i]->x = m[0][0]*x + m[0][1]*y + m[0][2]*z + x0;
-        A[i]->y = m[1][0]*x + m[1][1]*y + m[1][2]*z + y0;
-        A[i]->z = m[2][0]*x + m[2][1]*y + m[2][2]*z + z0;
-      }
-    }
-
-}
-
-
-void  GetVecRotMatrix ( mat33 & vrm,
-                        realtype alpha,
-                        realtype vx,
-                        realtype vy,
-                        realtype vz )  {
-//   Calculates the rotation matrix for rotation by angle alpha about
-// arbitrary vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
-realtype ca,sa, rx,ry,rz, vl;
-
-  ca = cos(alpha);
-  sa = sin(alpha);
-
-  vl = sqrt ( vx*vx + vy*vy + vz*vz );
-  if (vl<=0.0)  return;
-  rx = vx/vl;
-  ry = vy/vl;
-  rz = vz/vl;
-
-  vrm[0][0] = rx*rx*(1.0-ca) + ca;
-  vrm[0][1] = rx*ry*(1.0-ca) - rz*sa;
-  vrm[0][2] = rx*rz*(1.0-ca) + ry*sa;
-
-  vrm[1][0] = ry*rx*(1.0-ca) + rz*sa;
-  vrm[1][1] = ry*ry*(1.0-ca) + ca;
-  vrm[1][2] = ry*rz*(1.0-ca) - rx*sa;
-
-  vrm[2][0] = rz*rx*(1.0-ca) - ry*sa;
-  vrm[2][1] = rz*ry*(1.0-ca) + rx*sa;
-  vrm[2][2] = rz*rz*(1.0-ca) + ca;
-
-}
-
-
-void  GetRotParameters ( mat33    & vrm,
-                         realtype & alpha,
-                         realtype & vx,
-                         realtype & vy,
-                         realtype & vz )  {
-//    Given the rotation matrix vrm, GetRotParameters(..)
-//  returns the rotation angle alpha and the normalized
-//  rotation axis vector (vx,vy,vz).
-//    The rotation angle and vector are determined up to
-//  their sign (however correlated, so that being substituted
-//  into GetVecRotMatrix(..) they yield the same rotation
-//  matrix).
-//    The function does not check for vrm to be a valid
-//  rotation matrix.
-realtype ca,sa,vl;
-  ca = (vrm[0][0]+vrm[1][1]+vrm[2][2]-1.0)/2.0;
-  if (ca<-1.0) ca = -1.0;  // does not work if rotation
-  if (ca>1.0)  ca =  1.0;  //   matrix is correct
-  sa = sqrt(1.0-ca*ca);
-  if (sa>0.0)  {
-    alpha = acos(ca);
-    // coefficient of 2 is corrected by normalization below
-    vx    = (vrm[2][1]-vrm[1][2])/sa;
-    vy    = (vrm[0][2]-vrm[2][0])/sa;
-    vz    = (vrm[1][0]-vrm[0][1])/sa;
-    // the following code is formally redundant if rotation
-    // matrix is correct, however it eliminates the round-offs
-    vl    = sqrt(vx*vx+vy*vy+vz*vz);
-    vx   /= vl;
-    vy   /= vl;
-    vz   /= vl;
-  } else  {
-    // zero rotation, arbitrary axis would do
-    alpha = 0.0;
-    vx    = 1.0;
-    vy    = 0.0;
-    vz    = 0.0;
-  }
-}
-
-
-void  GetVecTMatrix ( mat44 & vrm,
-                      realtype alpha,
-                      realtype vx,
-                      realtype vy,
-                      realtype vz,
-                      realtype x0,
-                      realtype y0,
-                      realtype z0 )  {
-//   Calculates the rotation-translation matrix for rotation by angle
-// alpha about arbitrary vector directed as (vx,vy,vz) =
-// (vx2-vx1,vy2-vy1,vz2-vz1). Point (x0,y0,z0) is the center of
-// rotation -- actually a point belonging to the rotation axis.
-mat33 m;
-
-  GetVecRotMatrix ( m,alpha,vx,vy,vz );
-
-  vrm[0][0] = m[0][0];  vrm[0][1] = m[0][1];  vrm[0][2] = m[0][2];
-  vrm[1][0] = m[1][0];  vrm[1][1] = m[1][1];  vrm[1][2] = m[1][2];
-  vrm[2][0] = m[2][0];  vrm[2][1] = m[2][1];  vrm[2][2] = m[2][2];
-  vrm[3][0] = 0.0;      vrm[3][1] = 0.0;      vrm[3][2] = 0.0;
-
-  vrm[3][3] = 1.0;
-
-  vrm[0][3] = x0 - m[0][0]*x0 - m[0][1]*y0 - m[0][2]*z0;
-  vrm[1][3] = y0 - m[1][0]*x0 - m[1][1]*y0 - m[1][2]*z0;
-  vrm[2][3] = z0 - m[2][0]*x0 - m[2][1]*y0 - m[2][2]*z0;
-
-}
-
-
-void  VectorRotation ( PPCAtom  A,
-                       int      nA,
-                       realtype alpha,
-                       realtype vx,
-                       realtype vy,
-                       realtype vz,
-                       realtype x0,
-                       realtype y0,
-                       realtype z0 )  {
-//   Vector rotation is rotation by angle alpha about arbitrary
-// vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
-// Point (x0,y0,z0) is the center of rotation -- actually
-// a point belonging to the rotation axis.
-mat33    m;
-realtype x,y,z;
-int      i;
-
-  GetVecRotMatrix ( m, alpha,vx,vy,vz );
-
-  for (i=0;i<nA;i++)
-    if (A[i])  {
-      if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-        x = A[i]->x - x0;
-        y = A[i]->y - y0;
-        z = A[i]->z - z0;
-        A[i]->x = m[0][0]*x + m[0][1]*y + m[0][2]*z + x0;
-        A[i]->y = m[1][0]*x + m[1][1]*y + m[1][2]*z + y0;
-        A[i]->z = m[2][0]*x + m[2][1]*y + m[2][2]*z + z0;
-      }
-    }
-
-}
-
-
-void  GetMassCenter ( PPCAtom    A,   int        nA,
-                      realtype & xmc, realtype & ymc,
-                      realtype & zmc )  {
-realtype w,mass;
-int      i,k;
-
-  xmc  = 0.0;
-  ymc  = 0.0;
-  zmc  = 0.0;
-  mass = 0.0;
-
-  for (i=0;i<nA;i++)
-    if (A[i])  {
-      if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-        k = getElementNo ( A[i]->element );
-        if (k>=0)  w = MolecWeight[k];
-             else  w = 1.0;
-        xmc  += w*A[i]->x;
-        ymc  += w*A[i]->y;
-        zmc  += w*A[i]->z;
-        mass += w;
-      }
-    }
-
-  if (mass>0.0)  {
-    xmc /= mass;
-    ymc /= mass;
-    zmc /= mass;
-  }
-
-}
-
-int CMMDBCoorManager::BringToUnitCell()  {
-// brings all chains into 0th unit cell
-PCChain   chain;
-PPCAtom   atom;
-realtype  x0,y0,z0, x,y,z, xf,yf,zf, sx,sy,sz;
-realtype  dx,dy,dz, d,d0;
-int       nAtoms;
-int       i,j,k,n,m,nt, ic,jc,kc, is,js,ks;
-
-  if (!Cryst.areMatrices())  return -1;
-
-  is = 0;  // this is only
-  js = 0;  //   to depress
-  ks = 0;  //      "uninitialized" worning
-
-  Cryst.Frac2Orth ( 0.5,0.5,0.5, x0,y0,z0 );
-
-  nt = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  {
-      for (j=0;j<Model[i]->nChains;j++)  {
-        chain = Model[i]->Chain[j];
-        if (chain)  {
-
-          x = 0.0;
-          y = 0.0;
-          z = 0.0;
-          m = 0;
-          for (k=0;k<chain->nResidues;k++)
-            if (chain->Residue[k])  {
-              chain->Residue[k]->GetAtomTable ( atom,nAtoms );
-              for (n=0;n<nAtoms;n++)
-                if (atom[n])  {
-                  if (!atom[n]->Ter)  {
-                    x += atom[n]->x;
-                    y += atom[n]->y;
-                    z += atom[n]->z;
-                    m++;
-                  }
-                }
-            }
-          x /= m;
-          y /= m;
-          z /= m;
-
-          Cryst.Orth2Frac ( x,y,z, xf,yf,zf );
-          sx = frac ( xf );
-          sy = frac ( yf );
-          sz = frac ( zf );
-          d0 = MaxReal;
-          for (ic=-3;ic<3;ic++)
-            for (jc=-3;jc<3;jc++)
-              for (kc=-3;kc<3;kc++)  {
-                Cryst.Frac2Orth ( sx+ic,sy+jc,sz+kc, dx,dy,dz );
-                dx -= x0;
-                dy -= y0;
-                dz -= z0;
-                d = dx*dx + dy*dy + dz*dz;
-                if (d<d0)  {
-                  d0 = d;
-                  is = ic;
-                  js = jc;
-                  ks = kc;
-                }
-              }
-
-          sx = xf - (sx+is);
-          sy = yf - (sy+js);
-          sz = zf - (sz+ks);
-
-          if ((fabs(sx)>1.0e-10) || (fabs(sy)>1.0e-10)
-                                 || (fabs(sz)>1.0e-10))  {
-            nt++;
-            for (k=0;k<chain->nResidues;k++)
-              if (chain->Residue[k])  {
-                chain->Residue[k]->GetAtomTable ( atom,nAtoms );
-                for (n=0;n<nAtoms;n++)
-                  if (atom[n])  {
-                    if (!atom[n]->Ter)  {
-                      Cryst.Orth2Frac ( atom[n]->x,atom[n]->y,
-                                        atom[n]->z,
-                                        xf,yf,zf );
-                      Cryst.Frac2Orth ( xf-sx,yf-sy,zf-sz,
-                                        atom[n]->x,atom[n]->y,
-                                        atom[n]->z );
-                    }
-                  }
-              }
-          }
-
-        }
-      }
-    }
-
-  return nt;  // number of converted chains
-
-}
-
-
-Boolean CMMDBCoorManager::Frac2Orth (
-              realtype   xfrac, realtype   yfrac, realtype   zfrac,
-              realtype & xorth, realtype & yorth, realtype & zorth )  {
-  return Cryst.Frac2Orth ( xfrac,yfrac,zfrac, xorth,yorth,zorth );
-}
-
-Boolean CMMDBCoorManager::Orth2Frac (
-              realtype   xorth, realtype   yorth, realtype   zorth,
-              realtype & xfrac, realtype & yfrac, realtype & zfrac )  {
-  return Cryst.Orth2Frac ( xorth,yorth,zorth, xfrac,yfrac,zfrac );
-}
-
-
-Boolean CMMDBCoorManager::Frac2Orth ( mat44 & F, mat44 & T )  {
-  return Cryst.Frac2Orth ( F,T );
-}
-
-Boolean CMMDBCoorManager::Orth2Frac ( mat44 & T, mat44 & F )  {
-  return Cryst.Orth2Frac ( T,F );
-}
-
-
-
-//  ------------------------  Contacts  -------------------------------
-
-
-#define  CA_CA_Dist2  16.0
-
-void  CMMDBCoorManager::FindSeqSection ( PCAtom atom, int seqDist,
-                                         int  & seq1, int & seq2 )  {
-PCAtom    a;
-PCResidue res;
-PCChain   chain;
-realtype  x0,y0,z0, x,y,z, dx,dy,dz, d2;
-int       i1;
-Boolean   B0,B;
-
-  x  = 0.0;
-  y  = 0.0;
-  z  = 0.0;
-  x0 = 0.0;
-  y0 = 0.0;
-  z0 = 0.0;
-
-  res = atom->residue;
-  if ((!res) || (seqDist<=0))  {
-    seq1 = MaxInt4;
-    seq2 = MinInt4;
-    return;
-  }
-
-  chain = res->chain;
-  if (!chain)  {
-    seq1 = MaxInt4;
-    seq2 = MinInt4;
-    return;
-  }
-
-  if (seqDist==1)  {
-    seq1 = res->index;
-    seq2 = seq1;
-    return;
-  }
-
-  a = res->GetAtom ( pstr("CA"),pstr("C"),NULL );
-  if (a)  {
-    x0 = a->x;
-    y0 = a->y;
-    z0 = a->z;
-    B0 = True;
-  } else
-    B0 = False;
-  if (B0)  {
-    x = x0;
-    y = y0;
-    z = z0;
-  }
-
-  B    = B0;
-  seq2 = res->index;
-  i1   = IMin(chain->nResidues,seq2+seqDist)-1;
-  while (seq2<i1)  {
-    seq2++;
-    if (chain->Residue[seq2])  {
-      a = chain->Residue[seq2]->GetAtom ( pstr("CA"),pstr("C"),NULL );
-      if (a && B)  {
-        dx = x-a->x;
-        dy = y-a->y;
-        dz = z-a->z;
-        d2 = dx*dx + dy*dy + dz*dz;
-        if (d2>CA_CA_Dist2)  {
-          seq2--;
-          break;
-        }
-      }
-      if (a)  {
-        x = a->x;
-        y = a->y;
-        z = a->z;
-        B = True;
-      } else
-        B = False;
-    }
-  }
-
-  if (B0)  {
-    x = x0;
-    y = y0;
-    z = z0;
-  }
-  B    = B0;
-  seq1 = res->index;
-  i1   = IMax(0,seq1-seqDist+1);
-  while (seq1>i1)  {
-    seq1--;
-    if (chain->Residue[seq1])  {
-      a = chain->Residue[seq1]->GetAtom ( pstr("CA"),pstr("C"),NULL );
-      if (a && B)  {
-        dx = x-a->x;
-        dy = y-a->y;
-        dz = z-a->z;
-        d2 = dx*dx + dy*dy + dz*dz;
-        if (d2>CA_CA_Dist2)  {
-          seq1++;
-          break;
-        }
-      }
-      if (a)  {
-        x = a->x;
-        y = a->y;
-        z = a->z;
-        B = True;
-      } else
-        B = False;
-    }
-  }
-
-}
-
-
-Boolean  CMMDBCoorManager::isContact ( PCAtom    a1, PCAtom    a2,
-                                       int     seq1, int     seq2,
-                                       realtype  dd, realtype d12,
-                                       realtype d22, realtype & d2 )  {
-//  seq1..seq2 is forbidden region for residue sequence numbers
-PCResidue  res1,res2;
-PCChain    chain1,chain2;
-realtype   dx,dy,dz;
-
-  if (a2->Ter)  return False;
-
-  dx = fabs(a2->x-a1->x);
-  if (dx<=dd)  {
-    dy = fabs(a2->y-a1->y);
-    if (dy<=dd)  {
-      dz = fabs(a2->z-a1->z);
-      if (dz<=dd)  {
-        d2 = dx*dx + dy*dy + dz*dz;
-        if ((d12<=d2) && (d2<=d22))  {
-          if (seq1<=seq2)  {
-            res1 = a1->residue;
-            res2 = a2->residue;
-            if (res1 && res2)  {
-              chain1 = res1->chain;
-              chain2 = res2->chain;
-              if (chain1 && chain2)  {
-                if (!strcmp(chain1->chainID,chain2->chainID))  {
-                  if ((seq1<=res2->index) && (res2->index<=seq2))
-                    return False;
-                }
-              }
-            }
-          }
-          return True;
-        }
-      }
-    }
-  }
-
-  return False;
-
-}
-
-Boolean  CMMDBCoorManager::isContact ( realtype   x, realtype   y,
-                                       realtype   z, PCAtom    a2,
-                                       realtype  dd, realtype d12,
-                                       realtype d22, realtype & d2 )  {
-realtype dx,dy,dz;
-
-  if (a2->Ter)  return False;
-
-  dx = fabs(a2->x-x);
-  if (dx<=dd)  {
-    dy = fabs(a2->y-y);
-    if (dy<=dd)  {
-      dz = fabs(a2->z-z);
-      if (dz<=dd)  {
-        d2 = dx*dx + dy*dy + dz*dz;
-        if ((d12<=d2) && (d2<=d22))  return True;
-      }
-    }
-  }
-
-  return False;
-
-}
-
-
-void  CMMDBCoorManager::SeekContacts ( PPCAtom    AIndex,
-                                       int        ilen,
-                                       int        atomNum,
-                                       realtype   dist1,
-                                       realtype   dist2,
-                                       int        seqDist,
-                                       RPSContact contact,
-                                       int &      ncontacts,
-                                       int        maxlen,
-                                       long       group )  {
-PCContactIndex ContactIndex;
-realtype       d12,d22,d2;
-int            i,seq1,seq2;
-
-  if (!AIndex)              return;
-  if (dist2<dist1)          return;
-  if (!AIndex[atomNum])     return;
-  if (AIndex[atomNum]->Ter) return;
-
-  ContactIndex = new CContactIndex ( contact,maxlen,ncontacts,ilen );
-
-  FindSeqSection ( AIndex[atomNum],seqDist,seq1,seq2 );
-
-  d12 = dist1*dist1;
-  d22 = dist2*dist2;
-
-  for (i=0;i<ilen;i++)
-    if ((i!=atomNum) && AIndex[i])  {
-      if (isContact(AIndex[atomNum],AIndex[i],seq1,seq2,dist2,
-                    d12,d22,d2))
-         ContactIndex->AddContact ( atomNum,i,sqrt(d2),group );
-    }
-
-  ContactIndex->GetIndex ( contact,ncontacts );
-
-  delete ContactIndex;
-
-}
-
-
-void  CMMDBCoorManager::SeekContacts ( PCAtom     A,
-                                       PPCAtom    AIndex,
-                                       int        ilen,
-                                       realtype   dist1,
-                                       realtype   dist2,
-                                       int        seqDist,
-                                       RPSContact contact,
-                                       int &      ncontacts,
-                                       int        maxlen,
-                                       long       group
-                                     )  {
-PCContactIndex ContactIndex;
-realtype       d12,d22,d2;
-int            i,seq1,seq2;
-
-  if (!AIndex)     return;
-  if (dist2<dist1) return;
-  if (!A)          return;
-  if (A->Ter)      return;
-
-  ContactIndex = new CContactIndex ( contact,maxlen,ncontacts,ilen );
-
-  FindSeqSection ( A,seqDist,seq1,seq2 );
-
-  d12 = dist1*dist1;
-  d22 = dist2*dist2;
-
-  for (i=0;i<ilen;i++)
-    if ((AIndex[i]!=A) && AIndex[i])  {
-      if (isContact(A,AIndex[i],seq1,seq2,dist2,d12,d22,d2))
-        ContactIndex->AddContact ( -1,i,sqrt(d2),group );
-    }
-
-  ContactIndex->GetIndex ( contact,ncontacts );
-
-  delete ContactIndex;
-
-}
-
-
-void  CMMDBCoorManager::SeekContacts ( PPCAtom    AIndex1,
-                                       int        ilen1,
-                                       PPCAtom    AIndex2,
-                                       int        ilen2,
-                                       realtype   dist1,
-                                       realtype   dist2,
-                                       int        seqDist,
-                                       RPSContact contact,
-                                       int &      ncontacts,
-                                       int        maxlen,
-                                       mat44 *    TMatrix,
-                                       long       group,
-                                       int        bricking,
-                                       Boolean    doSqrt
-                                     )  {
-//  It is Ok to have NULL pointers in AIndex1 and AIndex2
-PCContactIndex ContactIndex;
-PPCAtom        A1,A2;
-rvector        sx0,sy0,sz0;
-rvector        dx0,dy0,dz0;
-realtype       d12,d22,d2, eps;
-int            l1,l2, i,j, nx,ny,nz, dn;
-int            ix1,ix2, iy1,iy2, iz1,iz2, ix,iy,iz;
-int            seq1,seq2;
-PCBrick        B;
-Boolean        swap,UnitT;
-
-  if ((dist2<dist1) || (!AIndex1) || (!AIndex2))  return;
-
-  ContactIndex = new CContactIndex ( contact,maxlen,ncontacts,
-                                     ilen1*ilen2 );
-
-  sx0   = NULL;
-  sy0   = NULL;
-  sz0   = NULL;
-  dx0   = NULL;
-  dy0   = NULL;
-  dz0   = NULL;
-  UnitT = True;
-  if (TMatrix)  {
-    // Transformation matrix is given. Check that that is not
-    // the unit one.
-    eps = 1.0e-6;
-    for (i=0;(i<3) && UnitT;i++)
-      for (j=0;(j<4) && UnitT;j++)
-        if (i==j)  UnitT = fabs(1.0-(*TMatrix)[i][j])<eps;
-             else  UnitT = fabs((*TMatrix)[i][j])<eps;
-    if (!UnitT)  {
-      // A non-unit transformation to AIndex2 is required.
-      // As AIndex1 and AIndex2 may overlap, we have to save
-      // the original AIndex1 coordinates
-      GetVectorMemory ( sx0,ilen1,0 );
-      GetVectorMemory ( sy0,ilen1,0 );
-      GetVectorMemory ( sz0,ilen1,0 );
-      for (i=0;i<ilen1;i++)
-        if (AIndex1[i])  {
-          sx0[i] = AIndex1[i]->x;
-          sy0[i] = AIndex1[i]->y;
-          sz0[i] = AIndex1[i]->z;
-        }
-      // Save original AIndex2 coordinates and modify the index
-      GetVectorMemory ( dx0,ilen2,0 );
-      GetVectorMemory ( dy0,ilen2,0 );
-      GetVectorMemory ( dz0,ilen2,0 );
-      for (i=0;i<ilen2;i++)
-        if (AIndex2[i])  {
-          dx0[i] = AIndex2[i]->x;
-          dy0[i] = AIndex2[i]->y;
-          dz0[i] = AIndex2[i]->z;
-          AIndex2[i]->Transform ( *TMatrix );
-        }
-    }
-  }
-
-  // choose A2 as the largest atom set convenient for
-  // bricking (bricking on larger set is more efficient)
-  if (bricking & BRICK_ON_1)  {
-    A1   = AIndex2;
-    A2   = AIndex1;
-    l1   = ilen2;
-    l2   = ilen1;
-    swap = True;
-  } else if (bricking & BRICK_ON_2)  {
-    A1   = AIndex1;
-    A2   = AIndex2;
-    l1   = ilen1;
-    l2   = ilen2;
-    swap = False;
-  } else if (ilen1<=ilen2)  {
-    A1   = AIndex1;
-    A2   = AIndex2;
-    l1   = ilen1;
-    l2   = ilen2;
-    swap = False;
-  } else  {
-    A1   = AIndex2;
-    A2   = AIndex1;
-    l1   = ilen2;
-    l2   = ilen1;
-    swap = True;
-  }
-
-  d12 = dist1*dist1;
-  d22 = dist2*dist2;
-
-  if (((bricking & BRICK_READY)==0) || (!Brick))
-    MakeBricks ( A2,l2,dist2*1.5 );
-
-  dn = mround(dist2/brick_size)+1;
-
-  if (Brick)
-    for (i=0;i<l1;i++)
-      if (A1[i])  {
-        if (!A1[i]->Ter)  {
-          if (UnitT)  {
-            // No transformation -- AIndex1 and AIndex2 are unmodified.
-            // Calculate the forbidden sequence region
-            FindSeqSection ( A1[i],seqDist,seq1,seq2 );
-            // And the brick location
-            GetBrickCoor   ( A1[i],nx,ny,nz );
-          } else  {
-            // AIndex2 and AIndex1 are modified, but the sequence
-            // distance does not apply to physically different chains
-            // (meaning that transformation of A2 effectively makes
-            // a different chain). Use unmodified atom coordinates
-            // of 1st set for calculating the brick location.
-            if (swap) GetBrickCoor ( A1[i],nx,ny,nz ); // A1 is AIndex2
-                 else GetBrickCoor ( sx0[i],sy0[i],sz0[i],nx,ny,nz );
-        }
-        if (nx>=0)  {
-          ix1 = IMax ( 0,nx-dn );
-          iy1 = IMax ( 0,ny-dn );
-          iz1 = IMax ( 0,nz-dn );
-          ix2 = IMin ( nbrick_x,nx+dn+1 );
-          iy2 = IMin ( nbrick_y,ny+dn+1 );
-          iz2 = IMin ( nbrick_z,nz+dn+1 );
-          if (UnitT)  {
-            // AIndex1 unmodified, use it
-            for (ix=ix1;ix<ix2;ix++)
-              if (Brick[ix])
-                for (iy=iy1;iy<iy2;iy++)
-                  if (Brick[ix][iy])
-                    for (iz=iz1;iz<iz2;iz++)  {
-                      B = Brick[ix][iy][iz];
-                      if (B)
-                        for (j=0;j<B->nAtoms;j++)
-                          if (B->Atom[j]!=A1[i])  {
-                            if (isContact(A1[i],B->Atom[j],seq1,seq2,
-                                          dist2,d12,d22,d2))  {
-                              if (doSqrt)  d2 = sqrt(d2);
-                              if (swap)  ContactIndex->AddContact (
-                                           B->id[j],i,d2,group );
-                                   else  ContactIndex->AddContact (
-                                           i,B->id[j],d2,group );
-                            }
-                          }
-                    }
-          } else if (swap)  {
-            // A1 stands for AIndex2, it is modified and we need to use
-            // the modified coordinates
-            for (ix=ix1;ix<ix2;ix++)
-              if (Brick[ix])
-                for (iy=iy1;iy<iy2;iy++)
-                  if (Brick[ix][iy])
-                    for (iz=iz1;iz<iz2;iz++)  {
-                      B = Brick[ix][iy][iz];
-                      if (B)
-                        for (j=0;j<B->nAtoms;j++)
-                          if (isContact(A1[i]->x,A1[i]->y,A1[i]->z,
-                                        B->Atom[j], dist2,d12,d22,d2))  {
-                            if (doSqrt)  d2 = sqrt(d2);
-                            ContactIndex->AddContact ( B->id[j],i,d2,group );
-                          }
-                    }
-          } else  {
-            // A1 stands for AIndex1, it may be modified (if AIndex1
-            // and AIndex2 overlap) -- use its unmodified coordinates
-            // instead.
-            for (ix=ix1;ix<ix2;ix++)
-              if (Brick[ix])
-                for (iy=iy1;iy<iy2;iy++)
-                  if (Brick[ix][iy])
-                    for (iz=iz1;iz<iz2;iz++)  {
-                      B = Brick[ix][iy][iz];
-                      if (B)
-                        for (j=0;j<B->nAtoms;j++)
-                          if (isContact(sx0[i],sy0[i],sz0[i],
-                                        B->Atom[j],dist2,d12,d22,d2))  {
-                            if (doSqrt)  d2 = sqrt(d2);
-                            ContactIndex->AddContact ( i,B->id[j],d2,group );
-                          }
-                    }
-          }
-        }
-      }
-    }
-
-
-  if (!UnitT)  {
-    // restore original coordinates
-    for (i=0;i<ilen1;i++)
-      if (AIndex1[i])  {
-        AIndex1[i]->x = sx0[i];
-        AIndex1[i]->y = sy0[i];
-        AIndex1[i]->z = sz0[i];
-      }
-    for (i=0;i<ilen2;i++)
-      if (AIndex2[i])  {
-        AIndex2[i]->x = dx0[i];
-        AIndex2[i]->y = dy0[i];
-        AIndex2[i]->z = dz0[i];
-      }
-    FreeVectorMemory ( sx0,0 );
-    FreeVectorMemory ( sy0,0 );
-    FreeVectorMemory ( sz0,0 );
-    FreeVectorMemory ( dx0,0 );
-    FreeVectorMemory ( dy0,0 );
-    FreeVectorMemory ( dz0,0 );
-  }
-
-  ContactIndex->GetIndex ( contact,ncontacts );
-
-  delete ContactIndex;
-
-}
-
-
-void  CMMDBCoorManager::SeekContacts ( PPCAtom   AIndex1,
-                                       int       ilen1,
-                                       PPCAtom   AIndex2,
-                                       int       ilen2,
-                                       realtype  contDist,
-                                       PSContact contact,
-                                       int &     ncontacts,
-                                       int       bricking
-                                     )  {
-//  Simplified optimized for speed version:
-//    - no NULL pointers and Ters in AIndex1 and AIndex2
-//    - no checks for identity atoms in AIndex1 and AIndex2
-//    - contact must be pre-allocated with at least ilen1*ilen2 elements
-//    - contact returns square distances
-//    - ncontacts is always reset
-PPCAtom   A1,A2;
-realtype  contDist2, dx,dy,dz, d2;
-int       l1,l2, i,j, nx,ny,nz, dn;
-int       ix1,ix2, iy1,iy2, iz1,iz2, ix,iy,iz;
-PCBrick   B;
-Boolean   swap;
-
-  // choose A2 as the largest atom set convenient for
-  // bricking (bricking on larger set is more efficient)
-  if (bricking & BRICK_ON_1)  {
-    A1   = AIndex2;
-    A2   = AIndex1;
-    l1   = ilen2;
-    l2   = ilen1;
-    swap = True;
-  } else if (bricking & BRICK_ON_2)  {
-    A1   = AIndex1;
-    A2   = AIndex2;
-    l1   = ilen1;
-    l2   = ilen2;
-    swap = False;
-  } else if (ilen1<=ilen2)  {
-    A1   = AIndex1;
-    A2   = AIndex2;
-    l1   = ilen1;
-    l2   = ilen2;
-    swap = False;
-  } else  {
-    A1   = AIndex2;
-    A2   = AIndex1;
-    l1   = ilen2;
-    l2   = ilen1;
-    swap = True;
-  }
-
-  contDist2 = contDist*contDist;
-
-  if (((bricking & BRICK_READY)==0) || (!Brick))
-    MakeBricks ( A2,l2,contDist*1.5 );
-
-  ncontacts = 0;
-
-  if (!Brick)  return;
-
-  dn = (int)floor(contDist/brick_size)+1;
-
-  if (swap)  {
-
-    for (i=0;i<l1;i++)
-      if (A1[i])  {
-        // Find brick location
-        GetBrickCoor ( A1[i],nx,ny,nz );
-        if (nx>=0)  {
-          ix1 = IMax ( 0,nx-dn );
-          iy1 = IMax ( 0,ny-dn );
-          iz1 = IMax ( 0,nz-dn );
-          ix2 = IMin ( nbrick_x,nx+dn+1 );
-          iy2 = IMin ( nbrick_y,ny+dn+1 );
-          iz2 = IMin ( nbrick_z,nz+dn+1 );
-          for (ix=ix1;ix<ix2;ix++)
-            if (Brick[ix])
-              for (iy=iy1;iy<iy2;iy++)
-                if (Brick[ix][iy])
-                  for (iz=iz1;iz<iz2;iz++)  {
-                    B = Brick[ix][iy][iz];
-                    if (B)
-                      for (j=0;j<B->nAtoms;j++)  {
-                        dx = A1[i]->x - B->Atom[j]->x;
-                        dy = A1[i]->y - B->Atom[j]->y;
-                        dz = A1[i]->z - B->Atom[j]->z;
-                        d2 = dx*dx + dy*dy + dz*dz;
-                        if (d2<=contDist2)  {
-                          contact[ncontacts].id1  = B->id[j];
-                          contact[ncontacts].id2  = i;
-                          contact[ncontacts].dist = d2;
-                          ncontacts++;
-                        }
-                      }
-                  }
-        }
-      }
-
-  } else  {
-
-    for (i=0;i<l1;i++)
-      if (A1[i])  {
-        // Find brick location
-        GetBrickCoor ( A1[i],nx,ny,nz );
-        if (nx>=0)  {
-          ix1 = IMax ( 0,nx-dn );
-          iy1 = IMax ( 0,ny-dn );
-          iz1 = IMax ( 0,nz-dn );
-          ix2 = IMin ( nbrick_x,nx+dn+1 );
-          iy2 = IMin ( nbrick_y,ny+dn+1 );
-          iz2 = IMin ( nbrick_z,nz+dn+1 );
-          for (ix=ix1;ix<ix2;ix++)
-            if (Brick[ix])
-              for (iy=iy1;iy<iy2;iy++)
-                if (Brick[ix][iy])
-                  for (iz=iz1;iz<iz2;iz++)  {
-                    B = Brick[ix][iy][iz];
-                    if (B)
-                      for (j=0;j<B->nAtoms;j++)  {
-                        dx = A1[i]->x - B->Atom[j]->x;
-                        dy = A1[i]->y - B->Atom[j]->y;
-                        dz = A1[i]->z - B->Atom[j]->z;
-                        d2 = dx*dx + dy*dy + dz*dz;
-                        if (d2<=contDist2)  {
-                          contact[ncontacts].id1  = i;
-                          contact[ncontacts].id2  = B->id[j];
-                          contact[ncontacts].dist = d2;
-                          ncontacts++;
-                        }
-                      }
-                  }
-        }
-      }
-
-  }
-
-}
-
-
-void  CMMDBCoorManager::SeekContacts ( PPCAtom     AIndex1,
-                                       int         ilen1,
-                                       PPCAtom *   AIndex2,
-                                       ivector     ilen2,
-                                       int         nStructures,
-                                       realtype    dist1,
-                                       realtype    dist2,
-                                       PPCMContact & contact,
-                                       int         bricking
-                                     )  {
-//  It is Ok to have NULL pointers in AIndex1 and AIndex2
-PCMBrick B;
-PCAtom   A;
-realtype d12,d22,d2;
-int      dn, i,j,k, nx,ny,nz, ix1,iy1,iz1, ix2,iy2,iz2;
-int      ix,iy,iz;
-
-  if (dist2<dist1)              return;
-  if ((!AIndex1) || (!AIndex2)) return;
-
-  d12 = dist1*dist1;
-  d22 = dist2*dist2;
-
-  if (((bricking & BRICK_READY)==0) || (!MBrick))
-    MakeMBricks ( AIndex2,ilen2,nStructures,dist2*1.5 );
-
-  contact = new PCMContact[ilen1];
-
-  dn = mround(dist2/brick_size)+1;
-
-  if (MBrick)
-    for (i=0;i<ilen1;i++)  {
-      A = AIndex1[i];
-      contact[i] = NULL;
-      if (A)  {
-        if (!A->Ter)  {
-          contact[i] = new CMContact(nStructures);
-          contact[i]->contactID = i;
-          //  Calculate the brick location
-          GetMBrickCoor ( A,nx,ny,nz );
-          if (nx>=0)  {
-            ix1 = IMax ( 0,nx-dn );
-            iy1 = IMax ( 0,ny-dn );
-            iz1 = IMax ( 0,nz-dn );
-            ix2 = IMin ( nmbrick_x,nx+dn+1 );
-            iy2 = IMin ( nmbrick_y,ny+dn+1 );
-            iz2 = IMin ( nmbrick_z,nz+dn+1 );
-            for (ix=ix1;ix<ix2;ix++)
-              if (MBrick[ix])
-                for (iy=iy1;iy<iy2;iy++)
-                  if (MBrick[ix][iy])
-                    for (iz=iz1;iz<iz2;iz++)  {
-                      B = MBrick[ix][iy][iz];
-                      if (B)
-                        for (j=0;j<nStructures;j++)
-                          for (k=0;k<B->nAtoms[j];k++)
-                            if (B->Atom[j][k]!=A)  {
-                              if (isContact(A,B->Atom[j][k],
-                                            MaxInt4,MinInt4,
-                                            dist2,d12,d22,d2))
-                                contact[i]->AddContact (
-                                       B->Atom[j][k],j,B->id[j][k] );
-                            }
-                    }
-          }
-        }
-      }
-    }
-  else
-    for (i=0;i<ilen1;i++)
-      contact[i] = NULL;
-
-}
-
-
-
-DefineClass(CSortContacts);
-
-class CSortContacts : public CQuickSort  {
-  public :
-    CSortContacts() : CQuickSort() {}
-    int  Compare ( int i, int j );
-    void Swap    ( int i, int j );
-    void Sort    ( PSContact contact, int ncontacts, int sortmode );
-  protected :
-    int  mode;
-};
-
-int CSortContacts::Compare ( int i, int j )  {
-Boolean gt,lt;
-  switch (mode)  {
-    default          :
-    case CNSORT_1INC : gt = (((PSContact)data)[i].id1 >
-                             ((PSContact)data)[j].id1);
-                       lt = (((PSContact)data)[i].id1 <
-                             ((PSContact)data)[j].id1);
-                   break;
-    case CNSORT_1DEC : gt = (((PSContact)data)[j].id1 >
-                             ((PSContact)data)[i].id1);
-                       lt = (((PSContact)data)[j].id1 <
-                             ((PSContact)data)[i].id1);
-                   break;
-    case CNSORT_2INC : gt = (((PSContact)data)[i].id2 >
-                             ((PSContact)data)[j].id2);
-                       lt = (((PSContact)data)[i].id2 <
-                             ((PSContact)data)[j].id2);
-                   break;
-    case CNSORT_2DEC : gt = (((PSContact)data)[j].id2 >
-                             ((PSContact)data)[i].id2);
-                       lt = (((PSContact)data)[j].id2 <
-                             ((PSContact)data)[i].id2);
-                   break;
-    case CNSORT_DINC : gt = (((PSContact)data)[i].dist >
-                             ((PSContact)data)[j].dist);
-                       lt = (((PSContact)data)[i].dist <
-                             ((PSContact)data)[j].dist);
-                   break;
-    case CNSORT_DDEC : gt = (((PSContact)data)[j].dist >
-                             ((PSContact)data)[i].dist);
-                       lt = (((PSContact)data)[j].dist <
-                             ((PSContact)data)[i].dist);
-                   break;
-  }
-  if (gt)  return  1;
-  if (lt)  return -1;
-  return 0;
-}
-
-void CSortContacts::Swap ( int i, int j )  {
-  ((PSContact)data)[i].Swap ( ((PSContact)data)[j] );
-}
-
-
-void CSortContacts::Sort ( PSContact contact, int ncontacts,
-                           int sortmode )  {
-  mode = sortmode;
-  if (mode!=CNSORT_OFF)
-    CQuickSort::Sort ( &(contact[0]),ncontacts );
-}
-
-
-void  SortContacts ( PSContact contact, int ncontacts,
-                     int sortmode )  {
-CSortContacts SC;
-  if (sortmode!=CNSORT_OFF)
-    SC.Sort ( contact,ncontacts,sortmode );
-}
-
-
-//  -------------------  Stream functions  ----------------------
-
-void  CMMDBCoorManager::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version    );
-  CMMDBFile::write ( f );
-  f.WriteInt  ( &CoorIDCode );
-  f.WriteReal ( &brick_size );
-  f.WriteReal ( &xbrick_0   );
-  f.WriteReal ( &ybrick_0   );
-  f.WriteReal ( &zbrick_0   );
-  f.WriteInt  ( &nbrick_x   );
-  f.WriteInt  ( &nbrick_y   );
-  f.WriteInt  ( &nbrick_z   );
-}
-
-void  CMMDBCoorManager::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version    );
-  CMMDBFile::read ( f );
-  f.ReadInt  ( &CoorIDCode );
-  f.ReadReal ( &brick_size );
-  f.ReadReal ( &xbrick_0   );
-  f.ReadReal ( &ybrick_0   );
-  f.ReadReal ( &zbrick_0   );
-  f.ReadInt  ( &nbrick_x   );
-  f.ReadInt  ( &nbrick_y   );
-  f.ReadInt  ( &nbrick_z   );
-}
-
-
-MakeStreamFunctions(CMMDBCoorManager);
-
-
-
-
-// ===================================================================
-
-int  SuperposeAtoms ( mat44 & T, PPCAtom A1, int nA, PPCAtom A2,
-                      ivector C )  {
-realtype xc1,yc1,zc1, xc2,yc2,zc2, det,B;
-rmatrix  A,U,V;
-rvector  W,RV1;
-vect3    vc1,vc2;
-int      i,j,k,i1,i2,nat;
-
-
-  //  1. Set unit matrix as "default" return
-
-  for (i=0;i<4;i++)  {
-    for (j=0;j<4;j++)
-      T[i][j] = 0.0;
-    T[i][i] = 1.0;
-  }
-
-
-  //  2. Calculate mass centers
-
-  xc1 = 0.0;
-  yc1 = 0.0;
-  zc1 = 0.0;
-  xc2 = 0.0;
-  yc2 = 0.0;
-  zc2 = 0.0;
-
-  nat = 0;
-  if (C)  {
-
-    for (i1=0;i1<nA;i1++)
-      if (!A1[i1]->Ter)  {
-        i2 = C[i1];
-        if (i2>=0)  {
-          xc1 += A1[i1]->x;
-          yc1 += A1[i1]->y;
-          zc1 += A1[i1]->z;
-          xc2 += A2[i2]->x;
-          yc2 += A2[i2]->y;
-          zc2 += A2[i2]->z;
-          nat++;
-        }
-      }
-
-  } else  {
-
-    for (i=0;i<nA;i++)
-      if ((!A1[i]->Ter) && (!A2[i]->Ter))  {
-        xc1 += A1[i]->x;
-        yc1 += A1[i]->y;
-        zc1 += A1[i]->z;
-        xc2 += A2[i]->x;
-        yc2 += A2[i]->y;
-        zc2 += A2[i]->z;
-        nat++;
-      }
-
-  }
-
-  if (nat>1)  {
-    xc1 /= nat;
-    yc1 /= nat;
-    zc1 /= nat;
-    xc2 /= nat;
-    yc2 /= nat;
-    zc2 /= nat;
-  } else if (nat>0)  {
-    T[0][3] = xc2 - xc1;
-    T[1][3] = yc2 - yc1;
-    T[2][3] = zc2 - zc1;
-    return SPOSEAT_Ok;
-  } else
-    return SPOSEAT_NoAtoms;
-
-
-  //  3.  Calculate the correlation matrix
-
-  GetMatrixMemory ( A,3,3,1,1 );
-
-  for (i=1;i<=3;i++)
-    for (j=1;j<=3;j++)
-      A[i][j] = 0.0;
-
-  if (C)  {
-
-    for (i1=0;i1<nA;i1++)
-      if (!A1[i1]->Ter)  {
-        i2 = C[i1];
-        if (i2>=0)  {
-          vc1[0] = A1[i1]->x - xc1;
-          vc1[1] = A1[i1]->y - yc1;
-          vc1[2] = A1[i1]->z - zc1;
-          vc2[0] = A2[i2]->x - xc2;
-          vc2[1] = A2[i2]->y - yc2;
-          vc2[2] = A2[i2]->z - zc2;
-          for (i=1;i<=3;i++)
-            for (j=1;j<=3;j++)
-              A[i][j] += vc1[j-1]*vc2[i-1];
-        }
-      }
-
-  } else  {
-
-    for (k=0;k<nA;k++)
-      if ((!A1[k]->Ter) && (!A2[k]->Ter))  {
-        vc1[0] = A1[k]->x - xc1;
-        vc1[1] = A1[k]->y - yc1;
-        vc1[2] = A1[k]->z - zc1;
-        vc2[0] = A2[k]->x - xc2;
-        vc2[1] = A2[k]->y - yc2;
-        vc2[2] = A2[k]->z - zc2;
-        for (i=1;i<=3;i++)
-          for (j=1;j<=3;j++)
-            A[i][j] += vc1[j-1]*vc2[i-1];
-      }
-
-  }
-
-
-  //  4. Calculate transformation matrix (to be applied to A1)
-
-  det = A[1][1]*A[2][2]*A[3][3] +
-        A[1][2]*A[2][3]*A[3][1] +
-        A[2][1]*A[3][2]*A[1][3] -
-        A[1][3]*A[2][2]*A[3][1] -
-        A[1][1]*A[2][3]*A[3][2] -
-        A[3][3]*A[1][2]*A[2][1];
-
-  //  4.1 SV-decompose the correlation matrix
-
-  GetMatrixMemory ( U  ,3,3,1,1 );
-  GetMatrixMemory ( V  ,3,3,1,1 );
-  GetVectorMemory ( W  ,3,1 );
-  GetVectorMemory ( RV1,3,1 );
-
-  SVD ( 3,3,3,A,U,V,W,RV1,True,True,i );
-
-  if (i!=0)  {
-    FreeVectorMemory ( RV1,1 );
-    FreeVectorMemory ( W  ,1 );
-    FreeMatrixMemory ( V  ,3,1,1 );
-    FreeMatrixMemory ( U  ,3,1,1 );
-    FreeMatrixMemory ( A  ,3,1,1 );
-    return SPOSEAT_SVD_Fail;
-  }
-
-  //  4.2 Check for parasite inversion and fix it if found
-
-  if (det<=0.0)  {
-    k = 0;
-    B = MaxReal;
-    for (j=1;j<=3;j++)
-      if (W[j]<B)  {
-        B = W[j];
-        k = j;
-      }
-    for (j=1;j<=3;j++)
-      V[j][k] = -V[j][k];
-  }
-
-  //  4.3 Calculate rotational part of T
-
-  for (j=1;j<=3;j++)
-    for (k=1;k<=3;k++)  {
-      B = 0.0;
-      for (i=1;i<=3;i++)
-        B += U[j][i]*V[k][i];
-      T[j-1][k-1] = B;
-    }
-
-
-  //  4.4 Add translational part to T
-
-  T[0][3] = xc2 - T[0][0]*xc1 - T[0][1]*yc1 - T[0][2]*zc1;
-  T[1][3] = yc2 - T[1][0]*xc1 - T[1][1]*yc1 - T[1][2]*zc1;
-  T[2][3] = zc2 - T[2][0]*xc1 - T[2][1]*yc1 - T[2][2]*zc1;
-
-
-  //  5. Release memory and quit
-
-  FreeVectorMemory ( RV1,1 );
-  FreeVectorMemory ( W  ,1 );
-  FreeMatrixMemory ( V  ,3,1,1 );
-  FreeMatrixMemory ( U  ,3,1,1 );
-  FreeMatrixMemory ( A  ,3,1,1 );
-
-  return SPOSEAT_Ok;
-
-}
-
-realtype getPhi ( PPCAtom A )  {
-//
-//   A0    A1    A2    A3
-//   o-----o-----o-----o
-//            |
-//           Phi
-//
-//  -Pi <= Phi <= +Pi
-//
-vect3    U,W,V, a,b,c;
-realtype Wmag,S,T;
-
-  U[0] = A[0]->x - A[1]->x;
-  U[1] = A[0]->y - A[1]->y;
-  U[2] = A[0]->z - A[1]->z;
-
-  W[0] = A[2]->x - A[1]->x;
-  W[1] = A[2]->y - A[1]->y;
-  W[2] = A[2]->z - A[1]->z;
-
-  V[0] = A[3]->x - A[2]->x;
-  V[1] = A[3]->y - A[2]->y;
-  V[2] = A[3]->z - A[2]->z;
-
-  a[0] = U[1]*W[2] - W[1]*U[2];
-  a[1] = U[2]*W[0] - W[2]*U[0];
-  a[2] = U[0]*W[1] - W[0]*U[1];
-
-  b[0] = V[1]*W[2] - W[1]*V[2];
-  b[1] = V[2]*W[0] - W[2]*V[0];
-  b[2] = V[0]*W[1] - W[0]*V[1];
-
-  c[0] = a[1]*b[2] - b[1]*a[2];
-  c[1] = a[2]*b[0] - b[2]*a[0];
-  c[2] = a[0]*b[1] - b[0]*a[1];
-
-  Wmag = sqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]);
-
-  S    = c[0]*W[0] + c[1]*W[1] + c[2]*W[2];
-  T    = a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
-  T   *= Wmag;
-
-  if ((S==0.0) && (T==0.0))  return NO_TORSION;
-                       else  return atan2(S,T);
-
-}
-
-realtype getPsi ( PPCAtom A )  {
-vect3    v1,v2;
-realtype l1,l2;
-
-  v1[0] = A[0]->x - A[1]->x;
-  v1[1] = A[0]->y - A[1]->y;
-  v1[2] = A[0]->z - A[1]->z;
-
-  v2[0] = A[2]->x - A[1]->x;
-  v2[1] = A[2]->y - A[1]->y;
-  v2[2] = A[2]->z - A[1]->z;
-
-  l1 = v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2];
-  if (l1==0.0)  l1 = 1.0;
-  l2 = v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2];
-  if (l2==0.0)  l2 = 1.0;
-
-  return  acos((v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])/sqrt(l1*l2));
-
-}
-
diff --git a/mmdb/mmdb_coormngr.h b/mmdb/mmdb_coormngr.h
deleted file mode 100755
index 3d95d35..0000000
--- a/mmdb/mmdb_coormngr.h
+++ /dev/null
@@ -1,951 +0,0 @@
-//  $Id: mmdb_coormngr.h,v 1.29 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_coormngr <interface>
-//       ~~~~~~~~~
-//       Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CBrick           ( space brick                  )
-//       ~~~~~~~~~  CMMDBCoorManager ( MMDB atom coordinate manager )
-//
-//  (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_CoorMngr__
-#define __MMDB_CoorMngr__
-
-#ifndef  __MMDB_File__
-#include "mmdb_file.h"
-#endif
-
-
-
-// ===========================  CBrick  ==============================
-
-//  bricking control
-#define BRICK_ON_1       0x00000001
-#define BRICK_ON_2       0x00000002
-#define BRICK_READY      0x00000004
-
-
-DefineClass(CBrick);
-typedef  PPCBrick * PPPCBrick;
-
-class CBrick  {
-
-  public :
-    int     nAtoms;  // number of atoms hit into brick
-    PPCAtom   Atom;  // pointers to atoms
-    ivector     id;  // atom ids (in present realization, these are
-                     // indices of atoms from the bricked array)
-
-    CBrick ();
-    ~CBrick();
-
-    void  Clear   ();
-    void  AddAtom ( PCAtom A, int atomid );
-
-  protected :
-    int  nAllocAtoms;
-    void InitBrick();
-
-};
-
-
-// ===========================  CMBrick  =============================
-
-//  Bricking multiple structures
-
-DefineClass(CMBrick);
-typedef  PPCMBrick * PPPCMBrick;
-
-class CMBrick  {
-
-  public :
-    ivector  nAtoms;  // number of atoms in the brick
-    PPCAtom  * Atom;  // pointers to atoms
-    imatrix      id;  // atom ids (in present realization, these are
-                      // indices of atoms from the bricked array)
-
-    CMBrick ( int nStructures );
-    ~CMBrick();
-
-    void  Clear   ();
-    void  AddAtom ( PCAtom A, int structNo, int atomid );
-
-  protected :
-    ivector  nAllocAtoms;
-    int      nStruct;
-    void InitMBrick ( int nStructures );
-
-};
-
-
-
-//  ====================  CGenSym  ========================
-
-DefineClass(CGenSym);
-DefineStreamFunctions(CGenSym);
-
-class CGenSym : public CSymOps  {
-
-  friend class CMMDBCoorManager;
-
-  public :
-
-    CGenSym ();
-    CGenSym ( RPCStream Object );
-    ~CGenSym();
-
-    void FreeMemory();
-
-    int  AddSymOp    ( cpstr XYZOperation );
-    //  the number of just added operation may be obtained as
-    //  Nop = CGenSym::GetNofSymOps()-1 .
-
-    int  AddRenChain ( int Nop, const ChainID ch1, const ChainID ch2 );
-
-    void Copy  ( PCSymOps GenSym );
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected :
-
-    PChainID * chID1;   // pairs of chains to rename from chID1[n][i]
-    PChainID * chID2;   // to chID2[n][i] for each operation n<Nops
-    ivector    nChains; // number of chains to rename for each oper-n
-
-    void InitGenSym();
-
-  private :
-    int        nOpAlloc;  // number of allocated operations
-
-};
-
-
-// =========================  SContact  =============================
-
-DefineStructure(SContact);
-
-struct SContact  {
-  int      id1,id2;
-  long     group;
-  realtype dist;
-  void Copy ( RSContact c );
-  void Swap ( RSContact c );
-};
-
-
-// ========================  CMContact  =============================
-
-DefineClass(CMContact);
-
-class CMContact : public CStream  {
-
-  public :
-    int       nStruct,contactID;
-    ivector   nAtoms;
-    PPCAtom * Atom;
-    imatrix   id;
-
-    CMContact ( int nStructures  );
-    ~CMContact();
-
-    void    AddContact ( PCAtom A, int structNo, int atomid );
-
-  protected:
-    ivector nAlloc;
-
-};
-
-extern void DeleteMContacts ( PPCMContact & mcontact, int nContacts );
-
-
-// ======================  CMMDBCoorManager  =========================
-
-DefineClass(CMMDBCoorManager);
-DefineStreamFunctions(CMMDBCoorManager);
-
-//  ----  Atom extraction return codes
-#define CID_Ok          0
-#define CID_NoModel     1
-#define CID_NoChain     2
-#define CID_NoResidue   3
-#define CID_NoAtom      4
-#define CID_WrongPath   5
-
-//  ----  generate symmetry mates return codes
-#define GSM_Ok                0
-#define GSM_NoSymOps          1
-#define GSM_NoTransfMatrices  2
-#define GSM_NoCell            3
-
-class CMMDBCoorManager : public CMMDBFile  {
-
-  public :
-
-    int CoorIDCode; // last return from atom extraction procedure
-
-    CMMDBCoorManager ();
-    CMMDBCoorManager ( RPCStream Object );
-    ~CMMDBCoorManager();
-
-
-    //  ----------------------------------------------------------
-
-    int  SetDefaultCoorID ( cpstr CID );
-
-
-    //  ----------------  Bricking  ------------------------------
-
-    void  RemoveBricks ();
-    Boolean areBricks  () { return (Brick!=NULL); }
-    void  MakeBricks   ( PPCAtom atmvec, int avlen, 
-                         realtype Margin, realtype BrickSize=6.0 );
-    void  GetBrickDimension ( 
-                         int & nxmax, int & nymax, int & nzmax );
-    void  GetBrickCoor ( PCAtom A, int & nx, int & ny, int & nz );
-    void  GetBrickCoor ( realtype x, realtype y, realtype z,
-                         int & nx, int & ny, int & nz );
-    PCBrick GetBrick   ( int   nx, int   ny, int   nz );
-
-    void  RemoveMBricks ();
-    Boolean areMBricks  () { return (MBrick!=NULL); }
-    void  MakeMBricks   ( PPCAtom * atmvec, ivector avlen,
-                          int nStructures, realtype Margin,
-                          realtype BrickSize=6.0 );
-    void  GetMBrickDimension ( 
-                         int & nxmax, int & nymax, int & nzmax );
-    void  GetMBrickCoor ( PCAtom A, int & nx, int & ny, int & nz );
-    void  GetMBrickCoor ( realtype x, realtype y, realtype z,
-                          int & nx, int & ny, int & nz );
-    PCMBrick GetMBrick  ( int   nx, int   ny, int   nz );
-
-    //  ----------------  Extracting models  ---------------------
-
-    int GetNumberOfModels ()  { return nModels; }
-    int  GetFirstModelNum ();
-    PCModel GetFirstDefinedModel();
-    PCModel      GetModel ( int   modelNo  );  // 1<=modelNo<=nModels
-    PCModel      GetModel ( cpstr CID );
-    void    GetModelTable ( PPCModel & modTable,
-                            int & NumberOfModels );
-
-    //  ----------------  Deleting models  -----------------------
-
-    int  DeleteModel ( cpstr CID );
-    int  DeleteModel ( int modelNo );  // 1<=modelNo<=nOfModels
-
-    //  ----------------  Adding/Inserting models  ---------------
-
-    int  AddModel     ( PCModel model );
-    int  InsModel     ( PCModel model, int modelNo );
-    void RotateModels ( int  modelNo1, int modelNo2, int rotdir );
-    void SwapModels   ( int  modelNo1, int modelNo2 );
-
-    //  ----------------  Extracting chains  ---------------------
-
-    int GetNumberOfChains ( int   modelNo  );
-    int GetNumberOfChains ( cpstr CID );
-    PCChain      GetChain ( int modelNo, const ChainID chainID );
-    PCChain      GetChain ( int modelNo, int   chainNo );
-    PCChain      GetChain ( cpstr CID );
-    void    GetChainTable ( int modelNo, PPCChain & chainTable,
-                            int & NumberOfChains );
-    void    GetChainTable ( cpstr CID, PPCChain & chainTable,
-                            int & NumberOfChains );
-
-    //  -----------------  Deleting chains  ----------------------
-
-    int  DeleteChain     ( int modelNo, const ChainID chID );
-    int  DeleteChain     ( int modelNo, int chainNo  );
-    int  DeleteAllChains ( int modelNo );
-    int  DeleteAllChains ();
-
-    //  ------------------  Adding chains  -----------------------
-
-    int  AddChain ( int modelNo, PCChain chain );
-
-    //  ----------------  Extracting residues  -------------------
-
-    int GetNumberOfResidues ( int modelNo, const ChainID chainID );
-    int GetNumberOfResidues ( int modelNo, int   chainNo );
-    int GetNumberOfResidues ( cpstr CID );
-    PCResidue    GetResidue ( int modelNo, const ChainID chainID,
-                              int seqNo,   const InsCode insCode );
-    PCResidue    GetResidue ( int modelNo, int   chainNo,
-                              int seqNo,   const InsCode insCode );
-    PCResidue    GetResidue ( int modelNo, const ChainID chainID,
-                                                     int resNo );
-    PCResidue    GetResidue ( int modelNo, int   chainNo, int resNo );
-    PCResidue    GetResidue ( cpstr CID );
-    int        GetResidueNo ( int modelNo, const ChainID chainID,
-                              int seqNo,   const InsCode insCode );
-    int        GetResidueNo ( int modelNo, int   chainNo,
-                              int seqNo,   const InsCode insCode );
-    void    GetResidueTable ( PPCResidue & resTable,
-                              int & NumberOfResidues );
-    void    GetResidueTable ( int modelNo, const ChainID chainID,
-                              PPCResidue & resTable,
-                              int & NumberOfResidues );
-    void    GetResidueTable ( int modelNo, int chainNo,
-                              PPCResidue & resTable,
-                              int & NumberOfResidues );
-    void    GetResidueTable ( cpstr CID, PPCResidue & resTable,
-                              int & NumberOfResidues );
-
-
-    //  -----------------  Deleting residues  -----------------------
-
-    int DeleteResidue     ( int modelNo, const ChainID chainID,
-                            int seqNo,   const InsCode insCode );
-    int DeleteResidue     ( int modelNo, const ChainID chainID,
-                                                   int resNo );
-    int DeleteResidue     ( int modelNo, int   chainNo,
-                            int seqNo,   const InsCode insCode );
-    int DeleteResidue     ( int modelNo, int   chainNo, int resNo );
-    int DeleteAllResidues ( int modelNo, const ChainID chainID );
-    int DeleteAllResidues ( int modelNo, int   chainNo );
-    int DeleteAllResidues ( int modelNo );
-    int DeleteAllResidues ();
-    int DeleteSolvent     ();
-
-    //  -------------------  Adding residues  -----------------------
-
-    int AddResidue ( int modelNo, const ChainID chainID,
-                                                 PCResidue res );
-    int AddResidue ( int modelNo, int   chainNo, PCResidue res );
-
-    // --------------------  Extracting atoms  ----------------------
-
-    int   GetNumberOfAtoms ()  { return nAtoms;  }
-    int   GetNumberOfAtoms ( int modelNo, const ChainID chainID,
-                             int seqNo,   const InsCode insCode );
-    int   GetNumberOfAtoms ( int modelNo, int   chainNo,
-                             int seqNo,   const InsCode insCode );
-    int   GetNumberOfAtoms ( int modelNo, const ChainID chainID,
-                                                    int resNo );
-    int   GetNumberOfAtoms ( int modelNo, int   chainNo, int resNo );
-    int   GetNumberOfAtoms ( cpstr CID );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              const ChainID  chID,    // chain ID
-              int            seqNo,   // residue sequence number
-              const InsCode  insCode, // residue insertion code
-              const AtomName aname,   // atom name
-              const Element  elmnt,   // chemical element code or '*'
-              const AltLoc   aloc     // alternate location indicator
-                   );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              const ChainID  chID,    // chain ID
-              int            seqNo,   // residue sequence number
-              const InsCode  insCode, // residue insertion code
-              int            atomNo   // atom number 0..
-                   );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              const ChainID  chID,    // chain ID
-              int            resNo,   // residue number 0..
-              const AtomName aname,   // atom name
-              const Element  elmnt,   // chemical element code or '*'
-              const AltLoc   aloc     // alternate location indicator
-                   );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              const ChainID  chID,    // chain ID
-              int            resNo,   // residue number 0..
-              int            atomNo   // atom number 0..
-                   );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              int            chNo,    // chain number 0..
-              int            seqNo,   // residue sequence number
-              const InsCode  insCode, // residue insertion code
-              const AtomName aname,   // atom name
-              const Element  elmnt,   // chemical element code or '*'
-              const AltLoc   aloc     // alternate location indicator
-                   );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              int            chNo,    // chain number 0...
-              int            seqNo,   // residue sequence number
-              const InsCode  insCode, // residue insertion code
-              int            atomNo   // atom number 0...
-                   );
-
-    PCAtom GetAtom (
-              int            modelNo, // model serial number 1...
-              int            chNo,    // chain number 0...
-              int            resNo,   // residue number 0...
-              const AtomName aname,   // atom name
-              const Element  elmnt,   // chemical element code or '*'
-              const AltLoc   aloc     // alternate location indicator
-                   );
-
-    PCAtom GetAtom (
-              int      modelNo, // model serial number 1...
-              int      chNo,    // chain number 0...
-              int      resNo,   // residue number 0...
-              int      atomNo   // atom number 0...
-                   );
-
-
-    //   GetAtom(CID) returns atom answering to the following
-    // CID pattern:
-    //   /mdl/chn/seq(res).i/atm[elm]:a
-    // where
-    //   mdl   - model number (mandatory); at least model #1 is always
-    //           present
-    //   chn   - chain identifier ( mandatory)
-    //   seq   - residue sequence number (mandatory)
-    //   (res) - residue name in round brackets (may be omitted)
-    //   .i    - insert code after a dot; if '.i' or 'i' is missing
-    //           then residue without an insertion code is looked
-    //           for
-    //   atm   - atom name (mandatory)
-    //   [elm] - chemical element code in square brackets; it may
-    //           be omitted but could be helpful for e.g.
-    //           distinguishing C_alpha and CA
-    //   :a    - alternate location indicator after colon; if
-    //           ':a' or 'a' is missing then an atom without
-    //           alternate location indicator is looked for.
-    // All spaces are ignored, all identifiers should be in capital
-    // letters (comparisons are case-sensitive).
-    PCAtom GetAtom ( cpstr CID );
-
-
-    void GetAtomTable ( PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int modelNo, const ChainID chainID,
-                        int seqNo,   const InsCode insCode,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int modelNo, int   chainNo,
-                        int seqNo,   const InsCode insCode,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int modelNo, const ChainID chainID, int resNo,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int modelNo, int     chainNo, int resNo,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( cpstr CID, PPCAtom & atomTable,
-                        int & NumberOfAtoms );
-
-
-    //   GetAtomTable1(..) returns atom table without TER atoms and
-    // without NULL atom pointers. NumberOfAtoms returns the actual
-    // number of atom pointers in atomTable.
-    //   atomTable is allocated within the function. If it was
-    // not set to NULL before calling the function, the function will
-    // attempt to deallocate it first.
-    //   The application is responsible for deleting atomTable,
-    // however it must not touch atom pointers, i.e. use simply
-    // "delete atomTable;". Never pass atomTable from GetAtomTable(..)
-    // into this function, unless you set it to NULL before doing that.
-    void GetAtomTable1 ( PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int modelNo, const ChainID chainID,
-                         int seqNo,   const InsCode insCode,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int modelNo, int   chainNo,
-                         int seqNo,   const InsCode insCode,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int modelNo, const ChainID chainID, int resNo,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int modelNo, int     chainNo, int resNo,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( cpstr CID, PPCAtom & atomTable,
-                         int & NumberOfAtoms );
-
-
-    //  --------------------  Deleting atoms  -----------------------
-
-    int DeleteAtom ( int            modelNo,
-                     const ChainID  chID,
-                     int            seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int           modelNo,
-                     const ChainID chID,
-                     int           seqNo,
-                     const InsCode insCode,
-                     int           atomNo );
-    int DeleteAtom ( int            modelNo,
-                     const ChainID  chID,
-                     int            resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int modelNo, const ChainID chID,
-                     int resNo, int atomNo );
-    int DeleteAtom ( int modelNo, int chNo, int seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int modelNo, int chNo, int seqNo,
-                     const InsCode insCode, int atomNo );
-    int DeleteAtom ( int modelNo, int chNo, int resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int modelNo, int chNo, int resNo, int atomNo );
-
-    int DeleteAllAtoms ( int modelNo, const ChainID chID,
-                         int seqNo,   const InsCode insCode );
-    int DeleteAllAtoms ( int modelNo, const ChainID chID, int resNo );
-    int DeleteAllAtoms ( int modelNo, const ChainID chID );
-    int DeleteAllAtoms ( int modelNo, int chNo, int seqNo,
-                         const InsCode insCode );
-    int DeleteAllAtoms ( int modelNo, int chNo, int resNo );
-    int DeleteAllAtoms ( int modelNo, int chNo );
-    int DeleteAllAtoms ( int modelNo );
-    int DeleteAllAtoms ();
-
-    //  This function leaves only alternative location with maximal
-    // occupancy, if those are equal or unspecified, the one with
-    // "least" alternative location indicator.
-    //  The function returns the number of deleted atoms and optimizes
-    // the atom index.
-    int DeleteAltLocs  ();
-
-
-    //  ---------------------  Adding atoms  ------------------------
-
-    int AddAtom ( int modelNo, const ChainID chID,
-                  int seqNo,   const InsCode insCode, PCAtom atom );
-    int AddAtom ( int modelNo, const ChainID chID, int resNo,
-                                                      PCAtom atom );
-    int AddAtom ( int modelNo, int chNo, int seqNo,
-                               const InsCode insCode, PCAtom atom );
-    int AddAtom ( int modelNo, int chNo, int resNo, PCAtom  atom );
-
-
-    // --------------------  Transformations  -----------------------
-
-    int  GenerateSymMates ( PCGenSym GenSym=NULL );
-                             // 1: no Sym operations,
-                             // 2: no fract/orth matrices
-                             // 3: no cell parameters
-                             // 0: Ok
-
-    void ApplyTransform   ( mat44 & TMatrix ); // simply transforms all
-                                          // coordinates by multiplying
-                                          // with matrix TMatrix
-
-    int  BringToUnitCell();  // brings all chains into 0th unit cell
-
-    //   Frac2Orth(..) and Orth2Frac(..) transform between fractional
-    // and orthogonal coordinates, if areMatrices() returns True.
-    // If the transformation matrices were not set, the functions just
-    // copy the coordinates.  Returns True if the transformation was
-    // done; False return means that transformation matrices were not
-    // calculated
-    Boolean Frac2Orth (
-              realtype   xfrac, realtype   yfrac, realtype   zfrac,
-              realtype & xorth, realtype & yorth, realtype & zorth );
-    Boolean Orth2Frac (
-              realtype   xorth, realtype   yorth, realtype   zorth,
-              realtype & xfrac, realtype & yfrac, realtype & zfrac );
-
-
-    //   Below, F and T are transformation matrices in fractional and
-    // orthogonal coordinates, respectively.
-    Boolean Frac2Orth ( mat44 & F, mat44 & T );
-    Boolean Orth2Frac ( mat44 & T, mat44 & F );
-
-    // ====================  Seeking contacts  ======================
-
-    void  SeekContacts (
-             PPCAtom    AIndex,    // index of atoms [0..ilen-1]
-             int        ilen,      // length of index
-             int        atomNum,   // number of 1st contact atom
-                                   // in the index. All other atoms
-                                   // are checked for contact with
-                                   // 1st atom
-             realtype   dist1,     // minimal contact distance
-             realtype   dist2,     // maximal contact distance
-             int        seqDist,   // the sequence distance to neglect.
-                                   // If seqDist==0, all atoms are
-                                   // checked for contact. If
-                                   // seqDist==1, the atoms belonging
-                                   // to the same residue as atom
-                                   // AIndex[atomNum], are neglected.
-                                   // If seqDist>1, all atoms belonging
-                                   // to residues closer than
-                                   // +/-(seqDist-1) around that of 
-                                   // atom AIndex[atomNum], are
-                                   // neglected. If chain is broken
-                                   // (has a gap) on section
-                                   // [-(seqDist-1)..seqDist-1], the
-                                   // section of neglection is
-                                   // shortened to that gap.
-             RPSContact contact,   // indices of contacting atoms
-                                   // [0..ncontacts-1]. contact[i].id1
-                                   // is set to atomNum and
-                                   // contact[i].id2 is set to the
-                                   // index of 2nd contacting atom
-                                   // in vector AIndex
-             int &      ncontacts, // number of contacts found. If
-                                   // ncontacts>0 on input, it is
-                                   // assumed that new contacts that
-                                   // newly found contacts should be
-                                   // appended to those already
-                                   // existing
-             int        maxlen=0,  // if <=0, then vector contact is
-                                   // allocated dynamically. If
-                                   // contact!=NULL, then it is
-                                   // appended with new contacts.
-                                   // The application is responsible
-                                   // for deallocation of contact
-                                   // after use.
-                                   //   If maxlen>0 then vector contact
-                                   // is prohibited of dynamical
-                                   // allocation/deallocation. In this
-                                   // case, not more than maxlen
-                                   // contacts will be returned.
-             long       group=0    // a contact group ID, which will be
-                                   // simply stored in contact[i].group
-                                   // fields. This ID may be useful
-                                   // if contacts are obtained in
-                                   // multiple calls of the function
-                       );
-
-    void  SeekContacts (
-             PCAtom     A,         // 1st atom in contact
-             PPCAtom    AIndex,    // index of atoms [0..ilen-1] to
-                                   // check for contact with 1st atom
-             int        ilen,      // length of index
-             realtype   dist1,     // minimal contact distance
-             realtype   dist2,     // maximal contact distance
-             int        seqDist,   // the sequence distance to neglect.
-                                   // If seqDist==0, all atoms are
-                                   // checked for contact. If
-                                   // seqDist==1, the atoms belonging
-                                   // to the same residue as atom
-                                   // A, are neglected. If seqDist>1,
-                                   // all atoms belonging to residues
-                                   // closer than +/-(seqDist-1) around
-                                   // that of atom A, are neglected. If
-                                   // chain is broken (has a gap) on
-                                   // section
-                                   // [-(seqDist-1)..seqDist-1], the
-                                   // section of neglection is
-                                   // shortened to that gap.
-             RPSContact contact,   // indices of contacting atoms
-                                   // [0..ncontacts-1]. contact[i].id1
-                                   // is set to -1, and contact[i].id2
-                                   // is set to the index of 2nd
-                                   // contacting atom in vector AIndex
-             int &      ncontacts, // number of contacts found. If
-                                   // ncontacts>0 on input, it is
-                                   // assumed that new contacts that
-                                   // newly found contacts should be
-                                   // appended those already existing
-             int        maxlen=0,  // if <=0, then vector contact is
-                                   // allocated dynamically. If
-                                   // contact!=NULL, then it is
-                                   // appended with new contacts.
-                                   // The application is responsible
-                                   // for deallocation of contact
-                                   // after use.
-                                   //   If maxlen>0 then vector contact
-                                   // is prohibited of dynamical
-                                   // allocation/deallocation. In this
-                                   // case, not more than maxlen
-                                   // contacts will be returned.
-             long       group=0    // a contact group ID, which will be
-                                   // simply stored in contact[i].group
-                                   // fields. This ID may be useful
-                                   // if contacts are obtained in
-                                   // multiple calls of the function
-                       );
-
-    void  SeekContacts (
-             PPCAtom    AIndex1,   //  1st atom index [0..ilen1-1]
-             int        ilen1,     //  length of 1st index
-             PPCAtom    AIndex2,   //  2nd atom index [0..ilen2-1] to
-                                   // check for contact with 1st index
-             int        ilen2,     //  length of 2nd index
-             realtype   dist1,     //  minimal contact distance
-             realtype   dist2,     //  maximal contact distance
-             int        seqDist,   //  the sequence distance to
-                                   // neglect.
-                                   //  If seqDist==0, all atoms are
-                                   // checked for contact.
-                                   //  If seqDist==1, the atoms
-                                   // belonging to the same residue
-                                   // are neglected.
-                                   //  If seqDist>1, all atoms
-                                   // belonging to residues closer than
-                                   // +/-(seqDist-1) to each other,
-                                   // are neglected. If chain is broken
-                                   // (has a gap) on section
-                                   // [-(seqDist-1)..seqDist-1], the
-                                   // section of neglection is
-                                   // shortened to that gap.
-             RPSContact contact,   //  indices of contacting atoms
-                                   // [0..ncontacts-1]. contact[i].id1
-                                   // contains number of atom from 1st
-                                   // index, and contact[i].id2
-                                   // contains number of atom from 2nd
-                                   // index, contacting with the former
-                                   // one
-             int &      ncontacts, //  number of contacts found. If
-                                   // ncontacts>0 on input, it is
-                                   // assumed that newly found
-                                   // contacts should be appended to
-                                   // those already existing
-             int        maxlen=0,  //  if <=0, then vector contact is
-                                   // allocated dynamically. If
-                                   // contact!=NULL, then it is
-                                   // appended with new contacts.
-                                   // The application is responsible
-                                   // for deallocation of contact
-                                   // after use.
-                                   //   If maxlen>0 then vector contact
-                                   // is prohibited of dynamical
-                                   // allocation/deallocation. In this
-                                   // case, not more than maxlen
-                                   // contacts will be returned.
-             mat44 * TMatrix=NULL, //  transformation matrix for 2nd
-                                   // set of atoms (AIndex2)
-             long       group=0,   //  a contact group ID, which will
-                                   // be stored in contact[i].group
-                                   // fields. This ID may be useful
-                                   // if contacts are obtained in
-                                   // multiple calls of the function
-             int     bricking=0,   //  bricking control; may be a
-                                   // combination of BRICK_ON_1 or
-                                   // BRICK_ON_2 with BRICK_READY
-             Boolean doSqrt=True   // if False, then SContact contains
-                                   // square distances
-                       );
-
-    //  Simplified optimized for speed version:
-    //    - no NULL pointers and Ters in AIndex1 and AIndex2
-    //    - no checks for identity atoms in AIndex1 and AIndex2
-    //    - contact must be pre-allocated with at least ilen1*ilen2
-    //      elements
-    //    - contact returns square distances
-    //    - ncontacts is always reset
-    void  SeekContacts (
-             PPCAtom    AIndex1,   //  1st atom index [0..ilen1-1]
-             int        ilen1,     //  length of 1st index
-             PPCAtom    AIndex2,   //  2nd atom index [0..ilen2-1] to
-                                   // check for contact with 1st index
-             int        ilen2,     //  length of 2nd index
-             realtype   contDist,  //  maximal contact distance
-             PSContact  contact,   //  indices of contacting atoms
-                                   // [0..ncontacts-1]. contact[i].id1
-                                   // contains number of atom from 1st
-                                   // index, and contact[i].id2
-                                   // contains number of atom from 2nd
-                                   // index, contacting with the former
-                                   // one. Must be pre-allocated
-             int &      ncontacts, //  number of contacts found
-             int       bricking=0  //  bricking control; may be a
-                                   // combination of BRICK_ON_1 or
-                                   // BRICK_ON_2 with BRICK_READY
-                       );
-
-    void  SeekContacts (
-           PPCAtom       AIndex1,  //  1st atom index [0..ilen1-1]
-           int           ilen1,    //  length of 1st index
-           PPCAtom *     AIndex2,  //  indexes of atoms to be checked
-                                   // for contact with each atom from
-                                   // Aindex1; dimension
-                                   // [0..nStructures-1][0..ilen2[i]-1]
-           ivector       ilen2,    //  lengths of indexes AIndex2
-           int           nStructures, //  number of indexes AIndex2
-           realtype      dist1,    //  minimal contact distance
-           realtype      dist2,    //  maximal contact distance
-           PPCMContact & contact,  // resulting contacts, one structure
-                                   // per each position in AIndex1. If
-                                   // AIndex1[i] is NULL, contact[i] is
-                                   // also NULL. "contact" is always
-                                   // allocated, no re-use or
-                                   // re-allocation is attempted.
-           int            bricking=0  //  bricking control; may be
-                                   // BRICK_READY if AIndex2 does not
-                                  // change
-                       );
-
-  protected :
-
-    //  bricks
-    realtype     brick_size, xbrick_0,ybrick_0,zbrick_0;
-    int          nbrick_x,nbrick_y,nbrick_z;
-    PPPCBrick  * Brick;
-
-    realtype     mbrick_size, xmbrick_0,ymbrick_0,zmbrick_0;
-    int          nmbrick_x,nmbrick_y,nmbrick_z;
-    PPPCMBrick * MBrick;
-
-    //  ---------------  Stream I/O  -----------------------------
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-    void  InitMMDBCoorManager();
-
-    void  ApplySymTransform ( int SymMatrixNo, PCGenSym GenSym=NULL );
-
-    void  ResetManager ();
-
-    void  FindSeqSection    ( PCAtom  atom, int  seqDist,
-                              int  &  seq1, int  &  seq2 );
-    Boolean    isContact    ( PCAtom    a1, PCAtom    a2,
-                              int     seq1, int     seq2,
-                              realtype  dd, realtype d12,
-                              realtype d22, realtype & d2 );
-    Boolean    isContact    ( realtype   x, realtype   y,
-                              realtype   z, PCAtom    a2,
-                              realtype  dd, realtype d12,
-                              realtype d22, realtype & d2 );
-
-};
-
-
-
-//  ===================================================================
-
-
-
-//   GetEulerRotMatrix(..) calculates the Euler rotation matrix
-// for rotation:
-//                   1) about z-axis by angle alpha
-//                   2) about new y-axis by angle beta
-//                   3) about new z-axis by angle gamma
-extern void  GetEulerRotMatrix ( mat33 & erm,   realtype alpha, 
-                                 realtype beta, realtype gamma );
-
-//  GetEulerTMatrix(..) calculates the Euler rotation-translation
-// matrix for rotation:
-//                   1) about z-axis by angle alpha
-//                   2) about new y-axis by angle beta
-//                   3) about new z-axis by angle gamma
-//  Point (x0,y0,z0) is the center of rotation.
-extern void  GetEulerTMatrix ( mat44 & erm,   realtype alpha, 
-                          realtype beta, realtype gamma,
-                          realtype x0,   realtype y0,  realtype z0 );
-
-//  Euler rotation:  1) about z-axis by angle alpha
-//                   2) about new y-axis by angle beta
-//                   3) about new z-axis by angle gamma
-//  Point (x0,y0,z0) is the center of rotation.
-extern void EulerRotation ( PPCAtom A, int nA,
-                         realtype alpha, realtype beta, realtype gamma,
-                         realtype x0,    realtype y0,   realtype z0 );
-
-//   GetVecRotMatrix(..) calculates the rotation matrix for
-// rotation by angle alpha about arbitrary vector directed
-// as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
-extern void GetVecRotMatrix ( mat33 & vrm,  realtype alpha, 
-                           realtype vx,  realtype vy, realtype vz );
-
-
-//    Given the rotation matrix vrm, GetRotParameters(..)
-//  returns the rotation angle alpha and the normalized
-//  rotation axis vector (vx,vy,vz).
-//    The rotation angle and vector are determined up to
-//  their sign (however correlated, so that being substituted
-//  into GetVecRotMatrix(..) they yield the same rotation
-//  matrix).
-//    The function does not check for vrm to be a valid
-//  rotation matrix.
-extern void GetRotParameters ( mat33 & vrm, realtype & alpha, 
-                       realtype & vx, realtype & vy, realtype & vz );
-
-
-//   GetVecTMatrix(..) calculates the rotation-translation matrix
-// for rotation by angle alpha about arbitrary vector directed as
-// (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1). Point (x0,y0,z0) is
-// the center of rotation -- actually a point belonging to the
-// rotation axis.
-extern void GetVecTMatrix  ( mat44 & vrm, realtype alpha, 
-                             realtype vx, realtype vy, realtype vz,
-                             realtype x0, realtype y0, realtype z0 );
-
-//   Vector rotation is rotation by angle alpha about arbitrary
-// vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
-// Point (x0,y0,z0) is the center of rotation -- actually
-// a point belonging to the rotation axis.
-extern void VectorRotation ( PPCAtom A, int nA,  realtype alpha,
-                             realtype vx, realtype vy, realtype vz,
-                             realtype x0, realtype y0, realtype z0 );
-
-extern void GetMassCenter  ( PPCAtom A, int nA,
-                      realtype & xmc, realtype & ymc, realtype & zmc );
-
-
-#define SPOSEAT_Ok       0
-#define SPOSEAT_NoAtoms  1
-#define SPOSEAT_SVD_Fail 2
-
-//   Given two sets of atoms, A1 and A2, SuperposeAtoms(...) calculates
-// the rotational-translational matrix T such that |T*A1 - A2| is
-// minimal in least-square terms.
-//   If vector C is not given (default), all nA atoms of set A1 are
-// considered as corresponding to nA first atoms of set A2,
-// A1[i] <-> A2[i], 0<=i<nA .
-//   If vector C is given, then the correspondence of atoms is
-// established as A1[i] <-> A2[C[i]] only for those i that C[i]>=0.
-// The default option (C==NULL) is thus identical to C[i]==i, 0<=i<nA.
-//   Upon normal completion, the procedure returns SPOSEAT_Ok.
-
-extern int SuperposeAtoms ( mat44 & T, PPCAtom A1, int nA, PPCAtom A2,
-                            ivector C=NULL );
-
-
-#define CNSORT_OFF    0
-#define CNSORT_1INC   1
-#define CNSORT_1DEC   2
-#define CNSORT_2INC   3
-#define CNSORT_2DEC   4
-#define CNSORT_DINC   5
-#define CNSORT_DDEC   6
-
-extern void  SortContacts ( PSContact contact, int ncontacts,
-                            int sortmode );
-
-
-#define  NO_TORSION  (-MaxReal)
-
-extern realtype getPhi ( PPCAtom A );  // A[0] - A[3] used
-extern realtype getPsi ( PPCAtom A );  // A[0] - A[2] used
-
-#endif
-
diff --git a/mmdb/mmdb_cryst.cpp b/mmdb/mmdb_cryst.cpp
deleted file mode 100755
index e205c0b..0000000
--- a/mmdb/mmdb_cryst.cpp
+++ /dev/null
@@ -1,2288 +0,0 @@
-//  $Id: mmdb_cryst.cpp,v 1.27 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    05.02.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Cryst  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CCrystContainer ( container for cryst.  data    )
-//       ~~~~~~~~~  CNCSMatrix      ( non-cryst. symm. matrix class )
-//                  CTVect          ( translational vector class    )
-//                  CMMDBCryst      ( MMDB cryst. section class     )
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __MMDB_Cryst__
-#include "mmdb_cryst.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-
-//  ==============  CCrystContainer  ====================
-
-PCContainerClass CCrystContainer::MakeContainerClass ( int ClassID )  {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template  :
-                  return  CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_NCSMatrix : return new CNCSMatrix();
-    case ClassID_TVect     : return new CTVect    ();
-  }
-}
-
-int CCrystContainer::AddMTRIXLine ( cpstr S )  {
-int i,RC;
-  RC = Error_NCSM_WrongSerial;
-  for (i=0;i<length;i++)  {
-    RC = PCNCSMatrix(Container[i])->ConvertPDBASCII(S);
-    if (RC==0)  break;
-    if (RC!=Error_NCSM_WrongSerial) break;
-  }
-  return RC;
-}
-
-MakeStreamFunctions(CCrystContainer)
-
-
-//  ================  CNCSMatrix  ===================
-
-CNCSMatrix::CNCSMatrix() : CContainerClass()  {
-  Init();
-}
-
-CNCSMatrix::CNCSMatrix ( cpstr S ) : CContainerClass()  {
-  Init();
-  ConvertPDBASCII ( S );
-}
-
-CNCSMatrix::CNCSMatrix ( RPCStream Object )
-          : CContainerClass(Object)  {
-  Init();
-}
-
-CNCSMatrix::~CNCSMatrix() {}
-
-void  CNCSMatrix::Init()  {
-int i,j;
-  serNum = -1;
-  iGiven = -1;
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      m[i][j] = 0.0;
-    m[i][i] = 1.0;
-    v[i] = 0.0;
-  }
-  WhatIsSet = 0;  // nothing is set
-}
-
-Boolean  CNCSMatrix::PDBASCIIDump1 ( RCFile f )  {
-//  makes the ASCII PDB MATRIXn lines if all
-//  of them were set.
-char S[100];
-int  i,j;
-
-  if ((WhatIsSet & NCSMSET_All)==NCSMSET_All)
-    for (i=0;i<3;i++)  {
-      sprintf   ( S,"MTRIX%1i %3i",i+1,serNum );
-      PadSpaces ( S,80 );
-      for (j=0;j<3;j++)
-        PutRealF ( &(S[10+j*10]),m[i][j],10,6 );
-      PutRealF ( &(S[45]),v[i],10,5 );
-      if (iGiven)  S[59] = '1';
-      f.WriteLine ( S );
-    }
-
-  return True;  // container should use this virtual
-
-}
-
-int CNCSMatrix::ConvertPDBASCII ( cpstr S )  {
-int      sN,iG;
-realtype m0,m1,m2,v0;
-
-  if (!(GetInteger(sN,&(S[7]) ,3 ) &&
-        GetReal   (m0,&(S[10]),10) &&
-        GetReal   (m1,&(S[20]),10) &&
-        GetReal   (m2,&(S[30]),10) &&
-        GetReal   (v0,&(S[45]),10)))
-    return Error_NCSM_Unrecognized;
-
-  if (S[59]=='1')  iG = 1;
-             else  iG = 0;
-
-  if (WhatIsSet & NCSMSET_All)  {
-    if (sN!=serNum)  return Error_NCSM_WrongSerial;
-    if (iG!=iGiven)  return Error_NCSM_UnmatchIG;
-  }
-
-  if (!strncmp(S,"MTRIX1",6))  {
-
-    if (WhatIsSet & NCSMSET_Matrix1)  return Error_NCSM_AlreadySet;
-    serNum  = sN;
-    iGiven  = iG;
-    m[0][0] = m0;
-    m[0][1] = m1;
-    m[0][2] = m2;
-    v[0]    = v0;
-    WhatIsSet |= NCSMSET_Matrix1;
-
-  } else if (!strncmp(S,"MTRIX2",6))  {
-
-    if (WhatIsSet & NCSMSET_Matrix2)  return Error_NCSM_AlreadySet;
-    serNum  = sN;
-    iGiven  = iG;
-    m[1][0] = m0;
-    m[1][1] = m1;
-    m[1][2] = m2;
-    v[1]    = v0;
-    WhatIsSet |= NCSMSET_Matrix2;
-
-  } else if (!strncmp(S,"MTRIX3",6))  {
-
-    if (WhatIsSet & NCSMSET_Matrix3)  return Error_NCSM_AlreadySet;
-    serNum  = sN;
-    iGiven  = iG;
-    m[2][0] = m0;
-    m[2][1] = m1;
-    m[2][2] = m2;
-    v[2]    = v0;
-    WhatIsSet |= NCSMSET_Matrix3;
-
-  } else
-    return Error_WrongSection;
-
-  return 0;
-
-}
-
-void  CNCSMatrix::MakeCIF ( PCMMCIFData CIF, int N )  {
-PCMMCIFLoop Loop;
-int         RC;
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_NCS_OPER,Loop );
-  if ((RC!=CIFRC_Ok) || (N==0))  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_ID       );
-    Loop->AddLoopTag ( CIFTAG_MATRIX11 );
-    Loop->AddLoopTag ( CIFTAG_MATRIX12 );
-    Loop->AddLoopTag ( CIFTAG_MATRIX13 );
-    Loop->AddLoopTag ( CIFTAG_VECTOR1  );
-    Loop->AddLoopTag ( CIFTAG_MATRIX21 );
-    Loop->AddLoopTag ( CIFTAG_MATRIX22 );
-    Loop->AddLoopTag ( CIFTAG_MATRIX23 );
-    Loop->AddLoopTag ( CIFTAG_VECTOR2  );
-    Loop->AddLoopTag ( CIFTAG_MATRIX31 );
-    Loop->AddLoopTag ( CIFTAG_MATRIX32 );
-    Loop->AddLoopTag ( CIFTAG_MATRIX33 );
-    Loop->AddLoopTag ( CIFTAG_VECTOR3  );
-    Loop->AddLoopTag ( CIFTAG_CODE     );
-  }
-  Loop->AddInteger ( serNum  );
-  if (WhatIsSet & NCSMSET_Matrix1) {
-    Loop->AddReal ( m[0][0] );
-    Loop->AddReal ( m[0][1] );
-    Loop->AddReal ( m[0][2] );
-    Loop->AddReal ( v[0]    );
-  } else  {
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-  }
-  if (WhatIsSet & NCSMSET_Matrix2) {
-    Loop->AddReal ( m[1][0] );
-    Loop->AddReal ( m[1][1] );
-    Loop->AddReal ( m[1][2] );
-    Loop->AddReal ( v[1]    );
-  } else  {
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-  }
-  if (WhatIsSet & NCSMSET_Matrix3) {
-    Loop->AddReal ( m[2][0] );
-    Loop->AddReal ( m[2][1] );
-    Loop->AddReal ( m[2][2] );
-    Loop->AddReal ( v[2]    );
-  } else  {
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-    Loop->AddString ( NULL );
-  }
-  if (iGiven==1)  Loop->AddString ( pstr("generated") );
-            else  Loop->AddNoData ( CIF_NODATA_DOT    );
-}
-
-void  CNCSMatrix::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-char        Code[100];
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_NCS_OPER );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-
-  if (Signal>=Loop->GetLoopLength())  {
-    Signal = -1;
-    return;
-  }
-
-  WhatIsSet = 0;
-  if (CIFGetInteger(serNum,Loop,CIFTAG_ID,Signal))  return;
-  if (CIFGetString(Code,Loop,CIFTAG_CODE,Signal,sizeof(Code),
-      pstr("")))
-    iGiven = MinInt4;
-  else if (!strcasecmp(Code,"generated"))
-    iGiven = 1;
-  else
-    iGiven = MinInt4;
-
-
-  if (CIFGetReal(m[0][0],Loop,CIFTAG_MATRIX11,Signal))  return;
-  if (CIFGetReal(m[0][1],Loop,CIFTAG_MATRIX12,Signal))  return;
-  if (CIFGetReal(m[0][2],Loop,CIFTAG_MATRIX13,Signal))  return;
-  if (CIFGetReal(v[0]   ,Loop,CIFTAG_VECTOR1 ,Signal))  return;
-  WhatIsSet |= NCSMSET_Matrix1;
-
-  if (CIFGetReal(m[1][0],Loop,CIFTAG_MATRIX21,Signal))  return;
-  if (CIFGetReal(m[1][1],Loop,CIFTAG_MATRIX22,Signal))  return;
-  if (CIFGetReal(m[1][2],Loop,CIFTAG_MATRIX23,Signal))  return;
-  if (CIFGetReal(v[1]   ,Loop,CIFTAG_VECTOR2 ,Signal))  return;
-  WhatIsSet |= NCSMSET_Matrix2;
-
-  if (CIFGetReal(m[2][0],Loop,CIFTAG_MATRIX31,Signal))  return;
-  if (CIFGetReal(m[2][1],Loop,CIFTAG_MATRIX32,Signal))  return;
-  if (CIFGetReal(m[2][2],Loop,CIFTAG_MATRIX33,Signal))  return;
-  if (CIFGetReal(v[2]   ,Loop,CIFTAG_VECTOR3 ,Signal))  return;
-  WhatIsSet |= NCSMSET_Matrix3;
-
-  Signal++;
-
-}
-
-void  CNCSMatrix::SetNCSMatrix ( int serialNum,
-                                 mat33 & ncs_m, vect3 & ncs_v,
-                                 int i_Given )  {
-int i,j;
-  serNum = serialNum;
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      m[i][j] = ncs_m[i][j];
-    v[i] = ncs_v[i];
-  }
-  iGiven     = i_Given;
-  WhatIsSet |= NCSMSET_All;
-}
-
-void  CNCSMatrix::Copy ( PCContainerClass NCSMatrix )  {
-int i,j;
-
-  serNum = PCNCSMatrix(NCSMatrix)->serNum;
-  iGiven = PCNCSMatrix(NCSMatrix)->iGiven;
-
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      m[i][j] = PCNCSMatrix(NCSMatrix)->m[i][j];
-    v[i] = PCNCSMatrix(NCSMatrix)->v[i];
-  }
-
-  WhatIsSet = PCNCSMatrix(NCSMatrix)->WhatIsSet;
-
-}
-
-void  CNCSMatrix::write ( RCFile f )  {
-int  i,j;
-byte Version=1;
-  f.WriteByte ( &Version );
-  f.WriteInt  ( &serNum  );
-  f.WriteInt  ( &iGiven  );
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      f.WriteReal ( &(m[i][j]) );
-    f.WriteReal ( &(v[i]) );
-  }
-  f.WriteWord ( &WhatIsSet );
-}
-
-void  CNCSMatrix::read ( RCFile f ) {
-int  i,j;
-byte Version;
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &serNum  );
-  f.ReadInt  ( &iGiven  );
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      f.ReadReal ( &(m[i][j]) );
-    f.ReadReal ( &(v[i]) );
-  }
-  f.ReadWord ( &WhatIsSet );
-}
-
-MakeStreamFunctions(CNCSMatrix)
-
-
-
-//  ================  CTVect  ===================
-
-CTVect::CTVect() : CContainerClass()  {
-  Init();
-}
-
-CTVect::CTVect ( cpstr S ) : CContainerClass()  {
-  Init();
-  ConvertPDBASCII ( S );
-}
-
-CTVect::CTVect ( RPCStream Object ) : CContainerClass(Object)  {
-  Init();
-}
-
-CTVect::~CTVect()  {
-  if (comment)  delete[] comment;
-}
-
-void CTVect::Init()  {
-  serNum  = -1;
-  t[0]    = 0.0;
-  t[1]    = 0.0;
-  t[2]    = 0.0;
-  comment = NULL;
-}
-
-void CTVect::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB TVECT line number N
-  sprintf   ( S,"TVECT  %3i",serNum );
-  PadSpaces ( S,80 );
-  PutRealF  ( &(S[10]),t[0],10,5 );
-  PutRealF  ( &(S[20]),t[1],10,5 );
-  PutRealF  ( &(S[30]),t[2],10,5 );
-  if (comment)
-    strncpy ( &(S[40]),comment,IMin(30,strlen(comment)) );
-}
-
-int CTVect::ConvertPDBASCII ( cpstr S )  {
-  GetInteger ( serNum ,&(S[7]) ,3  );
-  GetReal    ( t[0]   ,&(S[10]),10 );
-  GetReal    ( t[1]   ,&(S[20]),10 );
-  GetReal    ( t[2]   ,&(S[30]),10 );
-  CreateCopy ( comment,&(S[40])    );
-  return 0;
-
-}
-
-void CTVect::MakeCIF ( PCMMCIFData CIF, int N )  {
-PCMMCIFLoop Loop;
-int         RC;
-  RC = CIF->AddLoop ( CIFCAT_DATABASE_PDB_TVECT,Loop );
-  if ((RC!=CIFRC_Ok) || (N==0))  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_ID      );
-    Loop->AddLoopTag ( CIFTAG_VECTOR1 );
-    Loop->AddLoopTag ( CIFTAG_VECTOR2 );
-    Loop->AddLoopTag ( CIFTAG_VECTOR3 );
-    Loop->AddLoopTag ( CIFTAG_DETAILS );
-  }
-  Loop->AddInteger ( serNum  );
-  Loop->AddReal    ( t[0]    );
-  Loop->AddReal    ( t[1]    );
-  Loop->AddReal    ( t[2]    );
-  Loop->AddString  ( comment );
-}
-
-void  CTVect::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-
-  Loop = CIF->GetLoop ( CIFCAT_DATABASE_PDB_TVECT );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-
-  if (Signal>=Loop->GetLoopLength())  {
-    Signal = -1;
-    return;
-  }
-
-  if (CIFGetInteger(serNum,Loop,CIFTAG_ID,Signal))  return;
-  if (CIFGetReal(t[0],Loop,CIFTAG_VECTOR1,Signal))  return;
-  if (CIFGetReal(t[1],Loop,CIFTAG_VECTOR2,Signal))  return;
-  if (CIFGetReal(t[2],Loop,CIFTAG_VECTOR3,Signal))  return;
-  Loop->GetString ( comment,CIFTAG_DETAILS,Signal,True );
-
-  Signal++;
-
-}
-
-
-void  CTVect::Copy ( PCContainerClass TVect )  {
-int i;
-  serNum = PCTVect(TVect)->serNum;
-  for (i=0;i<3;i++)
-    t[i] = PCTVect(TVect)->t[i];
-  CreateCopy ( comment,PCTVect(TVect)->comment );
-}
-
-void  CTVect::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte ( &Version );
-  f.WriteInt  ( &serNum  );
-  for (i=0;i<3;i++)
-    f.WriteReal ( &(t[i]) );
-  f.CreateWrite ( comment );
-}
-
-void  CTVect::read ( RCFile f ) {
-int  i;
-byte Version;
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &serNum  );
-  for (i=0;i<3;i++)
-    f.ReadReal ( &(t[i]) );
-  f.CreateRead ( comment );
-}
-
-MakeStreamFunctions(CTVect)
-
-
-
-//  =====================   CMMDBCryst   =======================
-
-CMMDBCryst::CMMDBCryst() : CStream() {
-  Init ( True );
-}
-
-CMMDBCryst::CMMDBCryst ( RPCStream Object ) : CStream(Object)  {
-  Init ( True );
-}
-
-void  CMMDBCryst::Init ( Boolean fullInit )  {
-int i,j,k;
-
-  WhatIsSet = 0;  // nothing is set
-  a         = 1.0;
-  b         = 1.0;
-  c         = 1.0;
-  alpha     = 90.0;
-  beta      = 90.0;
-  gamma     = 90.0;
-  strcpy ( spaceGroup   ,"" );
-  strcpy ( spaceGroupFix,"" );
-  Z         = 1;
-  CellCheck = CCHK_NoCell;
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)  {
-      o[i][j] = 0.0;
-      s[i][j] = 0.0;
-      for (k=0;k<6;k++)
-        RR[k][i][j] = 0.0;
-    }
-    o[i][i] = 1.0;
-    s[i][i] = 1.0;
-    t[i]    = 0.0;
-    u[i]    = 0.0;
-    for (k=0;k<6;k++)
-      RR[k][i][i] = 1.0;
-  }
-  for (i=0;i<4;i++)  {
-    for (j=0;j<4;j++)  {
-      RO [i][j] = 0.0;
-      RF [i][j] = 0.0;
-      ROU[i][j] = 0.0;
-      RFU[i][j] = 0.0;
-    }
-    RO [i][i] = 1.0;
-    RF [i][i] = 1.0;
-    ROU[i][i] = 1.0;
-    RFU[i][i] = 1.0;
-  }
-  Vol    = 0.0;
-  VolChk = 0.0;
-  VolErr = 0.0;
-  as     = 1.0;
-  bs     = 1.0;
-  cs     = 1.0;
-  alphas = 90.0;
-  betas  = 90.0;
-  gammas = 90.0;
-
-  for (k=0;k<6;k++)
-    AC[k] = 0.0;
-
-  NCode  = 0;
-
-  if (fullInit)  {
-    syminfo_lib   = NULL;
-    ignoreScalei  = False;  // flag to ignore SCALEi cards
-    processSG     = True;   // flag to process space group at file read
-    fixSpaceGroup = True;   // flag to fix space group at file read
-  }
-
-}
-
-CMMDBCryst::~CMMDBCryst() {
-  FreeMemory();
-  if (syminfo_lib)  delete[] syminfo_lib;
-}
-
-void  CMMDBCryst::FreeMemory()  {
-  NCSMatrix.FreeContainer();
-  TVect    .FreeContainer();
-  SymOps   .FreeMemory   ();
-}
-
-void  CMMDBCryst::Reset()  {
-  FreeMemory();
-  Init ( False );
-}
-
-cpstr rhombohedral[] = {
-  cpstr("R 3"  ),
-  cpstr("R 3"  ),
-  cpstr("R 3 2"),
-  cpstr("R 3 2")
-};
-
-cpstr short_mono[] = {
-  cpstr("P 2" ),
-  cpstr("P 21"),
-  cpstr("C 2" ),
-  cpstr("A 2" ),
-  cpstr("B 2" ),
-  cpstr("I 2" )
-};
-
-cpstr special[] = {
-  cpstr("A1"     ),
-            cpstr("Hall:  P 1 (-x,-1/2*y+1/2*z,1/2*y+1/2*z)"  ),
-  cpstr("C1211"  ),
-            cpstr("Hall:  C 2y (x+1/4,y+1/4,z)"               ),
-  cpstr("C21"    ),
-            cpstr("Hall:  C 2y (x+1/4,y+1/4,z)"               ),
-  cpstr("I1211"  ),
-            cpstr("Hall:  C 2y (x+1/4,y+1/4,-x+z-1/4)"        ),
-  cpstr("I21"    ),
-            cpstr("Hall:  C 2y (x+1/4,y+1/4,-x+z-1/4)"        ),
-  cpstr("P21212A"),
-            cpstr("Hall:  P 2 2ab (x+1/4,y+1/4,z)"            ),
-  cpstr("F422"   ),
-            cpstr("Hall:  I 4 2 (1/2*x+1/2*y,-1/2*x+1/2*y,z)" ),
-  cpstr("C4212"  ),
-            cpstr("Hall:  P 4 2 (1/2*x+1/2*y-1/4,-1/2*x+1/2*y-1/4,z)")
-};
-
-
-
-int  CMMDBCryst::FixSpaceGroup()  {
-//  This function attempts to clean up the Brookhaven mess in space
-// group naming, by checking the space group symbol with cell
-// parameters.  Returns:
-//
-//     0    - space group symbol is correct, spaceGroupFix receives
-//            a copy of spaceGroup
-//     1    - space group symbol does not agree with cell parameters,
-//            and fixed successfully. spaceGroupFix receives
-//            the appropriate space group symbol
-//    -1    - space group symbol does not agree with cell parameters,
-//            however fix is not possible.  spaceGroupFix receives
-//            a copy of spaceGroup
-//    -2    - any checks are not possible because cell parameters
-//            are not found, spaceGroupFix receives a copy of
-//            spaceGroup
-//
-realtype eps,m1,m2;
-SymGroup s;
-int      i,k;
-char     c;
-
-  strcpy ( spaceGroupFix,spaceGroup );
-
-  if ((WhatIsSet & CSET_CellParams)!=CSET_CellParams)  return -2;
-
-  eps = 0.01;
-
-  k = -1;
-  for (i=0;(i<4) && (k<0);i++)
-    if (!strcmp(spaceGroup,rhombohedral[i]))  k = i;
-
-  if (k>=0)  {
-    c = 'N';
-    if ((fabs(a-b)<=eps) && (fabs(alpha-90.0)<=eps) &&
-        (fabs(beta-90.0)<=eps) && (fabs(gamma-120.0)<=eps))
-      c = 'H';
-    else {
-      m1 = (a+b+c)/3.0;
-      m2 = (alpha+beta+gamma)/3.0;
-      if ((fabs(a-m1)<=eps) && (fabs(b-m1)<=eps) &&
-          (fabs(c-m1)<=eps) &&
-          (fabs(alpha-m2)<=eps) && (fabs(beta-m2)<=eps) &&
-          (fabs(gamma-m2)<=eps))
-        c = 'R';
-    }
-    if (c!=spaceGroup[0])  {
-      if (c!='N')  {
-        spaceGroupFix[0] = c;
-        return 1;
-      }
-      return -1;
-    }
-    return 0;
-  }
-
-  for (i=0;(i<6) && (k<0);i++)
-    if (!strcmp(spaceGroup,short_mono[i]))  k = i;
-
-  if (k>=0)  {
-    if ((fabs(alpha-90.0)<=eps) && (fabs(gamma-90.0)<=eps))  {
-      if (spaceGroup[0]=='B')  return -1;
-      sprintf ( spaceGroupFix,"%c 1 %s 1",spaceGroup[0],
-                &(spaceGroup[2]) );
-      return 1;
-    }
-    if ((fabs(alpha-90.0)<=eps) && (fabs(beta-90.0)<=eps))  {
-      if (spaceGroup[0]=='C')  return -1;
-      sprintf ( spaceGroupFix,"%c 1 1 %s",spaceGroup[0],
-                &(spaceGroup[2]) );
-      return 1;
-    }
-    return -1;
-  }
-
-  i = 0;
-  k = 0;
-  while (spaceGroup[i])  {
-    if (spaceGroup[i]!=' ')  s[k++] = spaceGroup[i];
-    i++;
-  }
-  s[k] = char(0);
-
-  k = -1;
-  for (i=0;(i<16) && (k<0);i+=2)
-    if (!strcmp(s,special[i]))  k = i;
-
-  if (k>=0)  {
-    strcpy ( spaceGroupFix,special[k+1] );
-    return 1;
-  }
-
-  return 0;
-
-}
-
-int  CMMDBCryst::ConvertPDBString ( pstr PDBString )  {
-// Interprets the ASCII PDB line and fills the corresponding fields.
-//   Returns zero if the line was converted, otherwise returns a
-// non-negative value of Error_XXXX.
-//   PDBString must be not shorter than 81 characters.
-int         RC;
-PCNCSMatrix ncsMatrix;
-PCTVect     tVect;
-
-  //  pad input line with spaces, if necessary
-  PadSpaces ( PDBString,80 );
-
-  if (!strncmp(PDBString,"CRYST",5))  {
-    // Here we check for "CRYST" and not for "CRYST1" keyword.
-    // As seems, people tend to not differentiating them.
-    if (GetReal(a,&(PDBString[6]) ,9) &&
-        GetReal(b,&(PDBString[15]),9) &&
-        GetReal(c,&(PDBString[24]),9))
-      WhatIsSet |= CSET_CellParams1;
-
-    if (GetReal(alpha,&(PDBString[33]),7) &&
-        GetReal(beta ,&(PDBString[40]),7) &&
-        GetReal(gamma,&(PDBString[47]),7))
-      WhatIsSet |= CSET_CellParams2;
-
-    GetString ( spaceGroup,&(PDBString[55]),11 );
-    CutSpaces ( spaceGroup,SCUTKEY_BEGEND );
-    if (fixSpaceGroup)  FixSpaceGroup();
-                  else  strcpy ( spaceGroupFix,spaceGroup );
-    if (spaceGroupFix[0] && processSG)  {
-      if (SymOps.SetGroup(spaceGroupFix,syminfo_lib)==SYMOP_Ok)
-        WhatIsSet |= CSET_SpaceGroup;
-    }
-
-    if (GetInteger(Z,&(PDBString[66]),4))
-      WhatIsSet |= CSET_ZValue;
-
-    WhatIsSet &= 0xFBFF;
-
-    if ((a*b*c*alpha*beta*gamma==0.0) ||
-        ((a==1.0)      && (b==1.0)     && (c==1.0)      &&
-         (alpha==90.0) && (beta==90.0) && (gamma==90.0) &&
-         (!strcmp(spaceGroup,"P 1"))))  {
-      WhatIsSet &= ~(CSET_CellParams1 | CSET_CellParams2 |
-                     CSET_SpaceGroup);
-      WhatIsSet |= CSET_DummyCell;
-    }
-
-  } else if (!strncmp(PDBString,"ORIGX1",6))  {
-
-    if (GetReal(o[0][0],&(PDBString[10]),10) &&
-        GetReal(o[0][1],&(PDBString[20]),10) &&
-        GetReal(o[0][2],&(PDBString[30]),10) &&
-        GetReal(t[0]   ,&(PDBString[45]),10))
-      WhatIsSet |= CSET_OrigMatrix1;
-
-  } else if (!strncmp(PDBString,"ORIGX2",6))  {
-
-    if (GetReal(o[1][0],&(PDBString[10]),10) &&
-        GetReal(o[1][1],&(PDBString[20]),10) &&
-        GetReal(o[1][2],&(PDBString[30]),10) &&
-        GetReal(t[1]   ,&(PDBString[45]),10))
-      WhatIsSet |= CSET_OrigMatrix2;
-
-  } else if (!strncmp(PDBString,"ORIGX3",6))  {
-
-    if (GetReal(o[2][0],&(PDBString[10]),10) &&
-        GetReal(o[2][1],&(PDBString[20]),10) &&
-        GetReal(o[2][2],&(PDBString[30]),10) &&
-        GetReal(t[2]   ,&(PDBString[45]),10))
-      WhatIsSet |= CSET_OrigMatrix3;
-
-  } else if (!strncmp(PDBString,"SCALE1",6))  {
-
-    if (GetReal(s[0][0],&(PDBString[10]),10) &&
-        GetReal(s[0][1],&(PDBString[20]),10) &&
-        GetReal(s[0][2],&(PDBString[30]),10) &&
-        GetReal(u[0]   ,&(PDBString[45]),10))
-      WhatIsSet |= CSET_ScaleMatrix1;
-    WhatIsSet &= 0xFBFF;
-    CellCheck |= CCHK_Unchecked;
-
-  } else if (!strncmp(PDBString,"SCALE2",6))  {
-
-    if (GetReal(s[1][0],&(PDBString[10]),10) &&
-        GetReal(s[1][1],&(PDBString[20]),10) &&
-        GetReal(s[1][2],&(PDBString[30]),10) &&
-        GetReal(u[1]   ,&(PDBString[45]),10))
-      WhatIsSet |= CSET_ScaleMatrix2;
-    WhatIsSet &= 0xFBFF;
-    CellCheck |= CCHK_Unchecked;
-
-  } else if (!strncmp(PDBString,"SCALE3",6))  {
-
-    if (GetReal(s[2][0],&(PDBString[10]),10) &&
-        GetReal(s[2][1],&(PDBString[20]),10) &&
-        GetReal(s[2][2],&(PDBString[30]),10) &&
-        GetReal(u[2]   ,&(PDBString[45]),10))
-      WhatIsSet |= CSET_ScaleMatrix3;
-    WhatIsSet &= 0xFBFF;
-    CellCheck |= CCHK_Unchecked;
-
-  } else if (!strncmp(PDBString,"MTRIX",5))  {
-
-    RC = NCSMatrix.AddMTRIXLine ( PDBString );
-    if (RC==Error_NCSM_WrongSerial)  {
-      ncsMatrix = new CNCSMatrix();
-      RC = ncsMatrix->ConvertPDBASCII ( PDBString );
-      if (RC==0)  NCSMatrix.AddData ( ncsMatrix );
-            else  delete ncsMatrix;
-    }
-    return RC;
-
-  } else if (!strncmp(PDBString,"TVECT ",6))  {
-
-    tVect = new CTVect();
-    RC = tVect->ConvertPDBASCII(PDBString);
-    if (RC==0)  TVect.AddData ( tVect );
-          else  delete tVect;
-    return RC;
-
-  } else
-    return Error_WrongSection;
-
-  return 0;
-
-}
-
-void  CMMDBCryst::PDBASCIIDump ( RCFile f )  {
-int  i,j;
-char S[100];
-
-  if (WhatIsSet & (CSET_CrystCard | CSET_DummyCell))  {
-    strcpy    ( S,"CRYST1" );
-    PadSpaces ( S,80 );
-    if (WhatIsSet & CSET_CellParams1)  {
-      PutRealF ( &(S[6 ]),a,9,3 );
-      PutRealF ( &(S[15]),b,9,3 );
-      PutRealF ( &(S[24]),c,9,3 );
-    }
-    if (WhatIsSet & CSET_CellParams2)  {
-      PutRealF ( &(S[33]),alpha,7,2 );
-      PutRealF ( &(S[40]),beta ,7,2 );
-      PutRealF ( &(S[47]),gamma,7,2 );
-    }
-    if ((WhatIsSet & CSET_SpaceGroup) || (spaceGroup[0]))
-      strncpy ( &(S[55]),spaceGroup,IMin(11,strlen(spaceGroup)) );
-    if (WhatIsSet & CSET_ZValue)
-      PutInteger ( &(S[66]),Z,4 );
-    f.WriteLine ( S );
-  }
-
-  if ((WhatIsSet & CSET_OrigMatrix)==CSET_OrigMatrix)
-    for (i=0;i<3;i++)  {
-      sprintf   ( S,"ORIGX%1i",i+1);
-      PadSpaces ( S,80 );
-      for (j=0;j<3;j++)
-        PutRealF ( &(S[10+j*10]),o[i][j],10,6 );
-      PutRealF ( &(S[45]),t[i],10,5 );
-      f.WriteLine ( S );
-    }
-
-  if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)
-    for (i=0;i<3;i++)  {
-      sprintf   ( S,"SCALE%1i",i+1);
-      PadSpaces ( S,80 );
-      for (j=0;j<3;j++)
-        PutRealF ( &(S[10+j*10]),s[i][j],10,6 );
-      PutRealF ( &(S[45]),u[i],10,5 );
-      f.WriteLine ( S );
-    }
-
-  NCSMatrix.PDBASCIIDump ( f );
-  TVect    .PDBASCIIDump ( f );
-
-}
-
-
-int  CMMDBCryst::GetCIF ( PCMMCIFData CIF ) {
-PCMMCIFStruct Struct;
-int RC;
-
-  WhatIsSet = 0;
-
-  Struct = CIF->GetStructure ( CIFCAT_CELL );
-
-  if (Struct)  {
-
-    RC = CIFGetReal ( a,Struct,CIFTAG_LENGTH_A );
-    if (!RC)  RC = CIFGetReal ( b,Struct,CIFTAG_LENGTH_B );
-    if (!RC)  RC = CIFGetReal ( c,Struct,CIFTAG_LENGTH_C );
-    if (RC==Error_UnrecognizedReal)  return RC;
-    if (!RC)  WhatIsSet |= CSET_CellParams1;
-
-    RC = CIFGetReal ( alpha,Struct,CIFTAG_ANGLE_ALPHA );
-    if (!RC)  RC = CIFGetReal ( beta,Struct,CIFTAG_ANGLE_BETA );
-    if (!RC)  RC = CIFGetReal ( gamma,Struct,CIFTAG_ANGLE_GAMMA );
-    if (RC==Error_UnrecognizedReal)  return RC;
-    if (!RC)  WhatIsSet |= CSET_CellParams2;
-
-    RC = CIFGetInteger ( Z,Struct,CIFTAG_Z_PDB );
-    if (RC==Error_UnrecognizedReal)  return RC;
-    if (!RC) WhatIsSet |= CSET_ZValue;
-
-  }
-
-  Struct = CIF->GetStructure ( CIFCAT_SYMMETRY );
-  if (Struct)  {
-    CIFGetString ( spaceGroup,Struct,CIFTAG_SPACE_GROUP_NAME_H_M,
-                   sizeof(spaceGroup),pstr("") );
-    CutSpaces ( spaceGroup,SCUTKEY_BEGEND );
-    if (fixSpaceGroup)  FixSpaceGroup();
-                  else  strcpy ( spaceGroupFix,spaceGroup );
-    /*
-    if (fixSpaceGroup)  {
-      if (!strcasecmp(spaceGroup,"P 21"))
-        strcpy ( spaceGroup,"P 1 21 1" );
-      else if (!strcasecmp(spaceGroup,"C 2"))
-        strcpy ( spaceGroup,"C 1 2 1" );
-    }
-    */
-    if (spaceGroupFix[0] && processSG)  {
-      if (SymOps.SetGroup(spaceGroupFix,syminfo_lib)==SYMOP_Ok)
-        WhatIsSet |= CSET_SpaceGroup;
-    }
-  }
-
-  if ((a*b*c*alpha*beta*gamma==0.0) ||
-      ((a==1.0)      && (b==1.0)     && (c==1.0)      &&
-       (alpha==90.0) && (beta==90.0) && (gamma==90.0) &&
-       (!strcmp(spaceGroup,"P 1"))))  {
-    WhatIsSet &= ~(CSET_CellParams1 | CSET_CellParams2 |
-                   CSET_SpaceGroup);
-    WhatIsSet |= CSET_DummyCell;
-  }
-
-  Struct = CIF->GetStructure ( CIFCAT_DATABASE_PDB_MATRIX );
-  if (Struct)  {
-    RC = CIFGetReal ( o[0][0],Struct,CIFTAG_ORIGX11 );
-    if (!RC)  RC = CIFGetReal ( o[0][1],Struct,CIFTAG_ORIGX12 );
-    if (!RC)  RC = CIFGetReal ( o[0][2],Struct,CIFTAG_ORIGX13 );
-    if (!RC)  RC = CIFGetReal ( o[1][0],Struct,CIFTAG_ORIGX21 );
-    if (!RC)  RC = CIFGetReal ( o[1][1],Struct,CIFTAG_ORIGX22 );
-    if (!RC)  RC = CIFGetReal ( o[1][2],Struct,CIFTAG_ORIGX23 );
-    if (!RC)  RC = CIFGetReal ( o[2][0],Struct,CIFTAG_ORIGX31 );
-    if (!RC)  RC = CIFGetReal ( o[2][1],Struct,CIFTAG_ORIGX32 );
-    if (!RC)  RC = CIFGetReal ( o[2][2],Struct,CIFTAG_ORIGX33 );
-    if (!RC)  RC = CIFGetReal ( t[0]   ,Struct,CIFTAG_ORIGX_VECTOR1 );
-    if (!RC)  RC = CIFGetReal ( t[1]   ,Struct,CIFTAG_ORIGX_VECTOR2 );
-    if (!RC)  RC = CIFGetReal ( t[2]   ,Struct,CIFTAG_ORIGX_VECTOR3 );
-    if (RC)  return RC;
-    WhatIsSet |= CSET_OrigMatrix;
-  }
-
-  Struct = CIF->GetStructure ( CIFCAT_ATOM_SITES );
-  if (Struct)  {
-    RC = CIFGetReal ( s[0][0],Struct,CIFTAG_FRACT_TRANSF_MATRIX11 );
-    if (!RC)
-      RC = CIFGetReal(s[0][1],Struct,CIFTAG_FRACT_TRANSF_MATRIX12);
-    if (!RC)
-      RC = CIFGetReal(s[0][2],Struct,CIFTAG_FRACT_TRANSF_MATRIX13);
-    if (!RC)
-      RC = CIFGetReal(s[1][0],Struct,CIFTAG_FRACT_TRANSF_MATRIX21);
-    if (!RC)
-      RC = CIFGetReal(s[1][1],Struct,CIFTAG_FRACT_TRANSF_MATRIX22);
-    if (!RC)
-      RC = CIFGetReal(s[1][2],Struct,CIFTAG_FRACT_TRANSF_MATRIX23);
-    if (!RC)
-      RC = CIFGetReal(s[2][0],Struct,CIFTAG_FRACT_TRANSF_MATRIX31);
-    if (!RC)
-      RC = CIFGetReal(s[2][1],Struct,CIFTAG_FRACT_TRANSF_MATRIX32);
-    if (!RC)
-      RC = CIFGetReal(s[2][2],Struct,CIFTAG_FRACT_TRANSF_MATRIX33);
-    if (!RC)
-      RC = CIFGetReal(u[0]   ,Struct,CIFTAG_FRACT_TRANSF_VECTOR1 );
-    if (!RC)
-      RC = CIFGetReal(u[1]   ,Struct,CIFTAG_FRACT_TRANSF_VECTOR2 );
-    if (!RC)
-      RC = CIFGetReal(u[2]   ,Struct,CIFTAG_FRACT_TRANSF_VECTOR3 );
-    if (RC)  return RC;
-    WhatIsSet |= CSET_ScaleMatrix;
-  }
-
-  RC = NCSMatrix.GetCIF(CIF,ClassID_NCSMatrix);
-  if (RC) return RC;
-
-  RC = TVect.GetCIF(CIF,ClassID_TVect);
-  return RC;
-
-}
-
-void CMMDBCryst::MakeCIF ( PCMMCIFData CIF )  {
-PCMMCIFStruct Struct;
-char          S[200];
-
-  if (WhatIsSet & (CSET_CellParams1 | CSET_DummyCell))  {
-    CIF->AddStructure ( CIFCAT_CELL,Struct );
-    Struct->PutReal ( a,CIFTAG_LENGTH_A,8 );
-    Struct->PutReal ( b,CIFTAG_LENGTH_B,8 );
-    Struct->PutReal ( c,CIFTAG_LENGTH_C,8 );
-  }
-
-  if (WhatIsSet & (CSET_CellParams2 | CSET_DummyCell))  {
-    CIF->AddStructure ( CIFCAT_CELL,Struct );
-    Struct->PutReal ( alpha,CIFTAG_ANGLE_ALPHA,8 );
-    Struct->PutReal ( beta ,CIFTAG_ANGLE_BETA, 8 );
-    Struct->PutReal ( gamma,CIFTAG_ANGLE_GAMMA,8 );
-  }
-
-  if ((WhatIsSet & (CSET_SpaceGroup | CSET_DummyCell)) ||
-      (spaceGroup[0]))
-    CIF->PutString ( strcpy_cs(S,spaceGroup),CIFCAT_SYMMETRY,
-                     CIFTAG_SPACE_GROUP_NAME_H_M );
-
-  if (WhatIsSet & (CSET_ZValue | CSET_DummyCell))
-    CIF->PutInteger ( Z,CIFCAT_CELL,CIFTAG_Z_PDB );
-
-
-  if ((WhatIsSet & CSET_OrigMatrix)==CSET_OrigMatrix)  {
-    CIF->AddStructure ( CIFCAT_DATABASE_PDB_MATRIX,Struct );
-    Struct->PutReal ( o[0][0],CIFTAG_ORIGX11      ,8 );
-    Struct->PutReal ( o[0][1],CIFTAG_ORIGX12      ,8 );
-    Struct->PutReal ( o[0][2],CIFTAG_ORIGX13      ,8 );
-    Struct->PutReal ( o[1][0],CIFTAG_ORIGX21      ,8 );
-    Struct->PutReal ( o[1][1],CIFTAG_ORIGX22      ,8 );
-    Struct->PutReal ( o[1][2],CIFTAG_ORIGX23      ,8 );
-    Struct->PutReal ( o[2][0],CIFTAG_ORIGX31      ,8 );
-    Struct->PutReal ( o[2][1],CIFTAG_ORIGX32      ,8 );
-    Struct->PutReal ( o[2][2],CIFTAG_ORIGX33      ,8 );
-    Struct->PutReal ( t[0]   ,CIFTAG_ORIGX_VECTOR1,8 );
-    Struct->PutReal ( t[1]   ,CIFTAG_ORIGX_VECTOR2,8 );
-    Struct->PutReal ( t[2]   ,CIFTAG_ORIGX_VECTOR3,8 );
-  }
-
-  if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)  {
-    CIF->AddStructure ( CIFCAT_ATOM_SITES,Struct );
-    Struct->PutReal ( s[0][0],CIFTAG_FRACT_TRANSF_MATRIX11,8 );
-    Struct->PutReal ( s[0][1],CIFTAG_FRACT_TRANSF_MATRIX12,8 );
-    Struct->PutReal ( s[0][2],CIFTAG_FRACT_TRANSF_MATRIX13,8 );
-    Struct->PutReal ( s[1][0],CIFTAG_FRACT_TRANSF_MATRIX21,8 );
-    Struct->PutReal ( s[1][1],CIFTAG_FRACT_TRANSF_MATRIX22,8 );
-    Struct->PutReal ( s[1][2],CIFTAG_FRACT_TRANSF_MATRIX23,8 );
-    Struct->PutReal ( s[2][0],CIFTAG_FRACT_TRANSF_MATRIX31,8 );
-    Struct->PutReal ( s[2][1],CIFTAG_FRACT_TRANSF_MATRIX32,8 );
-    Struct->PutReal ( s[2][2],CIFTAG_FRACT_TRANSF_MATRIX33,8 );
-    Struct->PutReal ( u[0]   ,CIFTAG_FRACT_TRANSF_VECTOR1 ,8 );
-    Struct->PutReal ( u[1]   ,CIFTAG_FRACT_TRANSF_VECTOR2 ,8 );
-    Struct->PutReal ( u[2]   ,CIFTAG_FRACT_TRANSF_VECTOR3 ,8 );
-  }
-
-  NCSMatrix.MakeCIF ( CIF );
-  TVect    .MakeCIF ( CIF );
-
-}
-
-
-
-cpstr OrthCode[6] = {
-  cpstr("A/X0, C*/Z0"), // (standard brookhaven)
-  cpstr("B/X0, A*/Z0"),
-  cpstr("C/X0, B*/Z0"),
-  cpstr("HEX A+B/X0, C*/Z0"),
-  cpstr("A*/X0, C/Z0 (rollett)"),
-  cpstr("A/X0, B*/Y0")
-};
-
-cpstr getOrthCodeName ( int NCode )  {
-  if ((NCode>0) && (NCode<=6))  return OrthCode[NCode-1];
-  return cpstr("CUSTOM");
-}
-
-void  CMMDBCryst::CalcCoordTransforms()  {
-realtype rChk1,rChk2,Fac;
-int      i,j,k;
-
-  WhatIsSet &= ~CSET_Transforms;  // clear the flag
-
-  if ((WhatIsSet & CSET_CellParams)==CSET_CellParams)  {
-    //   The 'cryst1' card was supplied. Calculate
-    // standard orthogonalizations.
-
-    CalcOrthMatrices();
-    if (NCode<0)  NCode = 0;
-
-    for (i=0;i<3;i++)  {
-      for (j=0;j<3;j++)
-        RO[i][j] = RR[NCode][i][j];
-      RO[i][3] = 0.0;
-      RO[3][i] = 0.0;
-    }
-    RO[3][3] = 1.0;
-    Mat4Inverse ( RO,RF );
-
-    WhatIsSet |= CSET_Transforms;
-
-    if (ignoreScalei)
-      CellCheck = CCHK_Ok;
-    else if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)  {
-      //   All 'scalei' cards were supplied. Calculate
-      // rotation and translation matrices and check
-      // if they are in consistence with the cell.
-
-      for (i=0;i<3;i++)  {
-        for (j=0;j<3;j++)
-          RF[i][j] = s[i][j];
-        RF[i][3] = u[i];
-        RF[3][i] = 0.0;
-      }
-      RF[3][3] = 1.0;
-      Mat4Inverse ( RF,RO );
-
-      // Find orthogonalisation type
-      VolChk = RO[0][0]*(RO[1][1]*RO[2][2] - RO[1][2]*RO[2][1]) +
-               RO[0][1]*(RO[1][2]*RO[2][0] - RO[1][0]*RO[2][2]) +
-               RO[0][2]*(RO[1][0]*RO[2][1] - RO[1][1]*RO[2][0]);
-
-      CellCheck = CCHK_Ok;
-      if (Vol>0.0)  {
-        VolErr = fabs(VolChk-Vol)/Vol;
-        if (VolErr>0.02)     CellCheck |= CCHK_Error;
-        else if (VolErr>0.1) CellCheck |= CCHK_Disagreement;
-      } else
-        CellCheck |= CCHK_NoCell;
-
-      //  try to find NCode
-      NCode = -1;
-      for (k=0;(k<6) && (NCode<0);k++)  {
-        NCode = k;
-        for (i=0;i<3;i++)
-          for (j=0;j<3;j++)  {
-            rChk1 = RO[i][j] + RR[k][i][j];
-            rChk2 = RO[i][j] - RR[k][i][j];
-            if (fabs(rChk1)>=0.1)  {
-              if (fabs(rChk2/rChk1)>0.01)
-                NCode = -1;
-            }
-          }
-      }
-
-      //   Correct inaccuracy of SCALEi input due to FORMAT,
-      // replace RF,RO with RR[NCode][][] if possible.
-
-      if (NCode>=0)  {
-        for (i=0;i<3;i++)
-          for (j=0;j<3;j++)
-            RO[i][j] = RR[NCode][i][j];
-        Mat4Inverse ( RO,RF );
-      } else
-        CellCheck |= CCHK_NoOrthCode;
-
-      if ((u[0]!=0.0) || (u[1]!=0.0) || (u[2]!=0.0))
-        CellCheck |= CCHK_Translations;
-
-    }
-
-    //  Generate ROU and RFU for AnisoU stuff
-    RFU[3][3] = 1.0;
-    for (i=0;i<3;i++)  {
-      Fac = sqrt(RF[i][0]*RF[i][0] + RF[i][1]*RF[i][1] +
-                 RF[i][2]*RF[i][2]);
-      RFU[i][0] = RF[i][0]/Fac;
-      RFU[i][1] = RF[i][1]/Fac;
-      RFU[i][2] = RF[i][2]/Fac;
-      RFU[i][3] = 0.0;
-      RFU[3][i] = 0.0;
-    }
-    RFU[3][3] = 1.0;
-    Mat4Inverse ( RFU,ROU );
-
-  } else
-    CellCheck |= CCHK_NoCell;
-
-}
-
-
-void  CMMDBCryst::RWBROOKReadPrintout()  {
-int i,j;
-
-  if ((WhatIsSet & CSET_CellParams)==CSET_CellParams)  {
-    printf ( "  MATRICES DERIVED FROM CRYST1"
-             " CARD IN COORDINATE FILE\n\n\n"
-             "             RF                 "
-             "                 RO\n\n" );
-    for (i=0;i<4;i++)  {
-      printf ( " " );
-      for (j=0;j<4;j++)
-        printf ( "%8.3f",RF[i][j] );
-      printf ( "     " );
-      for (j=0;j<4;j++)
-        printf ( "%8.3f",RO[i][j] );
-      printf ( "\n" );
-    }
-    printf ( "\n" );
-  } else
-    printf ( "\n  $WARNING: NO CRYST CARDS READ$\n" );
-
-  if ((WhatIsSet & CSET_ScaleMatrix)!=CSET_ScaleMatrix)
-    printf ( "\n  $WARNING: NO SCALE CARDS READ$\n" );
-
-}
-
-
-void  CMMDBCryst::CalcOrthMatrices()  {
-//  Calculates matrices for standard orthogonalizations
-// and the cell volume.
-//  The matrices are stored in array RR
-realtype Conv,Alph,Bet,Gamm,Sum,V;
-realtype sinA,cosA,sinB,cosB,sinG,cosG;
-realtype sinAS,cosAS,sinBS,cosBS,sinGS,cosGS;
-int      i,j,k;
-
-  if ((WhatIsSet & CSET_CellParams)!=CSET_CellParams)  return;
-
-  Conv = Pi/180.0;
-
-  Alph = alpha*Conv;
-  Bet  = beta *Conv;
-  Gamm = gamma*Conv;
-
-  Sum  = (Alph+Bet+Gamm)*0.5;
-
-  V    = sqrt(sin(Sum-Alph)*sin(Sum-Bet)*sin(Sum-Gamm)*sin(Sum));
-
-  Vol  = 2.0*a*b*c*V;
-
-  //  Precaution measure for erratic use of the library
-  if ((fabs(Alph)<1.0e-6) || (fabs(Bet)<1.0e-6) ||
-                             (fabs(Gamm)<1.0e-6))  {
-    as     = 0.0;
-    bs     = 0.0;
-    cs     = 0.0;
-    alphas = 0.0;
-    betas  = 0.0;
-    gammas = 0.0;
-    for (k=0;k<6;k++)  {
-      AC[k] = 0.0;
-      for (i=0;i<3;i++)  {
-        for (j=0;j<3;j++)
-          RR[k][i][j] = 0.0;
-        RR[k][i][i] = 1.0;
-      }
-    }
-    return;
-  }
-
-  sinA   = sin(Alph);
-  cosA   = cos(Alph);
-  sinB   = sin(Bet);
-  cosB   = cos(Bet);
-  sinG   = sin(Gamm);
-  cosG   = cos(Gamm);
-
-  cosAS  = (cosG*cosB-cosA) / (sinB*sinG);
-  sinAS  = sqrt(1.0-cosAS*cosAS);
-  cosBS  = (cosA*cosG-cosB) / (sinA*sinG);
-  sinBS  = sqrt(1.0-cosBS*cosBS);
-  cosGS  = (cosA*cosB-cosG) / (sinA*sinB);
-  sinGS  = sqrt(1.0-cosGS*cosGS);
-
-  as     = b*c*sinA/Vol;
-  bs     = c*a*sinB/Vol;
-  cs     = a*b*sinG/Vol;
-  alphas = atan2(sinAS,cosAS)/Conv;
-  betas  = atan2(sinBS,cosBS)/Conv;
-  gammas = atan2(sinGS,cosGS)/Conv;
-
-// ---- Set useful things for calculating dstar
-
-  AC[0]  = as*as;
-  AC[1]  = bs*bs;
-  AC[2]  = cs*cs;
-  AC[3]  = 2.0*bs*cs*cosAS;
-  AC[4]  = 2.0*cs*as*cosBS;
-  AC[5]  = 2.0*as*bs*cosGS;
-
-// ---- Zero matrices
-
-  for (k=0;k<6;k++)
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)
-        RR[k][i][j] = 0.0;
-
-// ---- Calculate matrices
-
-// ---- XO along a  Zo along c*
-
-  RR[0][0][0] =  a;
-  RR[0][0][1] =  b*cosG;
-  RR[0][0][2] =  c*cosB;
-  RR[0][1][1] =  b*sinG;
-  RR[0][1][2] = -c*sinB*cosAS;
-  RR[0][2][2] =  c*sinB*sinAS;
-
- // ---- XO along b  Zo along a*
-
-  RR[1][0][0] =  a*cosG;
-  RR[1][0][1] =  b;
-  RR[1][0][2] =  c*cosA;
-  RR[1][1][0] = -a*sinG*cosBS;
-  RR[1][1][2] =  c*sinA;
-  RR[1][2][0] =  a*sinG*sinBS;
-
-// ---- XO along c  Zo along b*
-
-  RR[2][0][0] =  a*cosB;
-  RR[2][0][1] =  b*cosA;
-  RR[2][0][2] =  c;
-  RR[2][1][0] =  a*sinB;
-  RR[2][1][1] = -b*sinA*cosGS;
-  RR[2][2][1] =  b*sinA*sinGS;
-
-// ---- trigonal only - XO along a+b  YO alon a-b  Zo along c*
-
-  RR[3][0][0] =  a/2.0;
-  RR[3][0][1] =  a/2.0;
-  RR[3][1][0] = -a*sinG;
-  RR[3][1][1] =  a*sinG;
-  RR[3][2][2] =  c;
-
-// ---- XO along a*, ZO along c
-
-  RR[4][0][0] =  a*sinB*sinGS;
-  RR[4][1][0] = -a*sinB*cosGS;
-  RR[4][1][1] =  b*sinA;
-  RR[4][2][0] =  a*cosB;
-  RR[4][2][1] =  b*cosA;
-  RR[4][2][2] =  c;
-
-// ---- Grr*! to  Gerard Bricogne - his setting for P1 in SKEW.
-//      XO along a, Y0 along b*
-
-  RR[5][0][0] =  a;
-  RR[5][0][1] =  b*cosG;
-  RR[5][0][2] =  c*cosB;
-  RR[5][1][1] =  b*sinG*sinAS;
-  RR[5][2][1] = -b*sinG*cosAS;
-  RR[5][2][2] =  c*sinB;
-
-}
-
-
-Boolean CMMDBCryst::areMatrices()  {
-// returns True if the orthogonal-to-fractional and
-// fractional-to-orthogonal matrices are defined
-  return (WhatIsSet & CSET_Transforms)!=0x0000;
-}
-
-
-Boolean CMMDBCryst::Frac2Orth (
-              realtype x,    realtype y,    realtype z,
-              realtype & xx, realtype & yy, realtype & zz ) {
-  if (areMatrices())  {
-    xx = RO[0][0]*x + RO[0][1]*y + RO[0][2]*z + RO[0][3];
-    yy = RO[1][0]*x + RO[1][1]*y + RO[1][2]*z + RO[1][3];
-    zz = RO[2][0]*x + RO[2][1]*y + RO[2][2]*z + RO[2][3];
-    return True;
-  } else  {
-    xx = x;
-    yy = y;
-    zz = z;
-    return False;
-  }
-}
-
-Boolean CMMDBCryst::Orth2Frac (
-              realtype x,    realtype y,    realtype z,
-              realtype & xx, realtype & yy, realtype & zz ) {
-  if (areMatrices())  {
-    xx = RF[0][0]*x + RF[0][1]*y + RF[0][2]*z + RF[0][3];
-    yy = RF[1][0]*x + RF[1][1]*y + RF[1][2]*z + RF[1][3];
-    zz = RF[2][0]*x + RF[2][1]*y + RF[2][2]*z + RF[2][3];
-    return True;
-  } else  {
-    xx = x;
-    yy = y;
-    zz = z;
-    return False;
-  }
-}
-
-
-Boolean CMMDBCryst::Frac2Orth ( mat44 & F, mat44 & T )  {
-mat44 A;
-  if (areMatrices())  {
-    Mat4Mult ( A,F,RF );
-    Mat4Mult ( T,RO,A );
-    return True;
-  } else  {
-    Mat4Init ( T );
-    return False;
-  }
-}
-
-
-Boolean CMMDBCryst::Orth2Frac ( mat44 & T, mat44 & F )  {
-mat44 A;
-  if (areMatrices())  {
-    Mat4Mult ( A,T,RO );
-    Mat4Mult ( F,RF,A );
-    return True;
-  } else  {
-    Mat4Init ( F );
-    return False;
-  }
-}
-
-
-int  CMMDBCryst::GetNumberOfSymOps()  {
-  return SymOps.GetNofSymOps();
-}
-
-pstr CMMDBCryst::GetSymOp ( int Nop )  {
-  return SymOps.GetSymOp ( Nop );
-}
-
-
-int  CMMDBCryst::GetTMatrix ( mat44 & TMatrix, int Nop,
-                              int cellshift_a, int cellshift_b,
-                              int cellshift_c, PCSymOps symOpers )  {
-//
-//  GetTMatrix(..) calculates and returns the coordinate transformation
-//  matrix, which converts orthogonal coordinates according to the
-//  symmetry operation Nop and places them into unit cell shifted by
-//  cellshift_a a's, cellshift_b b's and cellshift_c c's.
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-//
-mat44 fm;
-int   i,j,k;
-
-  if (cellshift_a<=-MaxInt4) {
-    k = GetFractMatrix ( fm,Nop,0,0,0,symOpers );
-    fm[0][3] = frac(fm[0][3]);
-    fm[1][3] = frac(fm[1][3]);
-    fm[2][3] = frac(fm[2][3]);
-  } else
-    k = GetFractMatrix ( fm,Nop,cellshift_a,cellshift_b,cellshift_c,
-                         symOpers );
-
-  if (k)  {
-    Mat4Init ( TMatrix );
-    return k;
-  }
-
-  // transformation back to orthogonal coordinates
-  for (i=0;i<3;i++)  {
-    for (j=0;j<4;j++)  {
-      TMatrix[i][j] = 0.0;
-      for (k=0;k<3;k++)
-        TMatrix[i][j] += RO[i][k]*fm[k][j];
-    }
-    TMatrix[i][3] += RO[i][3];
-  }
-
-  TMatrix[3][0] = 0.0;
-  TMatrix[3][1] = 0.0;
-  TMatrix[3][2] = 0.0;
-  TMatrix[3][3] = 1.0;
-
-  return 0;
-
-}
-
-
-int  CMMDBCryst::GetUCTMatrix ( mat44 & TMatrix, int Nop,
-                                realtype x, realtype y, realtype z,
-                                int cellshift_a, int cellshift_b,
-                                int cellshift_c, PCSymOps symOpers )  {
-//
-//  GetUCTMatrix(..) calculates and returns the coordinate
-//  transformation matrix, which converts orthogonal coordinates
-//  according to the symmetry operation Nop. Translation part of
-//  the matrix is being chosen such that point (x,y,z) has least
-//  distance to the center of primary (333) unit cell, and then
-//  it is shifted by cellshift_a a's, cellshift_b b's and
-//  cellshift_c c's.
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-//
-mat44    fm,tm;
-vect3    ft;
-realtype x0,y0,z0, dx,dy,dz, d,d0;
-int      i,j,k, ic,jc,kc;
-
-  k = GetFractMatrix ( fm,Nop,0,0,0,symOpers );
-  if (k) {
-    Mat4Init ( TMatrix );
-    return k;
-  }
-
-  fm[0][3] = frac(fm[0][3]) + cellshift_a;
-  fm[1][3] = frac(fm[1][3]) + cellshift_b;
-  fm[2][3] = frac(fm[2][3]) + cellshift_c;
-
-  Frac2Orth ( cellshift_a+0.5,cellshift_b+0.5,cellshift_c+0.5,
-              x0,y0,z0 );
-
-  // transformation back to orthogonal coordinates
-
-  for (i=0;i<3;i++)
-    for (j=0;j<3;j++)  {
-      tm[i][j] = 0.0;
-      for (k=0;k<3;k++)
-        tm[i][j] += RO[i][k]*fm[k][j];
-    }
-  tm[3][0] = 0.0;
-  tm[3][1] = 0.0;
-  tm[3][2] = 0.0;
-  tm[3][3] = 1.0;
-
-  d0 = MaxReal;
-  for (ic=-3;ic<3;ic++)
-    for (jc=-3;jc<3;jc++)
-      for (kc=-3;kc<3;kc++)  {
-        ft[0] = fm[0][3] + ic;
-        ft[1] = fm[1][3] + jc;
-        ft[2] = fm[2][3] + kc;
-        for (i=0;i<3;i++)  {
-          tm[i][3] = 0.0;
-          for (k=0;k<3;k++)
-            tm[i][3] += RO[i][k]*ft[k];
-          tm[i][3] += RO[i][3];
-        }
-        dx = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3] - x0;
-        dy = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3] - y0;
-        dz = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3] - z0;
-        d = dx*dx + dy*dy + dz*dz;
-        if (d<d0)  {
-          d0 = d;
-          Mat4Copy ( tm,TMatrix );
-        }
-      }
-
-  return 0;
-
-}
-
-
-int  CMMDBCryst::GetFractMatrix ( mat44 & TMatrix, int Nop,
-                                  int cellshift_a, int cellshift_b,
-                                  int cellshift_c,
-                                  PCSymOps symOpers )  {
-//
-//  GetFractMatrix(..) calculates and returns the coordinate
-//  transformation matrix, which converts fractional coordinates
-//  according to the symmetry operation Nop and places them into
-//  unit cell shifted by cellshift_a a's, cellshift_b b's and
-//  cellshift_c c's.
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-//
-mat44 tm;
-int   i,j,k;
-
-  k = 0;
-  if (symOpers)  k = symOpers->GetTMatrix ( tm,Nop );
-           else  k = SymOps.GetTMatrix    ( tm,Nop );
-  if (!k)  {
-    if (!areMatrices())      k = 2;
-    if (!isCellParameters()) k = 3;
-  } else
-    k = 1;
-
-  if (k)  {
-    Mat4Init ( TMatrix );
-    return k;
-  }
-
-  //  transformation to fractional coordinates + symmetry operation
-  for (i=0;i<3;i++)  {
-    for (j=0;j<4;j++)  {
-      TMatrix[i][j] = 0.0;
-      for (k=0;k<3;k++)
-        TMatrix[i][j] += tm[i][k]*RF[k][j];
-    }
-    TMatrix[i][3] += tm[i][3];  // symmetry operation shift
-  }
-
-  // cell shift
-  TMatrix[0][3] += cellshift_a;
-  TMatrix[1][3] += cellshift_b;
-  TMatrix[2][3] += cellshift_c;
-
-  TMatrix[3][0] = 0.0;
-  TMatrix[3][1] = 0.0;
-  TMatrix[3][2] = 0.0;
-  TMatrix[3][3] = 1.0;
-
-  return 0;
-
-}
-
-int  CMMDBCryst::GetSymOpMatrix ( mat44 & TMatrix, int Nop )  {
-//
-//  GetSymOpMatrix(..) returns the transformation matrix for
-//  Nop-th symmetry operator in the space group
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-//
-  return SymOps.GetTMatrix ( TMatrix,Nop );
-}
-
-
-Boolean CMMDBCryst::Cryst2Orth ( rvector U )  {
-mat33    A,AT,Tmp,TmpMat;
-realtype BB;
-int      i,j,k;
-
-  if (areMatrices())  {
-
-    Tmp[0][0] = U[0];
-    Tmp[1][1] = U[1];
-    Tmp[2][2] = U[2];
-    Tmp[0][1] = U[3];
-    Tmp[1][0] = U[3];
-    Tmp[0][2] = U[4];
-    Tmp[2][0] = U[4];
-    Tmp[1][2] = U[5];
-    Tmp[2][1] = U[5];
-
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)  {
-        A [j][i] = ROU[j][i];
-        AT[i][j] = ROU[j][i];
-      }
-
-    //  TmpMat = Tmp*AT
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)  {
-        BB = 0.0;
-        for (k=0;k<3;k++)
-          BB += Tmp[i][k]*AT[k][j];
-        TmpMat[i][j] = BB;
-      }
-
-    //  Tmp = A*TmpMat
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)  {
-        BB = 0.0;
-        for (k=0;k<3;k++)
-          BB += A[i][k]*TmpMat[k][j];
-        Tmp[i][j] = BB;
-      }
-
-    U[0] = Tmp[0][0];
-    U[1] = Tmp[1][1];
-    U[2] = Tmp[2][2];
-    U[3] = Tmp[0][1];
-    U[4] = Tmp[0][2];
-    U[5] = Tmp[1][2];
-
-    return True;
-
-  }
-
-  return False;
-
-}
-
-
-Boolean  CMMDBCryst::Orth2Cryst ( rvector U )  {
-mat33    A,AT,Tmp,TmpMat;
-realtype BB;
-int      i,j,k;
-
-  if (areMatrices())  {
-
-    Tmp[0][0] = U[0];
-    Tmp[1][1] = U[1];
-    Tmp[2][2] = U[2];
-    Tmp[0][1] = U[3];
-    Tmp[1][0] = U[3];
-    Tmp[0][2] = U[4];
-    Tmp[2][0] = U[4];
-    Tmp[1][2] = U[5];
-    Tmp[2][1] = U[5];
-
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)  {
-        A [j][i] = RFU[j][i];
-        AT[i][j] = RFU[j][i];
-      }
-
-    //  TmpMat = Tmp*AT
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)  {
-        BB = 0.0;
-        for (k=0;k<3;k++)
-          BB += Tmp[i][k]*AT[k][j];
-        TmpMat[i][j] = BB;
-      }
-
-    //  Tmp = A*TmpMat
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)  {
-        BB = 0.0;
-        for (k=0;k<3;k++)
-          BB += A[i][k]*TmpMat[k][j];
-        Tmp[i][j] = BB;
-      }
-
-    U[0] = Tmp[0][0];
-    U[1] = Tmp[1][1];
-    U[2] = Tmp[2][2];
-    U[3] = Tmp[0][1];
-    U[4] = Tmp[0][2];
-    U[5] = Tmp[1][2];
-
-    return True;
-
-  }
-
-  return False;
-
-}
-
-
-void  CMMDBCryst::SetCell ( realtype cell_a,
-                            realtype cell_b,
-                            realtype cell_c,
-                            realtype cell_alpha,
-                            realtype cell_beta,
-                            realtype cell_gamma,
-                            int      OrthCode )  {
-//  this function should be used for changing the cell parameters
-int  i,j;
-
-  if ((cell_a>0.0)      && (cell_b>0.0)     && (cell_c>0.0) &&
-      (cell_alpha!=0.0) && (cell_beta!=0.0) && (cell_gamma!=0.0))  {
-
-    if (OrthCode>0)  NCode = OrthCode-1;
-               else  NCode = 0;
-
-    a     = cell_a;
-    b     = cell_b;
-    c     = cell_c;
-    alpha = cell_alpha;
-    beta  = cell_beta;
-    gamma = cell_gamma;
-
-    WhatIsSet |= CSET_CellParams;
-
-    // calculate matrices
-
-    for (i=0;i<4;i++)  {
-      for (j=0;j<4;j++)  {
-        RO [i][j] = 0.0;
-        RF [i][j] = 0.0;
-        ROU[i][j] = 0.0;
-        RFU[i][j] = 0.0;
-      }
-      RO [i][i] = 1.0;
-      RF [i][i] = 1.0;
-      ROU[i][i] = 1.0;
-      RFU[i][i] = 1.0;
-    }
-
-    CalcCoordTransforms();
-
-    if (!(CellCheck & CCHK_NoOrthCode))  {
-      for (i=0;i<3;i++)  {
-        for (j=0;j<3;j++)
-          RO[i][j] = RR[NCode][i][j];
-        RO[i][3] = 0.0;
-        RO[3][i] = 0.0;
-      }
-      RO[3][3] = 1.0;
-      Mat4Inverse ( RO,RF );
-    }
-
-    WhatIsSet |= CSET_Transforms;
-
-  } else
-
-    WhatIsSet &= ~(CSET_CellParams | CSET_Transforms);
-
-}
-
-void CMMDBCryst::SetSyminfoLib ( cpstr syminfoLib )  {
-  CreateCopy ( syminfo_lib,syminfoLib );
-}
-
-pstr CMMDBCryst::GetSyminfoLib()  {
-  return syminfo_lib;
-}
-
-int CMMDBCryst::SetSpaceGroup ( cpstr spGroup )  {
-//  This function does not attempt to fix the space group
-int RC,l;
-  RC = SYMOP_UnknownSpaceGroup;
-  WhatIsSet &= ~CSET_SpaceGroup;
-  if (spGroup)  {
-    if (spGroup[0])  {
-      l = IMin ( strlen(spGroup),sizeof(spaceGroup)-1 );
-      strcpy_ncss ( spaceGroup,spGroup,l );
-      strcpy ( spaceGroupFix,spaceGroup );
-      if (spaceGroup[0])  {
-        RC = SymOps.SetGroup ( spaceGroup,syminfo_lib );
-    //        RC = SymOps.SetGroup ( spGroup,syminfo_lib );
-        //      strncpy ( spaceGroup,spGroup,l );
-        //      spaceGroup[l] = char(0);
-        if (RC==SYMOP_Ok)  WhatIsSet |= CSET_SpaceGroup;
-      }
-    }
-  }
-  return RC;
-}
-
-
-void  CMMDBCryst::PutCell ( realtype cell_a,
-                            realtype cell_b,
-                            realtype cell_c,
-                            realtype cell_alpha,
-                            realtype cell_beta,
-                            realtype cell_gamma,
-                            int      OrthCode ) {
-//  this function should be used for setting the cell parameters
-int i,j;
-
-  if ((cell_a!=0.0) || (OrthCode>0))  {
-    a     = cell_a;
-    b     = cell_b;
-    c     = cell_c;
-    alpha = cell_alpha;
-    beta  = cell_beta;
-    gamma = cell_gamma;
-    WhatIsSet |= CSET_CellParams;
-  }
-
-  if (OrthCode>0)  {
-
-    // calculate matrices
-
-    NCode = OrthCode-1;
-    CalcOrthMatrices();
-
-    for (i=0;i<3;i++)  {
-      for (j=0;j<3;j++)
-        RO[i][j] = RR[NCode][i][j];
-      RO[i][3] = 0.0;
-      RO[3][i] = 0.0;
-    }
-    RO[3][3] = 1.0;
-
-    Mat4Inverse ( RO,RF );
-
-    WhatIsSet |= CSET_Transforms;
-
-  } else
-    WhatIsSet &= ~CSET_Transforms;
-
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      s[i][j] = RF[i][j];
-    u[i] = RF[i][3];
-  }
-
-  WhatIsSet |= CSET_ScaleMatrix;
-
-}
-
-
-Boolean CMMDBCryst::isScaleMatrix()  {
-  return  ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix);
-}
-
-Boolean CMMDBCryst::isCellParameters()  {
-  return  ((WhatIsSet & CSET_CellParams)==CSET_CellParams);
-}
-
-Boolean CMMDBCryst::isNCSMatrix()  {
-  return  (NCSMatrix.Length()>0);
-}
-
-int  CMMDBCryst::GetNumberOfNCSMatrices()  {
-  return  NCSMatrix.Length();
-}
-
-int  CMMDBCryst::GetNumberOfNCSMates()  {
-// Returns the number of NCS mates not given in the file (iGiven==0)
-int         i,l,iG;
-PCNCSMatrix NCSM;
-  iG = 0;
-  l  = NCSMatrix.Length();
-  for (i=0;i<l;i++)  {
-    NCSM = PCNCSMatrix(NCSMatrix.GetContainerClass(i));
-    if (NCSM)  {
-      if (!NCSM->iGiven)  iG++;
-    }
-  }
-  return iG;
-}
-
-Boolean CMMDBCryst::GetNCSMatrix ( int NCSMatrixNo,
-                                   mat33 & ncs_m, vect3 & ncs_v )  {
-int         i,j;
-PCNCSMatrix NCSM;
-  NCSM = PCNCSMatrix(NCSMatrix.GetContainerClass(NCSMatrixNo));
-  if (NCSM)  {
-    for (i=0;i<3;i++) {
-      for (j=0;j<3;j++)
-        ncs_m[i][j] = NCSM->m[i][j];
-      ncs_v[i] = NCSM->v[i];
-    }
-    return True;
-  }
-  return False;
-}
-
-Boolean CMMDBCryst::GetNCSMatrix ( int NCSMatrixNo,
-                                   mat44 & ncs_m, int & iGiven )  {
-int         i,j;
-PCNCSMatrix NCSM;
-  NCSM = PCNCSMatrix(NCSMatrix.GetContainerClass(NCSMatrixNo));
-  if (NCSM)  {
-    for (i=0;i<3;i++) {
-      for (j=0;j<3;j++)
-        ncs_m[i][j] = NCSM->m[i][j];
-      ncs_m[i][3] = NCSM->v[i];
-    }
-    ncs_m[3][0] = 0.0;
-    ncs_m[3][1] = 0.0;
-    ncs_m[3][2] = 0.0;
-    ncs_m[3][3] = 1.0;
-    iGiven = NCSM->iGiven;
-    return True;
-  } else  {
-    for (i=0;i<4;i++) {
-      for (j=0;j<4;j++)
-        ncs_m[i][j] = 0.0;
-      ncs_m[i][i] = 1.0;
-    }
-    return False;
-  }
-}
-
-int  CMMDBCryst::AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v,
-                                int iGiven )  {
-PCNCSMatrix ncsMatrix;
-  ncsMatrix = new CNCSMatrix();
-  ncsMatrix->SetNCSMatrix ( NCSMatrix.Length()+1,ncs_m,ncs_v,
-                            iGiven );
-  NCSMatrix.AddData ( ncsMatrix );
-  return ncsMatrix->serNum;
-}
-
-void  CMMDBCryst::GetRCell ( realtype & cell_as,
-                             realtype & cell_bs,
-                             realtype & cell_cs,
-                             realtype & cell_alphas,
-                             realtype & cell_betas,
-                             realtype & cell_gammas,
-                             realtype & vols )  {
-  cell_as     = as;
-  cell_bs     = bs;
-  cell_cs     = cs;
-  cell_alphas = alphas;
-  cell_betas  = betas;
-  cell_gammas = gammas;
-  if (Vol!=0.0)  vols = 1.0/Vol;
-           else  vols = 0.0;
-}
-
-void  CMMDBCryst::GetCell ( realtype & cell_a,
-                            realtype & cell_b,
-                            realtype & cell_c,
-                            realtype & cell_alpha,
-                            realtype & cell_beta,
-                            realtype & cell_gamma,
-                            realtype & vol )  {
-  if (WhatIsSet & CSET_CellParams)  {
-    cell_a     = a;
-    cell_b     = b;
-    cell_c     = c;
-    cell_alpha = alpha;
-    cell_beta  = beta;
-    cell_gamma = gamma;
-    vol        = Vol;
-  } else  {
-    cell_a     = 0.0;
-    cell_b     = 0.0;
-    cell_c     = 0.0;
-    cell_alpha = 0.0;
-    cell_beta  = 0.0;
-    cell_gamma = 0.0;
-    vol        = 0.0;
-  }
-}
-
-pstr CMMDBCryst::GetSpaceGroup()  {
-  if (WhatIsSet & CSET_SpaceGroup)  return spaceGroup;
-                              else  return NULL;
-}
-
-pstr CMMDBCryst::GetSpaceGroupFix()  {
-  if (WhatIsSet & CSET_SpaceGroup)  return spaceGroupFix;
-                              else  return NULL;
-}
-
-
-void  CMMDBCryst::Copy ( PCMMDBCryst Cryst )  {
-int i,j,k;
-
-  if (Cryst)  {
-
-    a     = Cryst->a;
-    b     = Cryst->b;
-    c     = Cryst->c;
-    alpha = Cryst->alpha;
-    beta  = Cryst->beta;
-    gamma = Cryst->gamma;
-
-    for (i=0;i<4;i++)
-      for (j=0;j<4;j++)  {
-        RO [i][j] = Cryst->RO [i][j];
-        RF [i][j] = Cryst->RF [i][j];
-        ROU[i][j] = Cryst->ROU[i][j];
-        RFU[i][j] = Cryst->RFU[i][j];
-      }
-
-    for (i=0;i<3;i++) {
-      for (j=0;j<3;j++)  {
-        o[i][j] = Cryst->o[i][j];
-        s[i][j] = Cryst->s[i][j];
-        for (k=0;k<6;k++)
-          RR[k][i][j] = Cryst->RR[k][i][j];
-      }
-      t[i] = Cryst->t[i];
-      u[i] = Cryst->u[i];
-    }
-
-    Vol       = Cryst->Vol;
-    NCode     = Cryst->NCode;
-    Z         = Cryst->Z;
-    CellCheck = Cryst->CellCheck;
-    WhatIsSet = Cryst->WhatIsSet;
-    strcpy ( spaceGroup   ,Cryst->spaceGroup    );
-    strcpy ( spaceGroupFix,Cryst->spaceGroupFix );
-
-    NCSMatrix.Copy ( &(Cryst->NCSMatrix) );
-    TVect    .Copy ( &(Cryst->TVect)     );
-    SymOps   .Copy ( &(Cryst->SymOps)    );
-
-    as     = Cryst->as;
-    bs     = Cryst->bs;
-    cs     = Cryst->cs;
-    alphas = Cryst->alphas;
-    betas  = Cryst->betas;
-    gammas = Cryst->betas;
-    VolChk = Cryst->VolChk;
-    VolErr = Cryst->VolErr;
-
-    for (k=0;k<6;k++)
-      AC[k] = Cryst->AC[k];
-
-  } else  {
-
-    NCSMatrix.FreeContainer();
-    TVect    .FreeContainer();
-    WhatIsSet = 0;
-
-  }
-
-}
-
-
-void  CMMDBCryst::write ( RCFile f )  {
-int  i,j,k;
-byte Version=3;
-
-  f.WriteByte ( &Version   );
-  f.WriteWord ( &WhatIsSet );
-  f.WriteReal ( &a         );
-  f.WriteReal ( &b         );
-  f.WriteReal ( &c         );
-  f.WriteReal ( &alpha     );
-  f.WriteReal ( &beta      );
-  f.WriteReal ( &gamma     );
-  f.WriteWord ( &CellCheck );
-  f.WriteBool ( &ignoreScalei );
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)  {
-      f.WriteReal ( &(RO [i][j]) );
-      f.WriteReal ( &(RF [i][j]) );
-      f.WriteReal ( &(ROU[i][j]) );
-      f.WriteReal ( &(RFU[i][j]) );
-    }
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)  {
-      f.WriteReal ( &(o[i][j]) );
-      f.WriteReal ( &(s[i][j]) );
-      for (k=0;k<6;k++)
-        f.WriteReal ( &(RR[k][i][j]) );
-    }
-    f.WriteReal ( &(t[i]) );
-    f.WriteReal ( &(u[i]) );
-  }
-  f.WriteReal ( &Vol    );
-  f.WriteReal ( &VolChk );
-  f.WriteReal ( &VolErr );
-  f.WriteInt  ( &NCode  );
-  f.WriteInt  ( &Z      );
-  f.WriteTerLine ( spaceGroup   ,False );
-  f.WriteTerLine ( spaceGroupFix,False );
-
-  for (i=0;i<6;i++)
-    f.WriteReal ( &(AC[6]) );
-  f.WriteReal ( &as     );
-  f.WriteReal ( &bs     );
-  f.WriteReal ( &cs     );
-  f.WriteReal ( &alphas );
-  f.WriteReal ( &betas  );
-  f.WriteReal ( &gammas );
-
-  NCSMatrix.write ( f );
-  TVect    .write ( f );
-  SymOps   .write ( f );
-
-}
-
-void  CMMDBCryst::read ( RCFile f )  {
-int  i,j,k;
-byte Version;
-
-  f.ReadByte ( &Version   );
-  f.ReadWord ( &WhatIsSet );
-  f.ReadReal ( &a         );
-  f.ReadReal ( &b         );
-  f.ReadReal ( &c         );
-  f.ReadReal ( &alpha     );
-  f.ReadReal ( &beta      );
-  f.ReadReal ( &gamma     );
-  f.ReadWord ( &CellCheck );
-  if (Version>2)
-    f.ReadBool ( &ignoreScalei );
-  else  ignoreScalei = False;
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)  {
-      f.ReadReal ( &(RO [i][j]) );
-      f.ReadReal ( &(RF [i][j]) );
-      f.ReadReal ( &(ROU[i][j]) );
-      f.ReadReal ( &(RFU[i][j]) );
-    }
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)  {
-      f.ReadReal ( &(o[i][j]) );
-      f.ReadReal ( &(s[i][j]) );
-      for (k=0;k<6;k++)
-        f.ReadReal ( &(RR[k][i][j]) );
-    }
-    f.ReadReal ( &(t[i]) );
-    f.ReadReal ( &(u[i]) );
-  }
-  f.ReadReal ( &Vol    );
-  f.ReadReal ( &VolChk );
-  f.ReadReal ( &VolErr );
-  f.ReadInt  ( &NCode  );
-  f.ReadInt  ( &Z      );
-  f.ReadTerLine ( spaceGroup,False );
-  if (Version>1)
-        f.ReadTerLine ( spaceGroupFix,False );
-  else  strcpy ( spaceGroupFix,spaceGroup );
-
-  for (i=0;i<6;i++)
-    f.ReadReal ( &(AC[6]) );
-  f.ReadReal ( &as     );
-  f.ReadReal ( &bs     );
-  f.ReadReal ( &cs     );
-  f.ReadReal ( &alphas );
-  f.ReadReal ( &betas  );
-  f.ReadReal ( &gammas );
-
-  NCSMatrix.read ( f );
-  TVect    .read ( f );
-  SymOps   .read ( f );
-
-}
-
-
-MakeStreamFunctions(CMMDBCryst)
-
-
-// ===================================================================
-
-
-void  TestCryst() {
-//  reads from 'in.cryst', writes into
-//  'out.cryst' and 'abin.cryst'
-CFile       f;
-char        S[81];
-PCMMDBCryst Cryst;
-
-  Cryst = new CMMDBCryst();
-
-  f.assign ( pstr("in.cryst"),True );
-  if (f.reset()) {
-    while (!f.FileEnd()) {
-      f.ReadLine ( S,sizeof(S) );
-      Cryst->ConvertPDBString ( S );
-    }
-    f.shut();
-  } else {
-    printf ( " Can't open input file 'in.chain' \n" );
-    delete Cryst;
-    return;
-  }
-
-  f.assign ( pstr("out.cryst"),True );
-  if (f.rewrite()) {
-    Cryst->PDBASCIIDump ( f );
-    f.shut();
-  } else {
-    printf ( " Can't open output file 'out.cryst' \n" );
-    delete Cryst;
-    return;
-  }
-
-
-  f.assign ( pstr("mmdb.cryst.bin"),False );
-  if (f.rewrite()) {
-    Cryst->write ( f );
-    f.shut();
-  } else {
-    printf ( "  Can't open binary cryst file for writing.\n" );
-    delete Cryst;
-    return;
-  }
-
-  delete Cryst;
-  printf ( "   Cryst deleted.\n" );
-
-  Cryst = new CMMDBCryst();
-  if (f.reset()) {
-    Cryst->read ( f );
-    f.shut();
-  } else {
-    printf ( "  Can't open binary cryst file for reading.\n" );
-    delete Cryst;
-    return;
-  }
-
-  f.assign ( pstr("abin.cryst"),True );
-  if (f.rewrite()) {
-    Cryst->PDBASCIIDump ( f );
-    f.shut();
-  } else
-    printf ( " Can't open output file 'abin.cryst' \n" );
-
-  delete Cryst;
-
-}
diff --git a/mmdb/mmdb_cryst.h b/mmdb/mmdb_cryst.h
deleted file mode 100755
index f6ddc26..0000000
--- a/mmdb/mmdb_cryst.h
+++ /dev/null
@@ -1,462 +0,0 @@
-//  $Id: mmdb_cryst.h,v 1.24 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    06.02.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Cryst <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CCrystContainer ( container for cryst. data     )
-//       ~~~~~~~~~  CNCSMatrix      ( non-cryst. symm. matrix class )
-//                  CTVect          ( translation vector class      )
-//                  CMMDBCryst      ( MMDB cryst. section class     )
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Cryst__
-#define __MMDB_Cryst__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef  __MMDB_SymOp__
-#include "mmdb_symop.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_Utils__
-#include "mmdb_utils.h"
-#endif
-
-
-//  ====================  CCrystContainer  ======================
-
-DefineClass(CCrystContainer)
-DefineStreamFunctions(CCrystContainer)
-
-class CCrystContainer : public CClassContainer  {
-
-  public :
-
-    CCrystContainer () : CClassContainer() {}
-    CCrystContainer ( RPCStream Object )
-                       : CClassContainer ( Object ) {}
-    ~CCrystContainer() {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-    int AddMTRIXLine ( cpstr S );
-
-};
-
-
-//  ==================  CNCSMatrix  ========================
-
-#define NCSMSET_Matrix1  0x00000001
-#define NCSMSET_Matrix2  0x00000002
-#define NCSMSET_Matrix3  0x00000004
-#define NCSMSET_All      0x00000007
-
-DefineClass(CNCSMatrix)
-DefineStreamFunctions(CNCSMatrix)
-
-class CNCSMatrix : public CContainerClass  {
-
-  friend class CMMDBCryst;
-
-  public :
-
-    int   serNum;   // serial number
-    mat33 m;        // non-crystallographic symmetry matrix
-    vect3 v;        // translational part of ncs matrix
-    int   iGiven;   // iGiven flag (see PDB format)
-
-    CNCSMatrix ();
-    CNCSMatrix ( cpstr S );
-    CNCSMatrix ( RPCStream Object );
-    ~CNCSMatrix();
-
-    Boolean PDBASCIIDump1   ( RCFile f );
-    int     ConvertPDBASCII ( cpstr S );
-    void    MakeCIF         ( PCMMCIFData CIF, int N );
-    void    GetCIF          ( PCMMCIFData CIF, int & Signal );
-
-    int     GetClassID      () { return ClassID_NCSMatrix; }
-
-    void    SetNCSMatrix    ( int serialNum,
-                              mat33 & ncs_m, vect3 & ncs_v,
-                              int i_Given );
-
-    void  Copy  ( PCContainerClass NCSMatrix );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    word  WhatIsSet;  //    mask       field
-                      //   0x0001    MTRIX1 was converted
-                      //   0x0002    MTRIX2 was converted
-                      //   0x0004    MTRIX3 was converted
-
-    void  Init();
-
-};
-
-
-//  ==================  CTVect  ========================
-
-DefineClass(CTVect)
-DefineStreamFunctions(CTVect)
-
-class CTVect : public CContainerClass  {
-
-  public :
-
-    int   serNum;   // serial number
-    vect3 t;        // translation vector
-    pstr  comment;  // comment
-
-    CTVect ();
-    CTVect ( cpstr S );
-    CTVect ( RPCStream Object );
-    ~CTVect();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_TVect; }
-
-    void  Copy  ( PCContainerClass TVect );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void  Init();
-
-};
-
-
-//  =================  CMMDBCryst  =======================
-
-DefineClass(CMMDBCryst);
-DefineStreamFunctions(CMMDBCryst);
-
-// constants for the CellCheck field
-#define CCHK_Ok            0x00000000
-#define CCHK_NoCell        0x00000001
-#define CCHK_Error         0x00000002
-#define CCHK_Disagreement  0x00000004
-#define CCHK_NoOrthCode    0x00000008
-#define CCHK_Translations  0x00000010
-#define CCHK_Unchecked     0x00001000
-
-// constants for the WhatIsSet field
-#define CSET_CellParams1   0x00000001
-#define CSET_CellParams2   0x00000002
-#define CSET_CellParams    0x00000003
-#define CSET_SpaceGroup    0x00000004
-#define CSET_ZValue        0x00000008
-#define CSET_CrystCard     0x0000000F
-#define CSET_OrigMatrix1   0x00000010
-#define CSET_OrigMatrix2   0x00000020
-#define CSET_OrigMatrix3   0x00000040
-#define CSET_OrigMatrix    0x00000070
-#define CSET_ScaleMatrix1  0x00000080
-#define CSET_ScaleMatrix2  0x00000100
-#define CSET_ScaleMatrix3  0x00000200
-#define CSET_ScaleMatrix   0x00000380
-#define CSET_Transforms    0x00000400
-#define CSET_DummyCell     0x00001000
-
-extern cpstr OrthCode[6];
-
-class CMMDBCryst : public CStream  {
-
-  friend class CChannel;
-
-  public :
-
-    realtype  a,b,c;            // cell parameters
-    realtype  alpha,beta,gamma; // cell parameters
-    mat44     RO,RF;            // orthogonal-fractional recalculation
-                                //   matrices
-    mat44     ROU,RFU;          // ort-frac recalc matrices for
-                                //   anisotr. t-fac
-    mat633    RR;               // standard orthogonalizations
-    realtype  Vol;              // cell volume
-    int       NCode;            // code of orthogonalization matrix
-    SymGroup  spaceGroup;       // group of space symmetry as read
-                                //    from file
-    SymGroup  spaceGroupFix;    // actually used space group
-    int       Z;                // Z-value
-
-    mat33     o;                // orthogonal transformation matrix
-    vect3     t;                // translation orthogonal vector
-    mat33     s;                // scale matrix
-    vect3     u;                // translation part of the scale matrix
-
-    word      CellCheck;        // 0x0000 - Ok
-                                // 0x0001 - no cell stored
-                                // 0x0002 - some error in cell volume
-                                // 0x0004 - disagreement between
-                                //           cell and PDB
-                                // 0x0008 - no orth code derived
-                                // 0x0010 - translations also specified
-                                // 0x1000 - the check was not done
-    word      WhatIsSet;        // indicator of the fields set
-    Boolean   ignoreScalei;     // flag to ignore SCALEi cards
-    Boolean   processSG;        // flag to process space group at file
-                                // read
-    Boolean   fixSpaceGroup;    // flag to fix space group at file read
-
-    CMMDBCryst ();
-    CMMDBCryst ( RPCStream Object );
-    ~CMMDBCryst();
-
-    void  FreeMemory();
-    void  Reset     ();
-
-    //   ConvertPDBString(..) interprets an ASCII PDB line and fills
-    // the corresponding data fields. It returns zero if the line was
-    // successfully converted, otherwise returns a non-negative value
-    // of Error_XXXX.
-    //   PDBString must be not shorter than 81 characters.
-    int   ConvertPDBString ( pstr PDBString );
-
-    //   RWBROOKReadPrintout() may be invoked after reading PDB file
-    // for simulating the old RWBROOK messages and warnings
-    void  RWBROOKReadPrintout();
-
-    void  SetCell ( realtype cell_a,
-                    realtype cell_b,
-                    realtype cell_c,
-                    realtype cell_alpha,
-                    realtype cell_beta,
-                    realtype cell_gamma,
-                    int      OrthCode );
-    void  PutCell ( realtype cell_a,
-                    realtype cell_b,
-                    realtype cell_c,
-                    realtype cell_alpha,
-                    realtype cell_beta,
-                    realtype cell_gamma,
-                    int      OrthCode );
-
-    void  GetCell ( realtype & cell_a,
-                    realtype & cell_b,
-                    realtype & cell_c,
-                    realtype & cell_alpha,
-                    realtype & cell_beta,
-                    realtype & cell_gamma,
-                    realtype & vol );
-
-    void  GetRCell ( realtype & cell_as,
-                     realtype & cell_bs,
-                     realtype & cell_cs,
-                     realtype & cell_alphas,
-                     realtype & cell_betas,
-                     realtype & cell_gammas,
-                     realtype & vols );
-
-    void  SetSyminfoLib ( cpstr syminfoLib );
-    pstr  GetSyminfoLib ();
-
-    int   SetSpaceGroup ( cpstr spGroup );
-    pstr  GetSpaceGroup ();
-    pstr  GetSpaceGroupFix();
-
-    //   CalcCoordTransforms() should be called once after all data
-    // relevant to the crystallographic information, are read and
-    // converted. Field CellCheck will then have bits set if there
-    // are errors, e.g. bit CCHK_NoCell means that the coordinate
-    // transformations cannot be performed.
-    void  CalcCoordTransforms();
-
-    // A PDB ASCII dump
-    void  PDBASCIIDump ( RCFile f );
-
-    int   GetCIF  ( PCMMCIFData CIF );
-    void  MakeCIF ( PCMMCIFData CIF );
-
-    Boolean areMatrices();  // returns True if the orthogonal-to-
-                            // fractional and fractional-to-orthogonal
-                            // matrices are defined
-
-    //   Frac2Orth(..) and Orth2Frac(..) transform between fractional
-    // and orthogonal coordinates, if areMatrices() returns True.
-    // If the transformation matrices were not set, the functions just
-    // copy the coordinates.  Returns True if the transformation was
-    // done; False return means that transformation matrices were not
-    // calculated
-    Boolean Frac2Orth (
-              realtype x,    realtype y,    realtype z,
-              realtype & xx, realtype & yy, realtype & zz );
-    Boolean Orth2Frac (
-              realtype x,    realtype y,    realtype z,
-              realtype & xx, realtype & yy, realtype & zz );
-
-    //   Below, F and T are transformation matrices in fractional and
-    // orthogonal coordinates, respectively.
-    Boolean Frac2Orth ( mat44 & F, mat44 & T );
-    Boolean Orth2Frac ( mat44 & T, mat44 & F );
-
-
-    //   Cryst2Orth(..) and Orth2Cryst(..) transform between fractional
-    // and orthogonal anisotropic temperature factors, if areMatrices()
-    // returns True. If the transformation matrices were not set, the
-    // functions leave the factors unchanged.
-    //   Vector U is composed as follows:
-    //      U[0]=u11   U[1]=u22   U[2]=u33
-    //      U[3]=u12   U[4]=u13   U[5]=u23
-    // Returns True if the transformation was done; False retuen
-    // means that transformation matrices were not calculated
-    Boolean Cryst2Orth ( rvector U );
-    Boolean Orth2Cryst ( rvector U );
-
-    void  CalcOrthMatrices();  // calculates RR, AC, cella's and Vol
-
-    Boolean  isNCSMatrix     ();
-    Boolean  isScaleMatrix   ();
-    Boolean  isCellParameters();
-
-    int      GetNumberOfSymOps();
-    pstr     GetSymOp ( int Nop );
-
-    int      GetNumberOfNCSMatrices();
-    int      GetNumberOfNCSMates   ();  // Returns the number of
-                                        // NCS mates not given in
-                                        // the file (iGiven==0)
-
-    Boolean  GetNCSMatrix ( int NCSMatrixNo, mat33 & ncs_m,
-                            vect3 & ncs_v );
-    Boolean  GetNCSMatrix ( int NCSMatrixNo, mat44 & ncs_m,
-                            int & iGiven ); // no=0..N-1
-    int      AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v, int iGiven );
-
-    //  GetTMatrix(..) calculates and returns the coordinate
-    //  transformation matrix, which converts orthogonal coordinates
-    //  according to the symmetry operation number Nop and places
-    //  them into unit cell shifted by cellshift_a a's, cellshift_b
-    //  b's and cellshift_c c's.
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    int   GetTMatrix ( mat44 & TMatrix, int Nop,
-                       int cellshift_a, int cellshift_b,
-                       int cellshift_c, PCSymOps symOpers=NULL );
-
-    //  GetUCTMatrix(..) calculates and returns the coordinate
-    //  transformation matrix, which converts orthogonal coordinates
-    //  according to the symmetry operation Nop. Translation part
-    //  of the matrix is  being chosen such that point (x,y,z) has
-    //  least distance to the center of primary (333) unit cell,
-    //  and then it is shifted by cellshift_a a's, cellshift_b b's
-    //  and cellshift_c c's.
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    //
-    int   GetUCTMatrix ( mat44 & TMatrix, int Nop,
-                         realtype x, realtype y, realtype z,
-                         int cellshift_a, int cellshift_b,
-                         int cellshift_c, PCSymOps symOpers=NULL );
-
-    //  GetFractMatrix(..) calculates and returns the coordinate
-    //  transformation matrix, which converts fractional coordinates
-    //  according to the symmetry operation number Nop and places them
-    //  into unit cell shifted by cellshift_a a's, cellshift_b b's and
-    //  cellshift_c c's.
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    int   GetFractMatrix ( mat44 & TMatrix, int Nop,
-                           int cellshift_a, int cellshift_b,
-                           int cellshift_c, PCSymOps symOpers=NULL );
-
-    //  GetSymOpMatrix(..) returns the transformation matrix for
-    //  Nop-th symmetry operator in the space group
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    //
-    int   GetSymOpMatrix ( mat44 & TMatrix, int Nop );
-
-    void  Copy  ( PCMMDBCryst Cryst );
-
-    void  write ( RCFile f );    // writes header to PDB binary file
-    void  read  ( RCFile f );    // reads header from PDB binary file
-
-  protected :
-
-    CCrystContainer NCSMatrix;      // non-cryst. symm. matrices
-    CCrystContainer TVect;          // translation vectors
-
-    realtype  as,bs,cs;             // calculated 'cell parameters'
-    realtype  alphas,betas,gammas;  // calculated 'cell parameters'
-    realtype  AC[6];
-    realtype  VolChk,VolErr;
-
-    pstr      syminfo_lib;          // path to syminfo.lib
-    CSymOps   SymOps;               // symmetry operations
-
-    void  Init ( Boolean fullInit );
-    int   FixSpaceGroup();
-
-};
-
-extern cpstr getOrthCodeName ( int NCode );
-
-/*
-extern void  TestCryst();  //  reads from 'in.cryst', writes into
-                           //  'out.cryst' and 'abin.cryst'
-*/
-
-#endif
-
diff --git a/mmdb/mmdb_defs.h b/mmdb/mmdb_defs.h
deleted file mode 100755
index 1d9908f..0000000
--- a/mmdb/mmdb_defs.h
+++ /dev/null
@@ -1,259 +0,0 @@
-//  $Id: mmdb_defs.h,v 1.27 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    23.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_Defs <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//      Definition of types, constants and important classes.
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Defs__
-#define __MMDB_Defs__
-
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-#define MMDB_MAJOR_VERSION    (1)
-#define MMDB_MINOR_VERSION    (25)
-#define MMDB_MICRO_VERSION    (5)
-
-
-//  =======================  types  =================================
-
-typedef  char         IDCode  [16];   // ID code of the entry
-typedef  IDCode *     PIDCode;        // pointer to ID code
-typedef  PIDCode &    RPIDCode;       // ref-ce to pointer to ID code
-typedef  char         Date    [12];   // date DD-MMM-YYYY
-typedef  char         RecName [7];    // name of PDB record
-
-typedef  char         ChainID [10];   // chain ID
-typedef  ChainID *    PChainID;       // pointer to chain ID
-typedef  char         InsCode [10];   // insertion code
-typedef  char         DBName  [10];   // sequence database name
-typedef  char         DBAcCode[20];   // seq. database accession code
-typedef  DBAcCode *   PDBAcCode;      // pointer to seq. db acc code
-typedef  char         DBIdCode[20];   // seq. database ident-n code
-typedef  DBIdCode *   PDBIdCode;      // pointer to DBIdCode
-typedef  char         ResName [20];   // residue name
-typedef  ResName  *   PResName;       // pointer to residue name
-typedef  PResName *   PPResName;      // ptr to vector of residue names
-typedef  char         HelixID [20];   // helix ID
-typedef  char         StrandID[20];   // strand ID
-typedef  char         SheetID [20];   // sheet ID
-typedef  char         TurnID  [20];   // turn ID
-typedef  char         LinkRID [20];   // Refmac link ID
-
-typedef  char         SymGroup[100];  // group of space symmetry
-typedef  realtype     vect3   [3];    // vector of 3 real numbers
-typedef  vect3    *   pvect3;
-typedef  pvect3   &   rpvect3;
-typedef  realtype     vect4   [4];    // vector of 4 real numbers
-typedef  vect3        mat33   [3];    // matrix 3x3 of real numbers
-
-typedef  vect4        mat44   [4];    // matrix 4x4 of real numbers
-typedef  mat44    *   pmat44;
-typedef  mat44    &   rmat44;
-typedef  pmat44   *   ppmat44;
-typedef  pmat44   &   rpmat44;
-typedef  mat33        mat633  [6];    // matrix 6x3x3 of real numbers
-
-typedef  char         AtomName[20];   // name of the atom
-typedef  AtomName *   PAtomName;      // pointer to atom name
-typedef  char         AltLoc  [20];   // alternate location indicator
-typedef  AltLoc   *   PAltLoc;        // pointer to alt loc indicator
-typedef  char         SegID   [20];   // segment identifier
-typedef  char         Element [10];   // chemical element name
-typedef  Element  *   PElement;       // ptr to chemical element name
-typedef  char         EnergyType[10]; // energy type name
-typedef  EnergyType * PEnergyType;    // pointer to energy type name
-
-// do not forget update this when change the above typedefs:
-#define MaxMMDBNameLength  40
-typedef  char     maxMMDBName[MaxMMDBNameLength];
-
-
-//  =====================  constants  ===============================
-
-//   ANY_RES should be used in selection functions for specifying
-// "any residue" to select
-#define ANY_RES  MinInt4
-
-//    PRNK_XXXXX are the print keys. PRNK_Silent supresses all print
-// inside mmdb_xxxx unless specifically ordered or catastrophic.
-// PRNK_SimRWBROOK instructs mmdb to issue, whenever possible and
-// necessary, printouts and warnings of RWBROOK (fortran) package.
-#define  PRNK_Silent                0
-#define  PRNK_SimRWBROOK            1
-
-//  Error_XXXX may be returned by XX::ConvertPDBString() and GetCIF(..)
-// functions.
-//  Error_WrongSection is returned if the string passed into function
-// does not belong to the corresponding PDB section.
-
-#define  Error_NoError               0
-#define  Error_Ok                    0
-#define  Error_WrongSection          1
-
-#define  Error_WrongChainID          2
-#define  Error_WrongEntryID          3
-
-//  Error_SEQRES_serNum is returned by CSeqRes::ConvertPDBASCII() if
-//  serial numbers of SEQRES records do not increment by 1
-#define  Error_SEQRES_serNum         4
-
-//  Error_SEQRES_numRes is returned by CSeqRes::ConvertPDBASCII() if
-//  SEQRES records show different number of residues
-#define  Error_SEQRES_numRes         5
-
-//  Error_SEQRES_extraRes is returned by CSeqRes::ConvertPDBASCII() if
-//  SEQRES contains more residues than specified
-#define  Error_SEQRES_extraRes       6
-
-#define  Error_NCSM_Unrecognized     7
-#define  Error_NCSM_AlreadySet       8
-#define  Error_NCSM_WrongSerial      9
-#define  Error_NCSM_UnmatchIG       10
-
-#define  Error_ATOM_Unrecognized    11
-#define  Error_ATOM_AlreadySet      12
-#define  Error_ATOM_NoResidue       13
-#define  Error_ATOM_Unmatch         14
-
-#define  Error_CantOpenFile         15
-#define  Error_UnrecognizedInteger  16
-#define  Error_WrongModelNo         17
-#define  Error_DuplicatedModel      18
-#define  Error_NoModel              19
-#define  Error_ForeignFile          20
-#define  Error_WrongEdition         21
-
-//  CIF specific
-#define  Error_NotACIFFile          22
-#define  Error_NoData               23
-#define  Error_UnrecognCIFItems     24
-#define  Error_MissingCIFField      25
-#define  Error_EmptyCIFLoop         26
-#define  Error_UnexpEndOfCIF        27
-#define  Error_MissgCIFLoopField    28
-#define  Error_NotACIFStructure     29
-#define  Error_NotACIFLoop          30
-#define  Error_UnrecognizedReal     31
-
-#define  Error_NoSheetID            32
-#define  Error_WrongSheetID         33
-#define  Error_WrongStrandNo        34
-
-//   Error_WrongNumberOfStrands may be issued when reading
-// sheet data from CIF
-#define  Error_WrongNumberOfStrands 35
-
-//   Error_WrongSheetOrder may be issued when reading
-// sheet data from CIF
-#define  Error_WrongSheetOrder      36
-
-//   Error_HBondInconsistency may be issued when reading
-// sheet data from CIF
-#define  Error_HBondInconsistency   37
-
-//   Error_EmptyResidueName is issued when PDB ATOM record
-// does not have a residue name
-#define  Error_EmptyResidueName     38
-
-//   Error_DuplicateSeqNum is issued when PDB ATOM records
-// show the sequence number and insertion code assigned
-// to more than one residue name
-#define  Error_DuplicateSeqNum      39
-
-//   Error_NoLogicalName may be returned by file i/o functions
-// if the specified environmental variable for file name
-// is not found.
-#define  Error_NoLogicalName        40
-
-//   Error_EmptyFile may be returned at reading non-existing
-// coordinate files
-#define  Error_EmptyFile            41
-
-
-//   Error_CIF_EmptyRow is the event of encountering
-// an empty row in _atom_site loop. It is handled
-// internally and has no effect on API
-#define  Error_CIF_EmptyRow      99999
-
-#define  Error_GeneralError1     10000
-
-
-//  ClassID_XXXX are used by container classes for proper
-// creating containered classes when reading from binary file.
-
-enum ClassID {
-  ClassID_Template   ,
-  ClassID_String     ,
-  ClassID_ObsLine    ,
-  ClassID_TitleLine  ,
-  ClassID_CAVEAT     ,
-  ClassID_Compound   ,
-  ClassID_Source     ,
-  ClassID_ExpData    ,
-  ClassID_MdlType    ,
-  ClassID_Author     ,
-  ClassID_RevData    ,
-  ClassID_Supersede  ,
-  ClassID_Journal    ,
-  ClassID_Remark     ,
-  ClassID_DBReference,
-  ClassID_SeqAdv     ,
-  ClassID_ModRes     ,
-  ClassID_Het        ,
-  ClassID_NCSMatrix  ,
-  ClassID_TVect      ,
-  ClassID_Helix      ,
-  ClassID_Turn       ,
-  ClassID_Link       ,
-  ClassID_LinkR      ,
-  ClassID_CisPep
-};
-
-
-//  =====================  classes  ===============================
-
-DefineClass(CAtom)
-DefineClass(CResidue)
-DefineClass(CChain)
-DefineClass(CModel)
-DefineClass(CMMDBManager)
-
-
-#endif
-
diff --git a/mmdb/mmdb_file.cpp b/mmdb/mmdb_file.cpp
deleted file mode 100755
index 7eaa664..0000000
--- a/mmdb/mmdb_file.cpp
+++ /dev/null
@@ -1,3060 +0,0 @@
-//  $Id: mmdb_file.cpp,v 1.34 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    16.05.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_File  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBFile  ( macromolecular data file class )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include "string.h"
-#endif
-
-#ifndef  __STDLIB_H
-#include "stdlib.h"
-#endif
-
-#ifndef  __MMDB_File__
-#include "mmdb_file.h"
-#endif
-
-#ifndef  __MMDB_Atom__
-#include "mmdb_atom.h"
-#endif
-
-#ifndef  __MMDB_MMCIF__
-#include "mmdb_mmcif.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-#ifndef  __MMDB_Tables__
-#include "mmdb_tables.h"
-#endif
-
-
-//  =====================   CMMDBFile   =======================
-
-CMMDBFile::CMMDBFile() : CUDData()  {
-  InitMMDBFile();
-}
-
-CMMDBFile::CMMDBFile ( RPCStream Object ) : CUDData(Object)  {
-  InitMMDBFile();
-}
-
-CMMDBFile::~CMMDBFile()  {
-  FreeFileMemory();
-}
-
-void  CMMDBFile::InitMMDBFile()  {
-  nModels = 0;
-  Model   = NULL;
-  nAtoms  = 0;
-  AtmLen  = 0;
-  Atom    = NULL;
-  CIF     = NULL;
-  crModel = NULL;
-  crChain = NULL;
-  crRes   = NULL;
-  lcount  = 0;
-  strcpy ( S,"" );
-//  Flags   = 0x00000000;           // no special effects
-  Flags   = MMDBF_IgnoreElement;  // done at request for default
-  FType   = MMDB_FILE_Undefined;  // undefined file operation
-  Exclude = True;
-  ignoreRemarks     = False;  // used temporarily
-  allowDuplChID     = False;  // used temporarily
-  enforceUniqueChID = False;  // used temporarily
-  modelCnt          = 0;      // used only at reading files
-}
-
-
-void  CMMDBFile::FreeCoordMemory()  {
-  //int i;
-
-/*
-  //   All atoms are kept in array Atom. Models, chains
-  // and residues have only references to Atom and
-  // they do not dispose Atoms when disposed themselves.
-  //   It is important, however, to dispose Atom at
-  // still alive residues, because each atom wipes out
-  // reference to itself from the corresponding residue
-  // before it dies.
-  if (Atom)  {
-    for (i=0;i<AtmLen;i++)
-      if (Atom[i]) delete Atom[i];
-    delete Atom;
-  }
-  Atom    = NULL;
-  AtmLen  = 0;
-  nAtoms  = 0;
-*/
-  DeleteAllModels();
-  if (Model)  delete[] Model;
-  Model   = NULL;
-  nModels = 0;
-
-  crModel = NULL;
-  crChain = NULL;
-  crRes   = NULL;
-
-  if (Atom)  delete[] Atom;
-
-  Atom    = NULL;
-  AtmLen  = 0;
-  nAtoms  = 0;
-
-  modelCnt = 0;
-
-}
-
-void  CMMDBFile::FreeFileMemory()  {
-
-  FreeCoordMemory  ();
-  Title.FreeMemory ( False );
-  Cryst.FreeMemory ();
-
-  SA      .FreeContainer();
-  Footnote.FreeContainer();
-  SB      .FreeContainer();
-  SC      .FreeContainer();
-
-  if (CIF)  delete CIF;
-  CIF = NULL;
-
-  lcount = 0;
-  S[0]   = char(0);
-
-}
-
-// virtual to be served by MMDB manager classes
-void CMMDBFile::ResetManager() {
-  Cryst.Reset();
-}
-
-void CMMDBFile::SetFlag ( word Flag )  {
-  Flags |= Flag;
-  ignoreSegID            = (Flags & MMDBF_IgnoreSegID            ) != 0;
-  ignoreElement          = (Flags & MMDBF_IgnoreElement          ) != 0;
-  ignoreCharge           = (Flags & MMDBF_IgnoreCharge           ) != 0;
-  ignoreNonCoorPDBErrors = (Flags & MMDBF_IgnoreNonCoorPDBErrors ) != 0;
-  ignoreUnmatch          = (Flags & MMDBF_IgnoreUnmatch          ) != 0;
-  allowDuplChID          = (Flags & MMDBF_AllowDuplChainID       ) != 0;
-  enforceUniqueChID      = (Flags & MMDBF_EnforceUniqueChainID   ) != 0;
-  Cryst.processSG        = (Flags & MMDBF_DoNotProcessSpaceGroup ) == 0;
-  Cryst.fixSpaceGroup    = (Flags & MMDBF_FixSpaceGroup          ) != 0;
-}
-
-void CMMDBFile::RemoveFlag ( word Flag )  {
-  Flags &= ~Flag;
-  ignoreSegID            = (Flags & MMDBF_IgnoreSegID            ) != 0;
-  ignoreElement          = (Flags & MMDBF_IgnoreElement          ) != 0;
-  ignoreCharge           = (Flags & MMDBF_IgnoreCharge           ) != 0;
-  ignoreNonCoorPDBErrors = (Flags & MMDBF_IgnoreNonCoorPDBErrors ) != 0;
-  ignoreUnmatch          = (Flags & MMDBF_IgnoreUnmatch          ) != 0;
-  allowDuplChID          = (Flags & MMDBF_AllowDuplChainID       ) != 0;
-  enforceUniqueChID      = (Flags & MMDBF_EnforceUniqueChainID   ) != 0;
-  Cryst.processSG        = (Flags & MMDBF_DoNotProcessSpaceGroup ) == 0;
-  Cryst.fixSpaceGroup    = (Flags & MMDBF_FixSpaceGroup          ) != 0;
-}
-
-
-int  CMMDBFile::ReadPDBASCII1 ( cpstr PDBLFName,
-                                byte gzipMode )  {
-pstr FName;
-  FName = getenv ( PDBLFName );
-  if (FName)  return ReadPDBASCII ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-void CMMDBFile::ReadPDBLine ( RCFile f, pstr L, int maxlen )  {
-int     i;
-Boolean Done;
-  do {
-    f.ReadLine ( L,maxlen );
-    Done = True;
-    if (ignoreRemarks)  {
-      if (!strncasecmp(L,"REMARK",6))  Done = False;
-    }
-    if (Flags & MMDBF_IgnoreBlankLines)  {
-      i = 0;
-      while (L[i] && (L[i]==' '))  i++;
-      if (!L[i])  Done = False;
-    }
-    if ((Flags & MMDBF_IgnoreHash) && (L[0]=='#'))
-      Done = False;
-  } while ((!f.FileEnd()) && (!Done));
-  PadSpaces  ( L,80 );
-}
-
-int  CMMDBFile::ReadPDBASCII ( cpstr PDBFileName,
-                               byte gzipMode )  {
-CFile f;
-int   RC;
-
-  //  open the file as ASCII for reading
-  //  opening it in pseudo-binary mode helps reading various
-  //  line terminators for files coming from different platforms
-  f.assign ( PDBFileName,False,False,gzipMode );
-
-  if (f.reset(True)) {
-
-    RC = ReadPDBASCII ( f );
-    f.shut();
-
-  } else  {
-
-    RC =  Error_CantOpenFile;
-    ResetManager  ();
-    FreeFileMemory();
-    FType = MMDB_FILE_PDB;
-
-  }
-
-  return RC;
-
-}
-
-
-int  CMMDBFile::ReadPDBASCII ( RCFile f )  {
-PCContString ContString;
-word         cleanKey;
-int          RC,modNum;
-Boolean      fend;
-
-  //  remove previous data
-  ResetManager  ();
-  FreeFileMemory();
-
-  FType = MMDB_FILE_PDB;
-  SetFlag ( 0 );
-
-  if (f.FileEnd())  return Error_EmptyFile;
-
-  lcount = 1;  // line counter
-
-  // read title section
-  RC = 0;
-  ReadPDBLine ( f,S,sizeof(S) );
-  if (Flags & MMDBF_EnforceSpaces)  EnforceSpaces ( S );
-  do  {
-    if (!strncmp(S,"FTNOTE",6))  {
-      ContString = new CContString(S);
-      Footnote.AddData ( ContString );
-    } else  {
-      RC = Title.ConvertPDBString(S);
-      if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
-        RC = 0;
-      if (RC)  break;
-    }
-    fend = f.FileEnd();
-    if (!fend)  {
-      ReadPDBLine ( f,S,sizeof(S) );
-      lcount++;
-    }
-  } while (!fend);
-
-  if (RC!=Error_WrongSection)  return RC;
-
-  ignoreRemarks = (Flags & MMDBF_IgnoreRemarks)!=0;
-
-  // read primary structure section
-  SwitchModel ( 1 );
-  if (!crModel)  return Error_GeneralError1;
-  do {
-    if (!strncmp(S,"FTNOTE",6))  {
-      ContString = new CContString(S);
-      Footnote.AddData ( ContString );
-    } else  {
-      RC = crModel->ConvertPDBString ( S );
-      if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
-        RC = 0;
-      if (RC)  break;
-    }
-    fend = f.FileEnd();
-    if (!fend)  {
-      ReadPDBLine ( f,S,sizeof(S) );
-      Title.TrimInput ( S );
-      lcount++;
-    }
-  } while (!fend);
-
-  if (RC!=Error_WrongSection)  return RC;
-
-  // temporary solution: the rest of file is stored
-  // in the form of strings
-  while (!f.FileEnd()          &&
-         strncmp(S,"CRYST" ,5) &&
-         strncmp(S,"ORIGX" ,5) &&
-         strncmp(S,"SCALE" ,5) &&
-         strncmp(S,"MTRIX" ,5) &&
-         strncmp(S,"TVECT" ,5) &&
-         strncmp(S,"MODEL ",6) &&
-         strncmp(S,"ATOM  ",6) &&
-         strncmp(S,"SIGATM",6) &&
-         strncmp(S,"ANISOU",6) &&
-         strncmp(S,"SIGUIJ",6) &&
-         strncmp(S,"TER   ",6) &&
-         strncmp(S,"HETATM",6) &&
-         strncmp(S,"ENDMDL",6))  {
-    if (!strncmp(S,"LINK  ",6))
-      crModel->ConvertPDBString ( S );
-    else if (!strncmp(S,"LINKR ",6))
-      crModel->ConvertPDBString ( S );
-    else if (!strncmp(S,"CISPEP",6)) {
-      GetInteger ( modNum,&(S[43]),3 );
-      if (modNum<=0)  modNum = 1;
-      if (modNum!=1)  SwitchModel ( modNum );
-      crModel->ConvertPDBString ( S );
-      if (modNum!=1)  SwitchModel ( 1 );
-    } else  {
-      ContString = new CContString(S);
-      SA.AddData ( ContString );
-    }
-    ReadPDBLine ( f,S,sizeof(S) );
-    Title.TrimInput ( S );
-    lcount++;
-  }
-
-  // read crystallographic information section
-  do {
-    RC = Cryst.ConvertPDBString ( S );
-    if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
-      RC = 0;
-    if (RC)  break;
-    fend = f.FileEnd();
-    if (!fend)  {
-      ReadPDBLine ( f,S,sizeof(S) );
-      Title.TrimInput ( S );
-      lcount++;
-    }
-  } while (!fend);
-
-  if (!RC)  {
-    RC = Cryst.ConvertPDBString ( S );
-    if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
-      RC = Error_WrongSection;
-  }
-
-  Cryst.CalcCoordTransforms();
-  if (Flags & MMDBF_SimRWBROOK)
-    Cryst.RWBROOKReadPrintout();
-
-  if (RC!=Error_WrongSection)  return RC;
-
-  // temporary solution: the rest of file is stored
-  // in the form of strings
-  while (!f.FileEnd()          &&
-         strncmp(S,"MODEL ",6) &&
-         strncmp(S,"ATOM  ",6) &&
-         strncmp(S,"SIGATM",6) &&
-         strncmp(S,"ANISOU",6) &&
-         strncmp(S,"SIGUIJ",6) &&
-         strncmp(S,"TER   ",6) &&
-         strncmp(S,"HETATM",6) &&
-         strncmp(S,"ENDMDL",6))  {
-    ContString = new CContString(S);
-    SB.AddData ( ContString );
-    ReadPDBLine ( f,S,sizeof(S) );
-    Title.TrimInput ( S );
-    lcount++;
-  }
-
-  if (Flags & MMDBF_NoCoordRead)  return 0;
-
-  // read coordinate section
-  RC = 0;
-  do {
-    RC = ReadPDBAtom ( S );
-    if (RC)  break;
-    fend = f.FileEnd();
-    if (!fend)  {
-      ReadPDBLine ( f,S,sizeof(S) );
-      Title.TrimInput ( S );
-      lcount++;
-    }
-  } while (!fend);
-//  if (!RC)
-//    RC = ReadPDBAtom(S);
-//  commented on 28.05.2004, it appears that "CHAIN_ORDER" should not
-//  be enforced here
-//  cleanKey = PDBCLEAN_ATNAME | PDBCLEAN_CHAIN_ORDER;
-  cleanKey = 0x00000000;
-  if (Flags & MMDBF_EnforceAtomNames)
-    cleanKey = PDBCLEAN_ATNAME;
-  if (Flags & MMDBF_AutoSerials)
-    cleanKey |= PDBCLEAN_SERIAL;
-
-  if (cleanKey)
-    PDBCleanup ( cleanKey );
-
-  if ((!f.FileEnd()) && (RC!=Error_WrongSection))  return RC;
-
-  // temporary solution: the rest of file is stored
-  // in the form of strings
-  while (!f.FileEnd())  {
-    if (strncmp(S,"END   ",6))  {  // END is added automatically
-      ContString = new CContString(S);
-      SC.AddData ( ContString );
-    }
-    ReadPDBLine ( f,S,sizeof(S) );
-    Title.TrimInput ( S );
-    lcount++;
-  }
-  lcount--;  // last line was not read
-
-  return 0;
-
-}
-
-
-int  CMMDBFile::ReadCIFASCII1 ( cpstr CIFLFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( CIFLFName );
-  if (FName)  return ReadCIFASCII ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int  CMMDBFile::ReadCIFASCII ( cpstr CIFFileName, byte gzipMode )  {
-CFile f;
-int   rc;
-
-  //  open the file as ASCII for reading
-  //  opening it in pseudo-binary mode helps reading various
-  //  line terminators for files coming from different platforms
-  f.assign ( CIFFileName,False,False,gzipMode );
-
-  if (f.reset(True)) {
-    rc = ReadCIFASCII ( f );
-    f.shut();
-  } else
-    rc = Error_CantOpenFile;
-
-  return rc;
-
-}
-
-int  CMMDBFile::ReadCIFASCII ( RCFile f )  {
-int  W;
-
-  //  remove previous data
-  ResetManager  ();
-  FreeFileMemory();
-  FType = MMDB_FILE_CIF;
-
-  SetFlag ( 0 );
-
-  CIFErrorLocation[0] = char(0);  // CIF reading phase
-
-  lcount = 0;  // line counter
-  S[0]   = char(0);
-
-  if (f.FileEnd())
-    return Error_EmptyFile;
-
-  if (!CIF)  CIF = new CMMCIFData();
-  CIF->SetStopOnWarning  ( True );
-  CIF->SetPrintWarnings  ( (Flags & MMDBF_PrintCIFWarnings)!=0 );
-  W = CIF->ReadMMCIFData ( f,S,lcount );
-
-  if (W)  {
-    if (W==CIFRC_NoDataLine)        return Error_NotACIFFile;
-    if (W & CIFW_UnrecognizedItems) return Error_UnrecognCIFItems;
-    if (W & CIFW_MissingField)      return Error_MissingCIFField;
-    if (W & CIFW_EmptyLoop)         return Error_EmptyCIFLoop;
-    if (W & CIFW_UnexpectedEOF)     return Error_UnexpEndOfCIF;
-    if (W & CIFW_LoopFieldMissing)  return Error_MissgCIFLoopField;
-    if (W & CIFW_NotAStructure)     return Error_NotACIFStructure;
-    if (W & CIFW_NotALoop)          return Error_NotACIFLoop;
-    return int(W);
-  }
-
-  W = ReadFromCIF ( CIF );
-  if (CIF)  {
-    delete CIF;
-    CIF = NULL;
-  }
-
-  return W;
-
-}
-
-
-int CMMDBFile::ReadFromCIF ( PCMMCIFData CIFD )  {
-PCMMCIFLoop  Loop1,Loop2;
-pstr         F,FC;
-word         cleanKey;
-int          RC,i,l,j,n,retc;
-
-  RC = Title.GetCIF ( CIFD );
-
-  if (RC)  {
-    CIFD->Optimize();
-    return RC;
-  }
-
-  SwitchModel ( 1 );
-  if (!crModel)  return Error_GeneralError1;
-  RC = crModel->GetCIF ( CIFD );
-  if (RC)  {
-    CIFD->Optimize();
-    return RC;
-  }
-
-  RC = Cryst.GetCIF ( CIFD );
-  if (RC)  {
-    CIFD->Optimize();
-    return RC;
-  }
-  Cryst.CalcCoordTransforms();
-  if (Flags & MMDBF_SimRWBROOK)
-    Cryst.RWBROOKReadPrintout();
-
-  RC = ReadCIFAtom ( CIFD );
-
-  Loop1 = CIFD->GetLoop ( CIFCAT_ENTITY      );
-  Loop2 = CIFD->GetLoop ( CIFCAT_STRUCT_ASYM );
-  if (Loop1 && Loop2)  {
-    // make 'Het' atoms
-    l = Loop1->GetLoopLength();
-    n = Loop2->GetLoopLength();
-    for (i=0;i<l;i++)  {
-      F = Loop1->GetString ( CIFTAG_TYPE,i,retc );
-      if (F && (!retc))  {
-        if (!strcasecmp(F,"non-polymer"))  {
-          F = Loop1->GetString ( CIFTAG_ID,i,retc );
-          if (F && (!retc))
-            for (j=0;j<n;j++)  {
-              FC = Loop2->GetString ( CIFTAG_ENTITY_ID,j,retc );
-              if (FC && (!retc))  {
-                if (!strcasecmp(FC,F))  {
-                  FC = Loop2->GetString ( CIFTAG_ID,j,retc );
-                  if (FC && (!retc))
-                    MakeHetAtoms ( FC,True );
-                }
-              }
-            }
-        }
-      }
-    }
-  }
-
-  if (!RC)  {
-    //  deleting these CIF loops here is a temporary solution
-    // taken in order to avoid mess at rewriting the CIF file.
-    CIFD->DeleteLoop ( CIFCAT_ATOM_SITE           );
-    CIFD->DeleteLoop ( CIFCAT_ATOM_SITE_ANISOTROP );
-    CIFD->Optimize   ();
-  }
-
-  cleanKey = 0x00000000;
-  if (Flags & MMDBF_EnforceAtomNames)
-    cleanKey = PDBCLEAN_ATNAME;
-  if (Flags & MMDBF_AutoSerials)
-    cleanKey |= PDBCLEAN_SERIAL;
-  if (cleanKey)
-    PDBCleanup ( cleanKey );
-
-  return RC;
-
-}
-
-int CMMDBFile::ReadCoorFile1 ( cpstr LFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( LFName );
-  if (FName)  return ReadCoorFile ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int CMMDBFile::ReadCoorFile ( cpstr CFName, byte gzipMode )  {
-// auto format recognition
-int     kin;
-Boolean IBL;
-
-  kin = isMMDBBIN ( CFName,gzipMode );
-  if (kin==Error_EmptyFile)
-              return Error_EmptyFile;
-  if (kin<0)  return Error_CantOpenFile;
-
-  if (kin==0) return  ReadMMDBF ( CFName,gzipMode );
-
-  IBL = ((Flags & MMDBF_IgnoreBlankLines)!=0);
-  if (isPDB(CFName,gzipMode,IBL)==0)
-    return ReadPDBASCII ( CFName,gzipMode );
-  if (isCIF(CFName,gzipMode)==0)
-    return ReadCIFASCII ( CFName,gzipMode );
-
-  return Error_ForeignFile;
-
-}
-
-
-int CMMDBFile::ReadCoorFile ( RCFile f )  {
-// auto format recognition
-int     kin;
-Boolean IBL;
-
-  kin = isMMDBBIN ( f );
-  f.reset ( True );
-  if (kin==Error_EmptyFile)
-              return Error_EmptyFile;
-  if (kin<0)  return Error_CantOpenFile;
-
-  if (kin==0) return  ReadMMDBF ( f );
-
-  IBL = ((Flags & MMDBF_IgnoreBlankLines)!=0);
-  kin = isPDB ( f,IBL );
-  f.reset ( True );
-  if (kin==0)
-    return ReadPDBASCII ( f );
-
-  kin = isCIF ( f );
-  f.reset ( True );
-  if (kin==0)
-    return ReadCIFASCII ( f );
-
-  return Error_ForeignFile;
-
-}
-
-
-word  CMMDBFile::PDBCleanup ( word CleanKey )  {
-//  cleans coordinate part to comply with PDB standards:
-//
-//    CleanKey          Action
-//  PDBCLEAN_ATNAME  pads atom names with spaces to form 4-symbol names
-//  PDBCLEAN_TER     inserts TER cards in the end of each chain
-//  PDBCLEAN_CHAIN   generates 1-character chain ids instead of
-//                   those many-character
-//  PDBCLEAN_CHAIN_STRONG generates 1-character chain ids starting
-//                   from 'A' on for all ids, including single-char
-//  PDBCLEAN_ALTCODE generates 1-character alternative codes instead
-//                   of those many-character
-//  PDBCLEAN_ALTCODE_STRONG generates 1-character alternative codes
-//                   from 'A' on for all codes, including
-//                   single-character ones
-//  PDBCLEAN_SERIAL  puts serial numbers in due order
-//  PDBCLEAN_INDEX   reorders the internal index of atoms such that
-//                   it follows the actual order of atoms in
-//                   the object hierarchy
-//  PDBCLEAN_SEQNUM  renumbers all residues so that they go
-//                   incrementally-by-one without insertion codes
-//  PDBCLEAN_CHAIN_ORDER puts chains in order of atom's serial numbers
-//  PDBCLEAN_SOLVENT moves solvent chains at the end of each model
-//  PDBCLEAN_ELEMENT calculates PDB element names where they are not
-//                   found in the chemical element table
-//  PDBCLEAN_ELEMENT_STRONG  calculates all chemical element names
-//
-//  Return codes (as bits):
-//  0                Ok
-//  PDBCLEAN_CHAIN   too many chains for assigning them 1-letter codes
-//  PDBCLEAN_ATNAME  element names were not available
-//  PDBCLEAN_ALTCODE too many alternative codes encountered.
-//
-word      RC;
-int       i,j,k,nal,nch,nr, nch1,nch2;
-char      c;
-AltLoc  * altLoc;
-ChainID * chain_ID;
-char      aLoc [257];
-char      chnID[257];
-int       model,modl;
-PPCAtom   Atom1;
-PPCChain  Chain1,Chain2;
-PCModel   crModel0;
-PCChain   crChain0;
-PCResidue crRes0;
-PCAtom    atom;
-pstr      chID;
-ChainID   chainID;
-Boolean   NewChain,Done,Solvent;
-
-  RC = 0;
-  if (nAtoms<=0)  return RC;
-
-  if (CleanKey & PDBCLEAN_ATNAME)
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])
-        if (!Atom[i]->MakePDBAtomName())  RC |= PDBCLEAN_ATNAME;
-
-  k = -1;
-
-  if (CleanKey & PDBCLEAN_TER)  {
-    model    = -1;
-    crModel0 = crModel;
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        modl = Atom[i]->GetModelNum();
-        chID = Atom[i]->GetChainID ();
-        if (model<0)  {
-          model = modl;
-          SwitchModel ( model );
-          if (chID)  strcpy ( chainID,chID );
-               else  chainID[0] = char(0);
-        } else  {
-          if (model!=modl)  NewChain = True;
-          else if (chID)    NewChain = strcmp(chID,chainID)!=0;
-                      else  NewChain = chainID[0]!=char(0);
-          if (NewChain)  {
-            if (k>=0)  {
-              if ((!Atom[k]->Ter) && (!Atom[k]->Het))  {
-                // insert 'Ter' before atom in position 'i'
-                PutAtom ( -(i+1),Atom[k]->serNum+1,pstr("TER"),
-                          Atom[k]->GetResName(),Atom[k]->GetChainID(),
-                          Atom[k]->GetSeqNum (),Atom[k]->GetInsCode(),
-                          pstr(" "),pstr(" "),pstr(" ") );
-                Atom[i]->MakeTer();
-              }
-            }
-            model = modl;
-            SwitchModel ( model );
-            if (chID)  strcpy ( chainID,chID );
-                 else  chainID[0] = char(0);
-          }
-        }
-        k = i;
-      }
-
-    if (k>=0)  {
-      if ((!Atom[k]->Ter) && (!Atom[k]->Het))  {  // add last TER
-        i = nAtoms;
-        SwitchModel ( Atom[k]->GetModelNum() );
-        PutAtom ( 0,nAtoms+1,pstr("TER"),Atom[k]->GetResName(),
-                  Atom[k]->GetChainID(),Atom[k]->GetSeqNum(),
-                  Atom[k]->GetInsCode(),pstr(" "),pstr(" "),
-                  pstr(" ") );
-        Atom[i]->MakeTer();
-      }
-    }
-
-    crModel = crModel0;
-  }
-
-
-  if (CleanKey & (PDBCLEAN_CHAIN | PDBCLEAN_CHAIN_STRONG))  {
-    chain_ID = new ChainID[256];
-    for (i=0;i<nModels;i++)
-      if (Model[i])  {
-        for (j=0;j<256;j++)  {
-          strcpy ( chain_ID[j]," " );
-          chnID[j] = char(0);
-        }
-        chnID[256] = char(0);
-        nch = 0;
-        for (j=0;j<Model[i]->nChains;j++)  {
-          crChain0 = Model[i]->Chain[j];
-          if (crChain0)  {
-            if (!crChain0->chainID[0])
-              strcpy ( crChain0->chainID," " );
-            k = 0;
-            while ((k<nch) && (strcmp(chain_ID[k],crChain0->chainID)))
-              k++;
-            if (k>=nch)  {
-              if (nch>=255)  RC |= PDBCLEAN_CHAIN;
-              else  {
-                strcpy ( chain_ID[nch],crChain0->chainID );
-                if (!chain_ID[nch][1])
-                  chnID[nch] = chain_ID[nch][0];
-                nch++;
-              }
-            }
-          }
-        }
-        c = 'A';
-        if (CleanKey & PDBCLEAN_CHAIN_STRONG)  {
-          // rename all chains through from A to Z
-          for (k=0;k<nch;k++)  {
-            chnID[k] = c;
-            c = char(int(c)+1);
-          }
-        } else  {
-          // rename only multi-character chain IDs
-          for (j=0;(j<nch) && (k<256);j++)  {
-            k = 0;
-            do  {
-              while ((k<nch) && (chnID[k]!=c))  k++;
-              if (k<nch)  c = char(int(c)+1);
-            } while (k<nch);
-            k = 0;
-            while ((k<256) && (chnID[k]))  k++;
-            if (k<256)  {
-              chnID[k] = c;
-              c = char(int(c)+1);
-            }
-          }
-        }
-        // assign new chain IDs
-        for (j=0;j<Model[i]->nChains;j++)  {
-          crChain0 = Model[i]->Chain[j];
-          if (crChain0)  {
-            k = 0;
-            while ((k<nch) && (strcmp(chain_ID[k],crChain0->chainID)))
-              k++;
-            strcpy ( crChain0->prevChainID,crChain0->chainID );
-            crChain0->chainID[0] = chnID[k];
-            crChain0->chainID[1] = char(0);
-          }
-        }
-      }
-    delete[] chain_ID;
-  }
-
-
-  if (CleanKey & (PDBCLEAN_ALTCODE | PDBCLEAN_ALTCODE_STRONG))  {
-    altLoc = new AltLoc[256];
-    for (i=0;i<256;i++)  {
-      strcpy ( altLoc[i]," " );
-      aLoc[i] = char(0);
-    }
-    aLoc[0]   = ' ';
-    aLoc[256] = char(0);
-    nal = 1;
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        if (!Atom[i]->altLoc[0])  strcpy ( Atom[i]->altLoc," " );
-        else  {
-          k = 0;
-          while ((k<nal) && (strcmp(altLoc[k],Atom[i]->altLoc)))  k++;
-          if (k>=nal)  {
-            if (nal>=255)  RC |= PDBCLEAN_ALTCODE;
-            else  {
-              strcpy ( altLoc[nal],Atom[i]->altLoc );
-              if (!altLoc[nal][1])  aLoc[nal] = altLoc[nal][0];
-              nal++;
-            }
-          }
-        }
-      }
-    c = 'A';
-    if (CleanKey & PDBCLEAN_ALTCODE_STRONG)
-      for (i=1;i<nal;i++)  {
-        aLoc[i] = c;
-        c = char(int(c)+1);
-      }
-    else
-      for (i=1;(i<nal) && (k<256);i++)  {
-        k = 0;
-        do  {
-          while ((k<nal) && (aLoc[k]!=c))  k++;
-          if (k<nal)  c = char(int(c)+1);
-        } while (k<nal);
-        k = 0;
-        while ((k<256) && (aLoc[k]))  k++;
-        if (k<256)  {
-          aLoc[k] = c;
-          c = char(int(c)+1);
-        }
-      }
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        k = 0;
-        while ((k<nal) && (strcmp(altLoc[k],Atom[i]->altLoc)))  k++;
-        Atom[i]->altLoc[0] = aLoc[k];
-        Atom[i]->altLoc[1] = char(0);
-      }
-    delete[] altLoc;
-  }
-
-
-  if (CleanKey & PDBCLEAN_SEQNUM)
-    for (i=0;i<nModels;i++)  {
-      crModel0 = Model[i];
-      if (crModel0)
-        for (j=0;j<crModel0->nChains;j++)  {
-          crChain0 = crModel0->Chain[j];
-          if (crChain0)  {
-            nr = 0;
-            for (k=0;k<crChain0->nResidues;k++)  {
-              crRes0 = crChain0->Residue[k];
-              if (crRes0)  {
-                nr++;
-                crRes0->seqNum     = nr;
-                crRes0->insCode[0] = char(0);
-              }
-            }
-          }
-        }
-    }
-
-  if (CleanKey & PDBCLEAN_SOLVENT)  {
-    Atom1 = new PCAtom[nAtoms];
-    k = 1;
-    for (i=0;i<nModels;i++)
-      if (Model[i])  {
-        if (Model[i]->nChains>k)  k = Model[i]->nChains;
-      }
-    Chain1 = new PCChain[k];
-    Chain2 = new PCChain[k];
-    k = 0;
-    for (i=0;i<nModels;i++)  {
-      crModel0 = Model[i];
-      if (crModel0)  {
-        nch1 = 0;
-        nch2 = 0;
-        for (nch=0;nch<crModel0->nChains;nch++)  {
-          crChain0 = crModel0->Chain[nch];
-          if (crChain0)  {
-            Solvent = False;
-            for (nr=0;(nr<crChain0->nResidues) && (!Solvent);nr++)  {
-              crRes0 = crChain0->Residue[nr];
-              if (crRes0)
-                for (j=0;(j<nSolventNames) && (!Solvent);j++)
-                  Solvent = !strcmp ( StdSolventName[j],crRes0->name );
-            }
-            if (Solvent)  Chain2[nch2++] = crChain0;
-                    else  Chain1[nch1++] = crChain0;
-          }
-        }
-        for (nch=0;nch<nch1;nch++)  {
-          crChain0 = Chain1[nch];
-          for (nr=0;nr<crChain0->nResidues;nr++)  {
-            crRes0 = crChain0->Residue[nr];
-            if (crRes0)
-              for (j=0;j<crRes0->nAtoms;j++)
-                if (crRes0->atom[j])  {
-                  Atom1[k] = crRes0->atom[j];
-                  Atom1[k]->index = k+1;
-                  k++;
-                }
-          }
-          crModel0->Chain[nch] = Chain1[nch];
-        }
-        for (nch=0;nch<nch2;nch++)  {
-          crChain0 = Chain2[nch];
-          for (nr=0;nr<crChain0->nResidues;nr++)  {
-            crRes0 = crChain0->Residue[nr];
-            if (crRes0)
-              for (j=0;j<crRes0->nAtoms;j++)
-                if (crRes0->atom[j])  {
-                  Atom1[k] = crRes0->atom[j];
-                  Atom1[k]->index = k+1;
-                  k++;
-                }
-          }
-          crModel0->Chain[nch1++] = Chain2[nch];
-        }
-        crModel0->nChains = nch1;
-      }
-    }
-    delete[] Chain1;
-    delete[] Chain2;
-    if (Atom)  delete[] Atom;
-    Atom   = Atom1;
-    AtmLen = nAtoms;
-    nAtoms = k;
-  }
-
-  if (CleanKey & (PDBCLEAN_CHAIN_ORDER | PDBCLEAN_CHAIN_ORDER_IX))  {
-    for (i=0;i<nModels;i++)  {
-      crModel0 = Model[i];
-      if (crModel0)  {
-        k = 0;
-        for (j=0;j<crModel0->nChains;j++)  {
-          crChain0 = crModel0->Chain[j];
-          if (crChain0)  {
-            crChain0->nWeights = 0;
-            crChain0->Weight   = 0.0;
-            if (k<j)  {
-              crModel0->Chain[k] = crModel0->Chain[j];
-              crModel0->Chain[j] = NULL;
-            }
-            k++;
-          }
-        }
-        crModel0->nChains = k;
-      }
-    }
-    if (CleanKey & PDBCLEAN_CHAIN_ORDER)
-      for (i=0;i<nAtoms;i++)
-        if (Atom[i])  {
-          crChain0 = Atom[i]->GetChain();
-          crChain0->nWeights++;
-          crChain0->Weight += Atom[i]->serNum;
-        }
-    else
-      for (i=0;i<nAtoms;i++)
-        if (Atom[i])  {
-          crChain0 = Atom[i]->GetChain();
-          crChain0->nWeights++;
-          crChain0->Weight += Atom[i]->GetIndex();
-        }
-    for (i=0;i<nModels;i++)  {
-      crModel0 = Model[i];
-      if (crModel0)  {
-        for (j=0;j<crModel0->nChains;j++)  {
-          crChain0 = crModel0->Chain[j];
-          if (crChain0->nWeights)
-            crChain0->Weight /= crChain0->nWeights;
-        }
-        //  bubble sorting
-        do {
-          Done = True;
-          for (j=1;j<crModel0->nChains;j++)
-            if (crModel0->Chain[j-1]->Weight >
-                crModel0->Chain[j]->Weight)  {
-              crChain0             = crModel0->Chain[j-1];
-              crModel0->Chain[j-1] = crModel0->Chain[j];
-              crModel0->Chain[j]   = crChain0;
-              Done = False;
-            }
-        } while (!Done);
-      }
-    }
-  }
-
-  if (CleanKey & PDBCLEAN_INDEX)  {
-    k = 0;
-    for (i=0;i<nModels;i++)  {
-      crModel0 = Model[i];
-      if (crModel0)  {
-        for (nch=0;nch<crModel0->nChains;nch++)  {
-          crChain0 = crModel0->Chain[nch];
-          if (crChain0)  {
-            for (nr=0;nr<crChain0->nResidues;nr++)  {
-              crRes0 = crChain0->Residue[nr];
-              if (crRes0)  {
-                for (j=0;j<crRes0->nAtoms;j++)  {
-                  atom = crRes0->atom[j];
-                  if (atom)  {
-                    Atom[atom->index-1] = Atom[k];
-                    if (Atom[k])
-                      Atom[k]->index = atom->index;
-                    Atom[k] = atom;
-                    k++;
-                    atom->index = k;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-    nAtoms = k;
-  }
-
-  if (CleanKey & PDBCLEAN_SERIAL)  {
-    k = 0;
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        if (k<i)  {
-          Atom[k] = Atom[i];
-          Atom[i] = NULL;
-        }
-        Atom[k]->index  = k+1;
-        Atom[k]->serNum = Atom[k]->index;
-        k++;
-      }
-    nAtoms = k;
-  }
-
-  if (CleanKey & PDBCLEAN_ELEMENT)  {
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i] && (!Atom[i]->Ter))  {
-        if (getElementNo(Atom[i]->element)==ELEMENT_UNKNOWN)  {
-          strcpy ( Atom[i]->element,"  " );
-          Atom[i]->MakePDBAtomName();
-        }
-      }
-  }
-
-  if (CleanKey & PDBCLEAN_ELEMENT_STRONG)  {
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i] && (!Atom[i]->Ter))  {
-        strcpy ( Atom[i]->element,"  " );
-        Atom[i]->MakePDBAtomName();
-      }
-  }
-
-  return RC;
-
-}
-
-void  CMMDBFile::MakeHetAtoms ( cpstr chainID, Boolean Make )  {
-//  Makes all atoms in chain 'chainID', in all models, as 'Het' atoms
-//  if Make is set True, and makes them 'ordinary' atoms otherwise.
-//  'Ter' is automatically removed when converting to 'Het' atoms,
-//  and is automatically added when converting to 'ordinary' atoms.
-int       i,j,k,l,n;
-PCModel   crModel0;
-PCChain   crChain0;
-PCResidue crRes0;
-  crModel0 = crModel;
-  for (i=0;i<nModels;i++)
-    if (Model[i])
-      for (j=0;j<Model[i]->nChains;j++)  {
-        crChain0 = Model[i]->Chain[j];
-        if (crChain0)  {
-          if (!strcmp(crChain0->chainID,chainID))  {
-            n = 0;
-            for (k=0;k<crChain0->nResidues;k++)  {
-              crRes0 = crChain0->Residue[k];
-              if (crRes0)
-                for (l=0;l<crRes0->nAtoms;l++)
-                  if (crRes0->atom[l])  {
-                    crRes0->atom[l]->Het = Make;
-                    n = crRes0->atom[l]->index;
-                  }
-            }
-            if (n>0)  {
-              n--;
-              if (Atom[n]->Het && Atom[n]->Ter)  RemoveAtom ( n+1 );
-              else if ((!Atom[n]->Het) && (!Atom[n]->Ter))  {
-                SwitchModel ( Model[i]->GetSerNum() );
-                if (n<nAtoms-1)
-                  PutAtom ( -(n+2),Atom[n]->serNum+1,pstr("TER"),
-                          Atom[n]->GetResName(),Atom[n]->GetChainID(),
-                          Atom[n]->GetSeqNum (),Atom[n]->GetInsCode(),
-                          pstr(" "),pstr(" "),pstr(" ") );
-                else
-                  PutAtom ( 0,nAtoms+1,pstr("TER"),
-                          Atom[n]->GetResName(),Atom[n]->GetChainID(),
-                          Atom[n]->GetSeqNum (),Atom[n]->GetInsCode(),
-                          pstr(" "),pstr(" "),pstr(" ") );
-                Atom[n+1]->MakeTer();
-              }
-            }
-          }
-        }
-      }
-  crModel = crModel0;
-}
-
-
-void CMMDBFile::RemoveAtom ( int index )  {
-//    Removes atom at the specified index in the Atom array.
-// This index is always accessible as Atom[index]->index.
-// If this leaves a residue empty, the residue is removed.
-// If this leaves an empty chain, the chain is removed as well;
-// the same happens to the model.
-PCResidue crRes0;
-PCChain   crChain0;
-PCModel   crModel0;
-int       i,j;
-
-  if ((index>0) && (index<=nAtoms))  {
-    if (Atom[index-1])  {
-      crRes0 = Atom[index-1]->residue;
-      if (crRes0)  {
-        if (crRes0->_ExcludeAtom(index))  {
-          // the residue appears empty after the exclusion
-          if (crRes)  {
-            if ((crRes->seqNum==crRes0->seqNum) &&
-                (!strcmp(crRes->insCode,crRes0->insCode)))
-              crRes = NULL;
-          }
-          crChain0 = crRes0->chain;
-          if (crChain0)  {
-            if (crChain0->_ExcludeResidue(crRes0->name,crRes0->seqNum,
-                                          crRes0->insCode))  {
-              // the chain appears empty after the exclusion
-              if (crChain)  {
-                if (!strcmp(crChain->chainID,crChain0->chainID))
-                  crChain = NULL;
-              }
-              crModel0 = PCModel(crChain0->model);
-              if (crModel0)  {
-                if (crModel0->_ExcludeChain(crChain0->chainID))  {
-                  // the model appears ampty after the exclusion
-                  if (crModel)  {
-                    if (crModel->serNum==crModel0->serNum)
-                      crModel = NULL;
-                  }
-                  i = crModel0->serNum-1;
-                  delete Model[i];
-                  Model[i] = NULL;
-                }
-              }
-              delete crChain0;  // it is already excluded from the hierarchy!
-            }
-          }
-          delete crRes0;  // it is already excluded from the hierarchy!
-        }
-      }
-      delete Atom[index-1];  // it is already excluded from the hierarchy!
-      Atom[index-1] = NULL;
-      // now rearrange and re-index atoms.
-      j = 0;
-      for (i=0;i<nAtoms;i++)
-        if (Atom[i])  {
-          if (j<i)  {
-            Atom[j] = Atom[i];
-            Atom[i] = NULL;
-          }
-          Atom[j]->index = j+1;
-          j++;
-        }
-      nAtoms = j;
-    }
-  }
-}
-
-
-int  CMMDBFile::_ExcludeModel ( int serNum )  {
-//   _ExcludeModel(..) excludes (but does not dispose!) a model
-// from the file. Returns 1 if the file gets empty and 0 otherwise.
-int  i,k;
-
-  if (!Exclude)  return 0;
-
-  if ((0<serNum) && (serNum<=nModels))
-    Model[serNum-1] = NULL;
-
-  k = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  {
-      if (k<i)  {
-        Model[k] = Model[i];
-        Model[i] = NULL;
-      }
-      Model[k]->serNum = k+1;
-      k++;
-    }
-
-  nModels = k;
-
-  if (nModels<=0)  return 1;
-             else  return 0;
-
-}
-
-
-int  CMMDBFile::FinishStructEdit()  {
-// Makes a new atom index after insertion or deletion of atoms.
-// This function may change atoms' positions in the index and
-// correspondingly the CAtom::index field.
-PCResidue res;
-PCChain   chain;
-PCModel   model;
-PPCAtom   Atom1;
-int       i,j,k,l,n,index,nAtoms1;
-
-  //  calculate new number of atoms
-  nAtoms1 = 0;
-  for (i=0;i<nModels;i++)  {
-    model = Model[i];
-    if (model)  {
-      for (j=0;j<model->nChains;j++)  {
-        chain = model->Chain[j];
-        if (chain)  {
-          for (k=0;k<chain->nResidues;k++)  {
-            res = chain->Residue[k];
-            if (res)  {
-              res->TrimAtomTable();
-              nAtoms1 += res->nAtoms;
-            }
-          }
-          chain->TrimResidueTable();
-        }
-      }
-      model->TrimChainTable();
-    }
-  }
-  TrimModelTable();
-
-  // compile a new index and null the old one
-
-  if (nAtoms1>0)  Atom1 = new PCAtom[nAtoms1];
-            else  Atom1 = NULL;
-
-  n = 0;
-  for (i=0;i<nModels;i++)  {
-    model = Model[i];
-    for (j=0;j<model->nChains;j++)  {
-      chain = model->Chain[j];
-      for (k=0;k<chain->nResidues;k++)  {
-        res = chain->Residue[k];
-        for (l=0;l<res->nAtoms;l++)  {
-          Atom1[n] = res->atom[l];
-          index    = Atom1[n]->index;
-          if ((index>0) && (index<=AtmLen))
-            Atom[index-1] = NULL;
-          Atom1[n]->index = n+1;
-          n++;
-        }
-      }
-    }
-  }
-
-//  if (n!=nAtoms1)  {
-//    printf ( " **** PROGRAM ERROR IN CMMDBFile::FinishStructEdit\n" );
-//    exit ( 1 );
-//  }
-
-
-  // check if there are dead atoms in the old index
-  for (i=0;i<AtmLen;i++)
-    if (Atom[i])  delete Atom[i];
-
-  // dispose old index and replace it with the new one
-  if (Atom)  delete[] Atom;
-
-  Atom   = Atom1;
-  AtmLen = n;
-  nAtoms = n;
-
-  if (n==nAtoms1)  return 0;  // Ok
-             else  return 1;  // not Ok; should never happen
-
-}
-
-void CMMDBFile::TrimModelTable()  {
-int i,j;
-  j = 0;
-  for (i=0;i<nModels;i++)
-    if (Model[i])  {
-      if (j<i)  {
-        Model[j] = Model[i];
-        Model[i] = NULL;
-      }
-      Model[j]->serNum = j+1;
-      j++;
-    }
-  nModels = j;
-}
-
-
-int  CMMDBFile::GenerateNCSMates()  {
-//
-//   Generates NCS mates according to NCS matrices given
-// in Cryst. This will result in generating many-character
-// chain names, composed as 'x_n' where 'x' is the original
-// name and 'n' is a unique number, which will coincide with
-// the symmetry operation (order) number. Another side
-// effect will be a disorder in atoms' serial numbers.
-//   The hierarchy should therefore be cleaned after
-// generating the NCS mates. An appropriate way to do that
-// is to issue the following call:
-//
-//   PDBCleanup ( PDBCLEAN_TER | PDBCLEAN_ALTCODE_STRONG |
-//                PDBCLEAN_CHAIN_STRONG | PDBCLEAN_SERIAL );
-//
-PPCChain chainTable,chain;
-PCChain  chn;
-mat44    ncs_m;
-ChainID  chainID;
-int      i,j,k,nNCSOps,nChains,iGiven;
-
-  nNCSOps = Cryst.GetNumberOfNCSMatrices();
-  if (nNCSOps<=0)  return 1;
-
-  for (i=0;i<nModels;i++)
-    if (Model[i])  {
-      Model[i]->GetChainTable ( chainTable,nChains );
-      if (nChains>0)  {
-        chain = new PCChain[nChains];
-        for (j=0;j<nChains;j++)
-          chain[j] = chainTable[j];
-        for (j=0;j<nChains;j++)
-          if (chain[j])  {
-            for (k=0;k<nNCSOps;k++)
-              if (Cryst.GetNCSMatrix(k,ncs_m,iGiven))  {
-                if (!iGiven)  {
-                  chn = newCChain();
-                  chn->Copy ( chain[j] );
-                  sprintf ( chainID,"%s_%i",
-                            chain[j]->GetChainID(),k+1 );
-                  chn->SetChainID     ( chainID );
-                  chn->ApplyTransform ( ncs_m   );
-                  Model[i]->AddChain  ( chn     );
-                }
-              }
-          }
-        delete[] chain;
-      }
-    }
-
-  return 0;
-
-}
-
-
-void  CMMDBFile::ApplyNCSTransform ( int NCSMatrixNo )  {
-mat33 t;
-vect3 v;
-int   i;
-  if (!Cryst.GetNCSMatrix(NCSMatrixNo,t,v))  return;
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])  Atom[i]->Transform ( t,v );
-}
-
-
-int  CMMDBFile::PutPDBString ( cpstr PDBString )  {
-int          RC;
-PCContString ContString;
-
-  strcpy    ( S,PDBString );  // maintain the buffer!
-  PadSpaces ( S,80 );
-  lcount++;
-
-  // belongs to title?
-  RC = Title.ConvertPDBString ( S );
-  if (RC!=Error_WrongSection)  return RC;
-
-  // belongs to primary structure section?
-  SwitchModel ( 1 );
-  RC = crModel->ConvertPDBString ( S );
-  if (RC!=Error_WrongSection)  return RC;
-
-  // belongs to the crystallographic information section?
-  RC = Cryst.ConvertPDBString ( S );
-  if (RC!=Error_WrongSection)  {
-//    if (RC==0)  Cryst.CalcCoordTransforms();
-    return RC;
-  }
-
-  // belongs to the coordinate section?
-  RC = ReadPDBAtom ( S );
-  if (RC!=Error_WrongSection)  return RC;
-
-  // temporary solution: the rest of file is stored
-  // in the form of strings
-  if ((S[0]) && (S[0]!=' ') && (strncmp(S,"END   ",6)))  {
-    // END is added automatically
-    ContString = new CContString(S);
-    SC.AddData ( ContString );
-  }
-
-  return 0;
-
-}
-
-
-int  CMMDBFile::AddPDBASCII1 ( cpstr PDBLFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( PDBLFName );
-  if (FName)  return AddPDBASCII ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int  CMMDBFile::AddPDBASCII ( cpstr PDBFileName, byte gzipMode ) {
-int   RC;
-CFile f;
-  //  open the file as ASCII for reading
-  //  opening it in pseudo-binary mode helps reading various
-  //  line terminators for files coming from different platforms
-  f.assign ( PDBFileName,False,False,gzipMode );
-  if (f.reset(True)) {
-    lcount = 1;  // line counter
-    RC     = 0;
-    while ((!f.FileEnd()) && (!RC))  {
-      ReadPDBLine ( f,S,sizeof(S) );
-      RC = PutPDBString ( S );
-    }
-    f.shut();
-  } else
-    RC = Error_CantOpenFile;
-  return RC;
-}
-
-
-void CMMDBFile::GetInputBuffer ( pstr Line, int & count )  {
-  if (FType==MMDB_FILE_PDB)  {  // PDB File
-    strcpy ( Line,S );
-    count = lcount;
-  } else if (FType==MMDB_FILE_CIF)  {
-    if (!CIFErrorLocation[0])  {  // CIF reading phase
-      strcpy ( Line,S );
-      count = lcount;
-    } else  {
-      strcpy ( Line,CIFErrorLocation );
-      count = -1;  // CIF interpretation phase
-    }
-  } else {
-    Line[0] = char(0);
-    count = -2;
-  }
-}
-
-
-int  CMMDBFile::CrystReady()  {
-//    Returns flags:
-// CRRDY_Complete       if crystallographic information is complete
-// CRRDY_NotPrecise     if cryst. inf-n is not precise
-// CRRDY_isTranslation  if cryst. inf-n contains translation
-// CRRDY_NoOrthCode     no orthogonalization code
-//    Fatal:
-// CRRDY_NoTransfMatrices  if transform. matrices were not calculated
-// CRRDY_Unchecked         if cryst. inf-n was not checked
-// CRRDY_Ambiguous         if cryst. inf-n is ambiguous
-// CRRDY_NoCell            if cryst. inf-n is unusable
-// CRRDY_NoSpaceGroup      if space group is not set
-int k;
-
-  if (!(Cryst.WhatIsSet & CSET_Transforms))
-    return CRRDY_NoTransfMatrices;
-
-  if ((Cryst.WhatIsSet & CSET_CellParams)!=CSET_CellParams)
-    return CRRDY_NoCell;
-
-  if (!(Cryst.WhatIsSet & CSET_SpaceGroup))
-    return CRRDY_NoSpaceGroup;
-
-  if (Cryst.CellCheck & CCHK_Unchecked)
-    return CRRDY_Unchecked;
-
-  if (Cryst.CellCheck & CCHK_Disagreement)
-    return CRRDY_Ambiguous;
-
-  k = 0x0000;
-  if (Cryst.CellCheck & CCHK_Error)        k |= CRRDY_NotPrecise;
-  if (Cryst.CellCheck & CCHK_Translations) k |= CRRDY_isTranslation;
-  if (Cryst.CellCheck & CCHK_NoOrthCode)   k |= CRRDY_NoOrthCode;
-
-  return k;
-
-}
-
-
-Boolean CMMDBFile::isCrystInfo()  {
-  return (((Cryst.WhatIsSet & CSET_CellParams)==CSET_CellParams) &&
-           (Cryst.WhatIsSet & CSET_SpaceGroup));
-}
-
-Boolean CMMDBFile::isCellInfo()  {
-  return ((Cryst.WhatIsSet & CSET_CellParams)==CSET_CellParams);
-}
-
-Boolean CMMDBFile::isSpaceGroup()  {
-  return (Cryst.WhatIsSet & CSET_SpaceGroup);
-}
-
-Boolean CMMDBFile::isTransfMatrix()  {
-  return Cryst.areMatrices();
-}
-
-Boolean CMMDBFile::isScaleMatrix()  {
-  return ((Cryst.WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix);
-}
-
-Boolean CMMDBFile::isNCSMatrix()  {
-  return Cryst.isNCSMatrix();
-}
-
-int  CMMDBFile::AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v,
-                               int iGiven )  {
-  return Cryst.AddNCSMatrix ( ncs_m,ncs_v,iGiven );
-}
-
-int  CMMDBFile::GetNumberOfNCSMatrices()  {
-  return Cryst.GetNumberOfNCSMatrices();
-}
-
-int  CMMDBFile::GetNumberOfNCSMates()  {
-// Returns the number of NCS mates not given in the file (iGiven==0)
-  return Cryst.GetNumberOfNCSMates();
-}
-
-Boolean  CMMDBFile::GetNCSMatrix ( int NCSMatrixNo, // 0..N-1
-                                   mat44 & ncs_m, int & iGiven )  {
-  return Cryst.GetNCSMatrix ( NCSMatrixNo,ncs_m,iGiven );
-}
-
-int  CMMDBFile::ReadPDBAtom ( cpstr L )  {
-//   If string L belongs to the coordinate section
-// (records ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM),
-// the correspondent information is retrieved and
-// stored in the dynamic Atom array. In parallel, the
-// structures of Model/Chain/Residue are generated and
-// referenced to the corresponding Atom.
-//   If processing of L was successful, the return is 0,
-// otherwise it returns the corresponding Error_XXX
-// code.
-//   If L does not belong to the coordinate section,
-// Error_WrongSection is returned.
-int RC,index,i;
-
-  if (!strncmp(L,"ATOM  ",6)) {
-
-    index = nAtoms+1;  // index for the next atom in Atom array
-    RC    = CheckAtomPlace ( index,L );
-    if (!RC)  RC = Atom[index-1]->ConvertPDBATOM ( index,L );
-
-  } else if (!strncmp(L,"SIGATM",6)) {
-
-    index = nAtoms;    // keep index!
-    RC    = CheckAtomPlace ( index,L );
-    if (!RC)  RC = Atom[index-1]->ConvertPDBSIGATM ( index,L );
-
-  } else if (!strncmp(L,"ANISOU",6)) {
-
-    index = nAtoms;    // keep index
-    RC    = CheckAtomPlace ( index,L );
-    if (!RC)  RC = Atom[index-1]->ConvertPDBANISOU ( index,L );
-
-  } else if (!strncmp(L,"SIGUIJ",6)) {
-
-    index = nAtoms;    // keep index
-    RC    = CheckAtomPlace ( index,L );
-    if (!RC)  RC = Atom[index-1]->ConvertPDBSIGUIJ ( index,L );
-
-  } else if (!strncmp(L,"TER   ",6)) {
-
-    index = nAtoms+1;  // new place in Atom array
-    RC    = CheckAtomPlace ( index,L );
-    if (!RC)  RC = Atom[index-1]->ConvertPDBTER ( index,L );
-
-  } else if (!strncmp(L,"HETATM",6)) {
-
-    index = nAtoms+1;  // new place in Atom array
-    RC    = CheckAtomPlace ( index,L );
-    if (!RC)  RC = Atom[index-1]->ConvertPDBHETATM ( index,L );
-
-  } else if (!strncmp(L,"MODEL ",6)) {
-
-    modelCnt++;
-    RC = SwitchModel ( L );
-    for (i=0;(i<nModels) && (!RC);i++)
-      if (Model[i] && (Model[i]!=crModel))  {
-        if (crModel->serNum==Model[i]->serNum)
-          RC = Error_DuplicatedModel;
-      }
-//    if (!RC)  {
-//      if (crModel->serNum!=modelCnt)
-//        RC = Error_DuplicatedModel;
-//    }
-
-  } else if (!strncmp(L,"ENDMDL",6)) {
-
-    crModel = NULL;
-    crChain = NULL;
-    crRes   = NULL;
-
-    RC      = 0;
-
-  } else
-    return Error_WrongSection;
-
-  return RC;
-
-}
-
-
-int  CMMDBFile::ReadCIFAtom ( PCMMCIFData CIFD )  {
-PCMMCIFLoop Loop,LoopAnis;
-int         RC,i,index,nATS;
-
-  Loop = CIFD->GetLoop ( CIFCAT_ATOM_SITE );
-  if (!Loop)  return 0;  // no atom coordinates in the file
-
-  LoopAnis = CIFD->GetLoop ( CIFCAT_ATOM_SITE_ANISOTROP );
-  nATS     = Loop->GetLoopLength();
-
-  for (i=1;i<=nATS;i++)  {
-    // nAtoms and i should always coincide at this point. This piece
-    // of code was however left in order to reach identity with
-    // ReadPDBAtom(..).
-    index = nAtoms+1;  // index for the next atom in Atom array
-    RC    = CheckAtomPlace ( index,Loop );
-    if (!RC)  RC = Atom[index-1]->GetCIF ( i,Loop,LoopAnis );
-    if (RC && (RC!=Error_CIF_EmptyRow))  return RC;
-  }
-  if (Flags & MMDBF_AutoSerials)
-    PDBCleanup ( PDBCLEAN_SERIAL );
-
-  return 0;
-
-}
-
-int  CMMDBFile::PutAtom ( int            index,
-                          int            serNum,
-                          const AtomName atomName,
-                          const ResName  resName,
-                          const ChainID  chainID,
-                          int            seqNum,
-                          const InsCode  insCode,
-                          const AltLoc   altLoc,
-                          const SegID    segID,
-                          const Element  element )  {
-
-//   An atom with the specified properties is put into the
-// structure. The current model is used; if no model is
-// set (crModel==NULL), one is created. Coordinates and
-// other parameters of the atom need to be set separately.
-//
-//   If index is positive and there is already an atom at
-// this position in the system, the new atom will REPLACE
-// it. The corresponding residues are automatically
-// updated.
-//
-//   If index is null (=0), the new atom will be put on
-// the top of the structure, i.e. it will be put into
-// (index=nAtoms+1)-th position.
-//
-//   If index is negative, then the new atom is INSERTED
-// BEFORE the atom in the (-index)th position. For
-// saving the computational efforts, this WILL NOT cause
-// the recalculation of all atoms' serial numbers
-// according to their actual positions. It will be needed
-// however to put the things in order by calling
-// CMMDBFile::OrderAtoms() at a certain point, especially
-// before writing an output ASCII file. NOTE that this
-// ordering is never done automatically.
-//
-//   Limitation: if PutAtom implies creating new
-// chains/residues, these are always created on the top
-// of existing chains/residues.
-
-
-int i,kndex,RC;
-
-  kndex = index;
-
-  if (kndex<0)  {  // the new atom is to be inserted
-
-    kndex = -kndex;
-    if (kndex>AtmLen)
-      ExpandAtomArray ( kndex+1000-AtmLen );
-
-    if (Atom[kndex-1]!=NULL)  { // the position is occupied
-
-      // expand the array if necessary
-      if (nAtoms>=AtmLen)
-        ExpandAtomArray ( IMax(kndex,nAtoms)+1000-AtmLen );
-
-      // now shift all atoms from (kndex-1)th to the end of array.
-      // note that this does not affect residues as they keep only
-      // pointers on atoms
-      for (i=nAtoms;i>=kndex;i--)  {
-        Atom[i] = Atom[i-1];
-        Atom[i]->index = i+1;  // this is Ok because residues keep
-                               // POINTERS rather than indices!
-      }
-      Atom[kndex-1] = NULL;
-      nAtoms++;
-
-    }
-
-  }
-
-  if (kndex==0)  kndex = nAtoms+1;
-
-  if (!crModel)  SwitchModel ( 1 );
-
-
-  RC = AllocateAtom ( kndex,chainID,chainID,resName,resName,
-                      seqNum,seqNum,1,insCode,True );
-  if (!RC)
-    Atom[kndex-1]->SetAtomName ( kndex,serNum,atomName,altLoc,
-                                 segID,element );
-  return RC;
-
-}
-
-
-int CMMDBFile::PutAtom ( int    index,  // same meaning as above
-                         PCAtom A,      // pointer to completed atom
-                                        // class
-                         int    serNum  // 0 means that the serial
-                                        // number will be set equal
-                                        // to "index". Otherwise,
-                                        // the serial number is set
-                                        // to the specified value
-                       )  {
-int i,kndex,RC,sn;
-
-  if (!A)  return -1;
-
-  kndex = index;
-
-  if (kndex<0)  {  // the new atom is to be inserted
-
-    kndex = -kndex;
-
-    if (kndex>AtmLen)
-      ExpandAtomArray ( kndex+1000-AtmLen );
-
-    if (Atom[kndex-1]!=NULL)  { // the position is occupied
-
-      // expand the array if necessary
-      if (nAtoms>=AtmLen)
-        ExpandAtomArray ( IMax(kndex,nAtoms)+1000-AtmLen );
-      // now shift all atoms from (kndex-1)th to the end of array.
-      // note that this does not affect residues as they keep only
-      // pointers on atoms
-
-      for (i=nAtoms;i>=kndex;i--)  {
-        Atom[i] = Atom[i-1];
-        Atom[i]->index = i+1;  // this is Ok because residues keep
-                               // POINTERS rather than indices!
-      }
-
-      Atom[kndex-1] = NULL;
-      nAtoms++;
-
-    }
-
-  }
-
-  if (kndex==0)  kndex = nAtoms+1;
-
-
-  RC = AllocateAtom ( kndex,A->GetChainID(),A->GetLabelAsymID(),
-                            A->GetResName(),A->GetLabelCompID(),
-                            A->GetSeqNum (),A->GetLabelSeqID (),
-                            A->GetLabelEntityID(),A->GetInsCode(),
-                            True );
-
-  if (serNum<=0)  sn = kndex;
-            else  sn = serNum;
-  if (!RC)  {
-    Atom[kndex-1]->Copy ( A );
-    Atom[kndex-1]->serNum = sn;
-  }
-
-  return RC;
-
-}
-
-int CMMDBFile::CheckInAtom ( int index, // same meaning as above
-                             PCAtom  A  // pointer to completed
-                                        // atom class
-                           )  {
-int i,kndex;
-
-  if (!A)  return -1;
-
-  kndex = index;
-
-  if (kndex<0)  {  // the new atom is to be inserted
-
-    kndex = -kndex;
-
-    if (kndex>AtmLen)
-      ExpandAtomArray ( kndex+1000-AtmLen );
-
-    if (Atom[kndex-1]!=NULL)  { // the position is occupied
-
-      // expand the array if necessary
-      if (nAtoms>=AtmLen)
-        ExpandAtomArray ( IMax(kndex,nAtoms)+1000-AtmLen );
-      // now shift all atoms from (kndex-1)th to the end of array.
-      // note that this does not affect residues as they keep only
-      // pointers on atoms
-
-      for (i=nAtoms;i>=kndex;i--)  {
-        Atom[i] = Atom[i-1];
-        if (Atom[i])
-          Atom[i]->index = i+1;  // this is Ok because residues keep
-                                 // POINTERS rather than indices!
-      }
-
-    }
-
-    nAtoms++;
-
-  } else  {
-    if (kndex==0)      kndex = nAtoms + 1;  // add atom on the very top
-    if (kndex>AtmLen)  ExpandAtomArray ( kndex+1000-AtmLen );
-    if (kndex>nAtoms)  nAtoms = kndex;
-    if (Atom[kndex-1]) delete Atom[kndex-1];
-  }
-
-  Atom[kndex-1] = A;
-  A->index = kndex;
-
-  return 0;
-
-}
-
-int CMMDBFile::CheckInAtoms ( int index, // same meaning as above
-                              PPCAtom A, // array of atoms to check in
-                              int natms  // number of atoms to check in
-                            )  {
-PPCAtom A1;
-int     i,j,k,k1,kndex;
-
-  if (!A)  return -1;
-
-  A1    = NULL;
-  kndex = index;
-
-  if (kndex<0)  {  // the new atoms are to be inserted
-
-    kndex = -kndex;
-
-    if (nAtoms+natms>=AtmLen)
-      ExpandAtomArray ( IMax(kndex,nAtoms)+1000+natms-AtmLen );
-
-    if (kndex<nAtoms)
-    A1 = new PCAtom[natms];
-    k = kndex-1;
-    j = 0;
-    for (i=0;i<natms;i++)
-      if (A[i])  {
-        if (Atom[k])  A1[j++] = Atom[k];
-        Atom[k] = A[i];
-        Atom[k]->index = k+1;
-        k++;
-      }
-
-    if (j>0)  {
-      // insert removed atoms into the gap
-      nAtoms += j;
-      k1      = k+j;
-      for (i=nAtoms-1;i>=k1;i--)  {
-        Atom[i] = Atom[i-j];
-        if (Atom[i])
-          Atom[i]->index = i+1;  // this is Ok because residues keep
-                                 // POINTERS rather than indices!
-      }
-      for (i=0;i<j;i++)  {
-        Atom[k] = A1[i];
-        Atom[k]->index = k+1;
-        k++;
-      }
-    }
-
-    delete[] A1;
-
-  } else  {
-
-    if (kndex==0)      kndex = nAtoms + 1;  // add atom on the very top
-    k = kndex + natms;
-    if (k>AtmLen)  ExpandAtomArray ( k+1000-AtmLen );
-    kndex--;
-    for (i=0;i<natms;i++)
-      if (A[i])  {
-        if (Atom[kndex]) delete Atom[kndex];
-        Atom[kndex] = A[i];
-        Atom[kndex]->index = kndex+1;
-        kndex++;
-      }
-    nAtoms = IMax(nAtoms,kndex);
-
-  }
-
-  return 0;
-
-}
-
-
-int CMMDBFile::SwitchModel ( cpstr L )  {
-int nM;
-
-  if (!GetInteger(nM,&(L[10]),4))
-    return Error_UnrecognizedInteger;
-
-  return SwitchModel ( nM );
-
-}
-
-int CMMDBFile::SwitchModel ( int nM )  {
-PPCModel Mdl;
-int      i;
-Boolean  Transfer;
-
-  if (nM<=0)
-    return Error_WrongModelNo;
-
-  if (nM>nModels)  {
-    if ((nModels==1) && Model[0])  Transfer = (nAtoms<=0);
-                             else  Transfer = False;
-    Mdl = new PCModel[nM];
-    for (i=0;i<nModels;i++)
-      Mdl[i] = Model[i];
-    for (i=nModels;i<nM;i++)
-      Mdl[i] = NULL;
-    if (Model) delete[] Model;
-    Model   = Mdl;
-    nModels = nM;
-    if (Transfer)  {
-      Model[nM-1] = Model[0];
-      Model[0]    = NULL;
-    }
-  }
-
-  if (!Model[nM-1])
-    Model[nM-1] = newCModel();
-  Model[nM-1]->SetMMDBManager ( PCMMDBManager(this),nM );
-
-  crModel = Model[nM-1];
-  crChain = NULL;  // new model - new chain
-  crRes   = NULL;  // new chain - new residue
-
-  return 0;
-
-}
-
-int CMMDBFile::CheckAtomPlace ( int index, cpstr L )  {
-//   This function gets the residue/chain information stored
-// in PDB string L (the records should start with the
-// keywords ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM) and
-// sets the pointers crChain and crRes to the respective.
-// chain and residue. If there is no chain/residue to place
-// the atom in, these will be created.
-//   The function prepares place for the atom in the index-th
-// cell of the Atom array, expanding it as necessary. If the
-// corresponding element in the Atom array was not initialized,
-// a CAtom class is created with reference to the current
-// residue.
-//   This function DOES NOT check the PDB string L for
-// atom keywords.
-ResName  resName;
-int      seqNum;
-ChainID  chainID;
-InsCode  insCode;
-
-  // get the residue sequence number/ insert code
-  if (!GetIntIns(seqNum,insCode,&(L[22]),4))  {
-    if (strncmp(L,"TER   ",6))
-          return Error_UnrecognizedInteger;
-    else  { // we allow for empty TER card here
-      seqNum  = 0;
-      insCode[0] = char(1);  // unprintable symbol! used as
-                             // flag that TER card does not
-                             // have serial number
-      insCode[1] = char(0);
-    }
-  }
-
-  // get chain ID
-  if (L[20]!=' ')  {
-    chainID[0] = L[20];
-    chainID[1] = L[21];
-    chainID[2] = char(0);
-  } else if (L[21]!=' ')  {
-    chainID[0] = L[21];
-    chainID[1] = char(0);
-  } else
-    chainID[0] = char(0);
-
-  // get residue name
-  strcpy_ncss ( resName,&(L[17]),3 );
-  if ((!resName[0]) && (!strncmp(L,"TER   ",6)))  {
-    insCode[0] = char(1);
-    insCode[1] = char(0);
-  }
-
-  return AllocateAtom ( index ,chainID,chainID,resName,resName,
-                        seqNum,seqNum,1,insCode,False );
-
-}
-
-int CMMDBFile::CheckAtomPlace ( int index, PCMMCIFLoop Loop )  {
-//   Version of CheckAtomPlace(..) for reading from CIF file.
-ResName  resName,label_comp_id;
-int      seqNum ,label_seq_id,label_entity_id,RC,k,nM;
-ChainID  chainID,label_asym_id;
-InsCode  insCode;
-pstr     F;
-
-  // Get the residue sequence number/insert code. They are
-  // removed from the file after reading.
-  k = index-1;
-//  if (!CIFGetInteger1(seqNum,Loop,CIFTAG_LABEL_SEQ_ID,k))
-  if (!CIFGetInteger1(seqNum,Loop,CIFTAG_AUTH_SEQ_ID,k))
-    CIFGetString  ( insCode,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,k,
-                    sizeof(InsCode),pstr("") );
-  else  {
-    F = Loop->GetString ( CIFTAG_GROUP_PDB,k,RC );
-    if ((!F) || (RC)) return  Error_CIF_EmptyRow;
-    if (strcmp(F,"TER"))  {
-      seqNum = MinInt4;  // only at reading CIF we allow this
-      CIFGetString ( insCode,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,k,
-                     sizeof(InsCode),pstr("") );
-    } else  { // we allow for empty TER card here
-      seqNum     = 0;
-      insCode[0] = char(1);  // unprintable symbol! used as
-                             // flag that TER card does not
-                             // have serial number
-      insCode[1] = char(0);
-    }
-  }
-
-  CIFGetInteger1 ( label_seq_id   ,Loop,CIFTAG_LABEL_SEQ_ID   ,k );
-  CIFGetInteger1 ( label_entity_id,Loop,CIFTAG_LABEL_ENTITY_ID,k );
-
-  // get chain/residue ID
-  CIFGetString ( chainID,Loop,CIFTAG_AUTH_ASYM_ID,k,
-                 sizeof(ChainID),pstr("") );
-  CIFGetString ( resName,Loop,CIFTAG_AUTH_COMP_ID,k,
-                 sizeof(ResName),pstr("") );
-
-  CIFGetString ( label_asym_id,Loop,CIFTAG_LABEL_ASYM_ID,k,
-                 sizeof(ChainID),pstr("") );
-  CIFGetString ( label_comp_id,Loop,CIFTAG_LABEL_COMP_ID,k,
-                 sizeof(ResName),pstr("") );
-
-  if (!resName[0])  strcpy ( resName,label_comp_id );
-
-  if (!CIFGetInteger1(nM,Loop,CIFTAG_PDBX_PDB_MODEL_NUM,k))  {
-    if (crModel)  {
-      if (nM!=crModel->serNum)  SwitchModel ( nM );
-    } else
-      SwitchModel ( nM );
-  }
-
-  return AllocateAtom ( index ,chainID,label_asym_id,resName,
-                        label_comp_id,seqNum,label_seq_id,
-                        label_entity_id,insCode,False );
-
-}
-
-
-int  CMMDBFile::AllocateAtom ( int           index,
-                               const ChainID chainID,
-                               const ChainID label_asym_id,
-                               const ResName resName,
-                               const ResName label_comp_id,
-                               int           seqNum,
-                               int           label_seq_id,
-                               int           label_entity_id,
-                               const InsCode insCode,
-                               Boolean       Replace )  {
-
-  if ((!resName[0]) && (insCode[0]!=char(1)))
-    return Error_EmptyResidueName;
-
-  // check if there is a pointer to model
-  if (!crModel)  {
-    // the model pointer was not set. Check if there are
-    // models already defined
-    if (!Model)
-         SwitchModel ( 1 );  // creates a model
-    else return Error_NoModel;
-  }
-
-  if (crChain && (insCode[0]!=char(1)))  {
-    //   If crChain is not NULL, the model pointer was not
-    // changed and we may try to keep using crChain as
-    // pointer to the being-read chain. However, we must
-    // check that the record still belongs to the same chain.
-    //   All this does not work if insCode[0] is set to 1
-    // which indicates a special case of 'TER' card without
-    // parameters.
-    if (enforceUniqueChID)  {
-      // enforcing unique chain IDs should be used only in case
-      // of multi-chain complexes where 1-letter chain IDs are
-      // not enough to accomodate all chains. Then chains are
-      // dynamically renamed like A0,A1,A2,.. etc. Therefore, we
-      // check only first symbol here.
-      if (chainID[0]!=crChain->chainID[0])
-        crChain = NULL;  // the chain has to be changed
-    } else if (strcmp(chainID,crChain->chainID))
-      crChain = NULL;  // the chain has to be changed
-  }
-  if (!crChain) {
-    // either the model or chain was changed  -- get a new chain
-    if (allowDuplChID)
-          crChain = crModel->CreateChain    ( chainID );
-    else  crChain = crModel->GetChainCreate ( chainID,
-                                              enforceUniqueChID );
-    crRes = NULL;  // new chain - new residue
-  }
-
-  if (crRes && (insCode[0]!=char(1)))  {
-    //   If crRes is not NULL, neither the model nor chain were
-    // changed. Check if this record still belongs to the
-    // same residue.
-    //   All this does not work if insCode[0] is set to 1
-    // which indicates a special case of 'TER' card without
-    // parameters.
-    if ((seqNum!=crRes->seqNum)         ||
-         strcmp(insCode,crRes->insCode) ||
-         strcmp(resName,crRes->name))
-      crRes = NULL;  // the residue has to be changed
-  }
-  if (!crRes)  {
-    // either the chain or residue was changed -- get a new residue
-    crRes = crChain->GetResidueCreate ( resName,seqNum,insCode,
-                                      Flags & MMDBF_IgnoreDuplSeqNum );
-    if (!crRes)  return  Error_DuplicateSeqNum;
-  }
-
-  strcpy ( crRes->label_asym_id,label_asym_id );
-  strcpy ( crRes->label_comp_id,label_comp_id );
-  crRes->label_seq_id    = label_seq_id;
-  crRes->label_entity_id = label_entity_id;
-
-  // now check if there is place in the Atom array
-  if (index>AtmLen)
-    // there is no place, expand Atom by 1000 atom places at once
-    ExpandAtomArray ( index+1000-AtmLen );
-  nAtoms = IMax(nAtoms,index);
-
-  // delete the to-be-replaced atom if there is any
-  if (Replace && Atom[index-1])  {
-    delete Atom[index-1];
-    Atom[index-1] = NULL;
-  }
-  if (!Atom[index-1])  {
-    Atom[index-1] = newCAtom();
-    crRes->_AddAtom ( Atom[index-1] );
-    Atom[index-1]->index = index;
-  }
-
-  return 0;
-
-}
-
-void CMMDBFile::ExpandAtomArray ( int inc )  {
-// Expands the Atom array by adding more inc positions.
-// The length of Atom array is increased unconditionally.
-PPCAtom Atom1;
-int     i;
-  AtmLen += inc;
-  Atom1   = new PCAtom[AtmLen];
-  for (i=0;i<nAtoms;i++)
-    Atom1[i] = Atom[i];
-  for (i=nAtoms;i<AtmLen;i++)
-    Atom1[i] = NULL;
-  if (Atom) delete[] Atom;
-  Atom = Atom1;
-}
-
-void CMMDBFile::AddAtomArray ( int inc )  {
-// Checks if 'inc' atoms may be added into Atom array,
-// and if not, expands the Atom array such that to
-// allocate exactly 'inc' atoms more than is currently
-// contained.
-PPCAtom Atom1;
-int     i;
-  if (nAtoms+inc>AtmLen)  {
-    AtmLen = nAtoms+inc;
-    Atom1  = new PCAtom[AtmLen];
-    for (i=0;i<nAtoms;i++)
-      Atom1[i] = Atom[i];
-    for (i=nAtoms;i<AtmLen;i++)
-      Atom1[i] = NULL;
-    if (Atom) delete[] Atom;
-    Atom = Atom1;
-  }
-}
-
-
-int  CMMDBFile::WritePDBASCII1 ( cpstr PDBLFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( PDBLFName );
-  if (FName)  return WritePDBASCII ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int  CMMDBFile::WritePDBASCII ( cpstr PDBFileName, byte gzipMode )  {
-CFile f;
-
-  //  opening it in pseudo-text mode ensures that the line
-  //  endings will correspond to the system MMDB is running on
-  f.assign ( PDBFileName,True,False,gzipMode );
-  FType = MMDB_FILE_PDB;
-
-  if (f.rewrite())  {
-    WritePDBASCII ( f );
-    f.shut();
-  } else
-    return Error_CantOpenFile;
-
-  return 0;
-
-}
-
-
-void  CMMDBFile::WritePDBASCII ( RCFile f )  {
-int  i;
-
-  FType = MMDB_FILE_PDB;
-
-  Title.PDBASCIIDump ( f );
-
-  i = 0;
-  while (i<nModels)
-    if (Model[i])  break;
-             else  i++;
-  if (i<nModels)
-    Model[i]->PDBASCIIDumpPS ( f );
-
-  // output cispep records
-  for (i=0;i<nModels;i++)
-    if (Model[i])
-      Model[i]->PDBASCIIDumpCP ( f );
-
-  SA      .PDBASCIIDump ( f );
-  Footnote.PDBASCIIDump ( f );
-  Cryst   .PDBASCIIDump ( f );
-  SB      .PDBASCIIDump ( f );
-
-  for (i=0;i<nModels;i++)
-    if (Model[i])
-      Model[i]->PDBASCIIDump ( f );
-
-  SC.PDBASCIIDump ( f );
-
-  f.WriteLine ( pstr("END") );
-
-}
-
-
-int  CMMDBFile::WriteCIFASCII1 ( cpstr CIFLFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( CIFLFName );
-  if (FName)  return WriteCIFASCII ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int  CMMDBFile::WriteCIFASCII ( cpstr CIFFileName, byte gzipMode )  {
-int  i;
-
-  if (!CIF)  CIF = new CMMCIFData();
-  CIF->SetStopOnWarning ( True );
-  CIF->SetPrintWarnings ( (Flags & MMDBF_PrintCIFWarnings)!=0 );
-  FType = MMDB_FILE_CIF;
-
-  Title.MakeCIF ( CIF );
-
-  i = 0;
-  while (i<nModels)
-    if (Model[i])  break;
-             else  i++;
-  if (i<nModels)
-    Model[i]->MakePSCIF ( CIF );
-
-  Cryst.MakeCIF ( CIF );
-
-  for (i=0;i<nModels;i++)
-    if (Model[i])
-      Model[i]->MakeAtomCIF ( CIF );
-
-  CIF->Optimize();
-  CIF->WriteMMCIFData ( CIFFileName,gzipMode );
-
-  return 0;
-
-}
-
-
-PCAtom  CMMDBFile::GetAtomI ( int index )  {
-  if (index>nAtoms)  return NULL;
-  if (index<1)       return NULL;
-  if (!Atom)         return NULL;
-  return Atom[index-1];
-}
-
-
-#define MMDBFLabel  "**** This is MMDB binary file ****"
-#define Edition     1
-
-int  CMMDBFile::ReadMMDBF1 ( cpstr MMDBLFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( MMDBLFName );
-  if (FName)  return ReadCoorFile ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int  CMMDBFile::ReadMMDBF ( cpstr MMDBFileName, byte gzipMode )  {
-CFile f;
-int   rc;
-
-  f.assign ( MMDBFileName,False,True,gzipMode );
-  FType = MMDB_FILE_Binary;
-  if (f.reset(True))  {
-    rc = ReadMMDBF ( f );
-    f.shut();
-  } else
-    rc = Error_CantOpenFile;
-
-  return rc;
-
-}
-
-int  CMMDBFile::ReadMMDBF ( RCFile f )  {
-char  Label[100];
-byte  Version;
-
-  FType = MMDB_FILE_Binary;
-  f.ReadFile ( Label,sizeof(MMDBFLabel) );
-  if (strncmp(Label,MMDBFLabel,sizeof(MMDBFLabel)))
-    return Error_ForeignFile;
-
-  f.ReadByte ( &Version );
-  if (Version>Edition)
-    return Error_WrongEdition;
-
-  read ( f );
-
-  return 0;
-
-}
-
-
-int  CMMDBFile::WriteMMDBF1 ( cpstr MMDBLFName, byte gzipMode )  {
-pstr FName;
-  FName = getenv ( MMDBLFName );
-  if (FName)  return WriteMMDBF ( FName,gzipMode );
-        else  return Error_NoLogicalName;
-}
-
-int  CMMDBFile::WriteMMDBF ( cpstr MMDBFileName, byte gzipMode )  {
-char  Label[100];
-byte  Version=Edition;
-CFile f;
-
-  f.assign ( MMDBFileName,False,True,gzipMode );
-  FType = MMDB_FILE_Binary;
-  if (f.rewrite())  {
-    strcpy ( Label,MMDBFLabel );
-    f.WriteFile ( Label,sizeof(MMDBFLabel) );
-    f.WriteByte ( &Version );
-    write ( f );
-    f.shut();
-  } else
-    return Error_CantOpenFile;
-
-  return 0;
-
-}
-
-
-pstr  CMMDBFile::GetEntryID()  {
-  return Title.idCode;
-}
-
-void  CMMDBFile::SetEntryID ( const IDCode idCode )  {
-  strcpy ( Title.idCode,idCode );
-}
-
-void CMMDBFile::SetSyminfoLib ( cpstr syminfo_lib )  {
-  Cryst.SetSyminfoLib ( syminfo_lib );
-}
-
-pstr CMMDBFile::GetSyminfoLib()  {
-  return Cryst.GetSyminfoLib();
-}
-
-int CMMDBFile::SetSpaceGroup ( cpstr spGroup )  {
-  return Cryst.SetSpaceGroup ( spGroup );
-}
-
-pstr CMMDBFile::GetSpaceGroup()  {
-  return Cryst.GetSpaceGroup();
-}
-
-pstr CMMDBFile::GetSpaceGroupFix()  {
-  return Cryst.GetSpaceGroupFix();
-}
-
-void  CMMDBFile::GetAtomStatistics ( RSAtomStat AS )  {
-int i;
-  AS.Init();
-  for (i=0;i<nModels;i++)
-    if (Model[i])  Model[i]->CalcAtomStatistics ( AS );
-  AS.Finish();
-}
-
-void CMMDBFile::SetIgnoreSCALEi ( Boolean ignoreScalei )  {
-  Cryst.ignoreScalei = ignoreScalei;
-}
-
-void CMMDBFile::SetCell ( realtype cell_a,
-                          realtype cell_b,
-                          realtype cell_c,
-                          realtype cell_alpha,
-                          realtype cell_beta,
-                          realtype cell_gamma,
-                          int      OrthCode )  {
-  Cryst.SetCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
-                  cell_gamma,OrthCode );
-}
-
-void CMMDBFile::PutCell ( realtype cell_a,
-                          realtype cell_b,
-                          realtype cell_c,
-                          realtype cell_alpha,
-                          realtype cell_beta,
-                          realtype cell_gamma,
-                          int      OrthCode )  {
-  Cryst.PutCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
-                  cell_gamma,OrthCode );
-}
-
-int  CMMDBFile::GetCell ( realtype & cell_a,
-                          realtype & cell_b,
-                          realtype & cell_c,
-                          realtype & cell_alpha,
-                          realtype & cell_beta,
-                          realtype & cell_gamma,
-                          realtype & vol,
-                          int      & OrthCode )  {
-  if (Cryst.WhatIsSet & CSET_CellParams)  {
-    Cryst.GetCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
-                    cell_gamma,vol );
-    OrthCode = Cryst.NCode + 1;
-    return 1;
-  } else {
-    cell_a     = 0.0;    cell_b    = 0.0;    cell_c     = 0.0;
-    cell_alpha = 0.0;    cell_beta = 0.0;    cell_gamma = 0.0;
-    vol        = 0.0;    OrthCode  = 0;
-    return 0;
-  }
-}
-
-int  CMMDBFile::GetRCell ( realtype & cell_as,
-                           realtype & cell_bs,
-                           realtype & cell_cs,
-                           realtype & cell_alphas,
-                           realtype & cell_betas,
-                           realtype & cell_gammas,
-                           realtype & vols,
-                           int      & OrthCode )  {
-  if (Cryst.WhatIsSet & CSET_CellParams)  {
-    Cryst.GetRCell ( cell_as,cell_bs,cell_cs,cell_alphas,cell_betas,
-                     cell_gammas,vols );
-    OrthCode = Cryst.NCode + 1;
-    return 1;
-  } else {
-    cell_as     = 0.0;    cell_bs    = 0.0;    cell_cs     = 0.0;
-    cell_alphas = 0.0;    cell_betas = 0.0;    cell_gammas = 0.0;
-    vols        = 0.0;    OrthCode   = 0;
-    return 0;
-  }
-}
-
-int CMMDBFile::GetNumberOfSymOps()  {
-  if (Cryst.WhatIsSet & CSET_SpaceGroup)
-        return Cryst.GetNumberOfSymOps();
-  else  return 0;
-}
-
-pstr CMMDBFile::GetSymOp ( int Nop )  {
-  return Cryst.GetSymOp ( Nop );
-}
-
-
-void CMMDBFile::GetROMatrix ( mat44 & RO )  {
-  Mat4Copy ( Cryst.RO,RO );
-}
-
-int CMMDBFile::GetTMatrix ( mat44 & TMatrix, int Nop,
-                            int cellshift_a, int cellshift_b,
-                            int cellshift_c )  {
-//  GetTMatrix(..) calculates and returns the coordinate transformation
-//  matrix, which converts orthogonal coordinates according to
-//  the symmetry operation number Nop and places them into unit cell
-//  shifted by cellshift_a a's, cellshift_b b's and cellshift_c c's.
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-  return Cryst.GetTMatrix ( TMatrix,Nop,cellshift_a,cellshift_b,
-                            cellshift_c,NULL );
-}
-
-
-int CMMDBFile::GetUCTMatrix ( mat44 & TMatrix, int Nop,
-                              realtype x, realtype y, realtype z,
-                              int cellshift_a, int cellshift_b,
-                              int cellshift_c )  {
-//  GetUCTMatrix(..) calculates and returns the coordinate
-//  transformation matrix, which converts orthogonal coordinates
-//  according to the symmetry operation number Nop. Translation
-//  part of the resulting matrix is being chosen such that point
-//  (x,y,z) has least distance to the center of primary (333)
-//  unit cell, and then it is shifted by cellshift_a a's,
-//  cellshift_b b's and cellshift_c c's.
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-  return Cryst.GetUCTMatrix ( TMatrix,Nop,x,y,z,
-                              cellshift_a,cellshift_b,cellshift_c,
-                              NULL );
-}
-
-
-int CMMDBFile::GetFractMatrix ( mat44 & TMatrix, int Nop,
-                                int cellshift_a, int cellshift_b,
-                                int cellshift_c )  {
-//  GetFractMatrix(..) calculates and returns the coordinate
-//  transformation matrix, which converts fractional coordinates
-//  according to the symmetry operation number Nop and places them
-//  into unit cell shifted by cellshift_a a's, cellshift_b b's and
-//  cellshift_c c's.
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-  return Cryst.GetFractMatrix ( TMatrix,Nop,cellshift_a,cellshift_b,
-                                cellshift_c,NULL );
-}
-
-int  CMMDBFile::GetSymOpMatrix ( mat44 & TMatrix, int Nop )  {
-//
-//  GetSymOpMatrix(..) returns the transformation matrix for
-//  Nop-th symmetry operator in the space group
-//
-//  Return 0 means everything's fine,
-//         1 there's no symmetry operation Nop defined
-//         2 fractionalizing/orthogonalizing matrices were not
-//           calculated
-//         3 cell parameters were not set up.
-//
-  return Cryst.GetSymOpMatrix ( TMatrix,Nop );
-}
-
-//  -------------  User-Defined Data  ------------------------
-
-int  CMMDBFile::RegisterUDInteger ( int udr_type, cpstr UDDataID )  {
-  return UDRegister.RegisterUDInteger ( udr_type,UDDataID );
-}
-
-int  CMMDBFile::RegisterUDReal ( int udr_type, cpstr UDDataID )  {
-  return UDRegister.RegisterUDReal ( udr_type,UDDataID );
-}
-
-int  CMMDBFile::RegisterUDString ( int udr_type, cpstr UDDataID )  {
-  return UDRegister.RegisterUDString ( udr_type,UDDataID );
-}
-
-int  CMMDBFile::GetUDDHandle ( int udr_type, cpstr UDDataID )  {
-  return UDRegister.GetUDDHandle ( udr_type,UDDataID );
-}
-
-
-
-//  ----------------------------------------------------------
-
-int CMMDBFile::DeleteAllModels()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nModels;i++)  {
-    if (Model[i])  {
-      delete Model[i];
-      Model[i] = NULL;
-      k++;
-    }
-  }
-  Exclude = True;
-  FinishStructEdit();
-  return k;
-}
-
-Boolean CMMDBFile::GetNewChainID ( int modelNo, ChainID chID,
-                                   int length )  {
-  if ((modelNo>=1) && (modelNo<=nModels))  {
-    if (Model[modelNo-1])
-      return  Model[modelNo-1]->GetNewChainID ( chID,length );
-  }
-  return False;
-}
-
-//  -------------------------------------------------------------
-
-PCMask CMMDBFile::GetSelMask ( int selHnd )  {
-UNUSED_ARGUMENT(selHnd);
-  return NULL;
-}
-
-//  -------------------------------------------------------------
-
-int  CMMDBFile::GetNofExpDataRecs()  {
-  return Title.ExpData.Length();
-}
-
-pstr  CMMDBFile::GetExpDataRec ( int recNo )  {
-PCExpData  expData;
-  expData = PCExpData(Title.ExpData.GetContainerClass(recNo));
-  if (expData)  return expData->Line;
-  return NULL;
-}
-
-
-//  -------------------------------------------------------------
-
-int  CMMDBFile::GetNofMdlTypeRecs()  {
-  return Title.MdlType.Length();
-}
-
-pstr  CMMDBFile::GetMdlTypeRec ( int recNo )  {
-PCMdlType  mdlType;
-  mdlType = PCMdlType(Title.MdlType.GetContainerClass(recNo));
-  if (mdlType)  return mdlType->Line;
-  return NULL;
-}
-
-
-//  -------------------  Stream functions  ----------------------
-
-void  CMMDBFile::Copy ( PCMMDBFile MMDBFile )  {
-int i;
-
-  Title.Copy ( &MMDBFile->Title );
-  Cryst.Copy ( &MMDBFile->Cryst );
-
-  //   It is important to copy atoms _before_ models,
-  // residues and chains!
-  Flags  = MMDBFile->Flags;
-  nAtoms = MMDBFile->nAtoms;
-  AtmLen = nAtoms;
-  if (nAtoms>0)  {
-    Atom = new PCAtom[AtmLen];
-    for (i=0;i<nAtoms;i++)
-      if (MMDBFile->Atom[i])  {
-        Atom[i] = newCAtom();
-        Atom[i]->Copy ( MMDBFile->Atom[i] );
-        Atom[i]->index = i+1;
-        // the internal atom references are installed
-        // by residue classes when they are copied in
-        // model->chain below
-      } else
-        Atom[i] = NULL;
-  }
-
-  nModels = MMDBFile->nModels;
-  if (nModels>0)  {
-    Model = new PCModel[nModels];
-    for (i=0;i<nModels;i++)  {
-      if (MMDBFile->Model[i])  {
-        Model[i] = newCModel();
-        Model[i]->SetMMDBManager ( PCMMDBManager(this),i+1 );
-        Model[i]->_copy ( MMDBFile->Model[i] );
-      } else
-        Model[i] = NULL;
-    }
-  }
-
-  SA      .Copy ( &MMDBFile->SA       );
-  Footnote.Copy ( &MMDBFile->Footnote );
-  SB      .Copy ( &MMDBFile->SB       );
-  SC      .Copy ( &MMDBFile->SC       );
-
-  if (MMDBFile->CIF)  {
-    CIF = new CMMCIFData;
-    CIF->Copy ( MMDBFile->CIF );
-  }
-
-}
-
-
-
-// -------  user-defined data handlers
-
-int  CMMDBFile::PutUDData ( int UDDhandle, int iudd )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::putUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CMMDBFile::PutUDData ( int UDDhandle, realtype rudd )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::putUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CMMDBFile::PutUDData ( int UDDhandle, cpstr sudd )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::putUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CMMDBFile::GetUDData ( int UDDhandle, int & iudd )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::getUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CMMDBFile::GetUDData ( int UDDhandle, realtype & rudd )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::getUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CMMDBFile::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::getUDData ( UDDhandle,sudd,maxLen );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CMMDBFile::GetUDData ( int UDDhandle, pstr & sudd )  {
-  if (UDDhandle & UDRF_HIERARCHY)
-        return  CUDData::getUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-
-pstr CMMDBFile::GetStructureTitle ( pstr & L )  {
-  return Title.GetStructureTitle ( L );
-}
-
-void  CMMDBFile::SetShortBinary()  {
-// leaves only coordinates in binary files
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])  Atom[i]->SetShortBinary();
-}
-
-
-void  CMMDBFile::write ( RCFile f )  {
-int  i,k;
-byte Version=1;
-
-  f.WriteByte ( &Version );
-
-  CUDData::write ( f );
-
-  Title     .write ( f );
-  Cryst     .write ( f );
-  UDRegister.write ( f );
-  DefPath   .write ( f );
-
-  f.WriteWord ( &Flags  );
-  f.WriteInt  ( &nAtoms );
-  for (i=0;i<nAtoms;i++)  {
-    if (Atom[i])  k = 1;
-            else  k = 0;
-    f.WriteInt ( &k );
-    if (Atom[i]) Atom[i]->write ( f );
-  }
-
-  f.WriteInt ( &nModels );
-  for (i=0;i<nModels;i++)  {
-    if (Model[i])  k = 1;
-             else  k = 0;
-    f.WriteInt ( &k );
-    if (Model[i]) Model[i]->write ( f );
-  }
-
-  SA      .write ( f );
-  Footnote.write ( f );
-  SB      .write ( f );
-  SC      .write ( f );
-
-  StreamWrite ( f,CIF );
-
-}
-
-void  CMMDBFile::read ( RCFile f )  {
-int  i,k;
-byte Version;
-
-  ResetManager  ();
-  FreeFileMemory();
-
-  f.ReadByte ( &Version );
-
-  CUDData::read ( f );
-
-  Title     .read ( f );
-  Cryst     .read ( f );
-  UDRegister.read ( f );
-  DefPath   .read ( f );
-
-  //   It is important to read atoms before models,
-  // residues and chains!
-  f.ReadWord ( &Flags  );
-  f.ReadInt  ( &nAtoms );
-  AtmLen = nAtoms;
-  if (nAtoms>0)  {
-    Atom = new PCAtom[AtmLen];
-    for (i=0;i<nAtoms;i++)  {
-      f.ReadInt ( &k );
-      if (k)  {
-        Atom[i] = newCAtom();
-        Atom[i]->read ( f );
-        // the internal atom references are installed
-        // by residue classes when they are read in
-        // model->chain below
-      } else
-        Atom[i] = NULL;
-    }
-  }
-
-  f.ReadInt ( &nModels );
-  if (nModels>0)  {
-    Model = new PCModel[nModels];
-    for (i=0;i<nModels;i++)  {
-      f.ReadInt ( &k );
-      if (k)  {
-        Model[i] = newCModel();
-        Model[i]->SetMMDBManager ( PCMMDBManager(this),0 );
-        Model[i]->read ( f );
-      } else
-        Model[i] = NULL;
-    }
-  }
-
-  SA      .read ( f );
-  Footnote.read ( f );
-  SB      .read ( f );
-  SC      .read ( f );
-
-  StreamRead ( f,CIF );
-
-}
-
-
-MakeStreamFunctions(CMMDBFile)
-
-
-int isMMDBBIN ( cpstr FName, byte gzipMode )  {
-CFile f;
-int   rc;
-
-  f.assign ( FName,False,True,gzipMode );
-  if (f.reset(True))  {
-    rc = isMMDBBIN ( f );
-    f.shut();
-  } else
-    rc = -1;
-
-  return rc;
-
-}
-
-int isMMDBBIN ( RCFile f )  {
-char  Label[100];
-byte  Version;
-
-  if (f.FileEnd())
-    return Error_EmptyFile;
-
-  f.ReadFile ( Label,sizeof(MMDBFLabel) );
-  if (strncmp(Label,MMDBFLabel,sizeof(MMDBFLabel)))
-    return 1;
-
-  f.ReadByte ( &Version );
-
-  if (Version>Edition)  return 2;
-                  else  return 0;
-
-}
-
-
-int isPDB ( cpstr FName, byte gzipMode, Boolean IgnoreBlankLines )  {
-CFile f;
-int   rc;
-
-  f.assign ( FName,False,False,gzipMode );
-  if (f.reset(True))  {
-    //  opening it in pseudo-binary mode helps reading various
-    //  line terminators for files coming from different platforms
-    rc = isPDB ( f,IgnoreBlankLines );
-    f.shut();
-  } else
-    rc = -1;
-
-  return rc;
-
-}
-
-int isPDB ( RCFile f, Boolean IgnoreBlankLines )  {
-char    S[256];
-int     i;
-Boolean Done;
-
-  if (f.FileEnd())
-    return Error_EmptyFile;
-
-  do {
-    Done = True;
-    f.ReadLine ( S,sizeof(S)-1 );
-    if (IgnoreBlankLines)  {
-      i = 0;
-      while (S[i] && (S[i]==' '))  i++;
-      if (!S[i])  Done = False;
-    }
-  } while ((!f.FileEnd()) && (!Done));
-
-  PadSpaces  ( S,80 );
-  if (!strncasecmp(S,"HEADER",6))  return 0;
-  if (!strncasecmp(S,"OBSLTE",6))  return 0;
-  if (!strncasecmp(S,"TITLE ",6))  return 0;
-  if (!strncasecmp(S,"CAVEAT",6))  return 0;
-  if (!strncasecmp(S,"COMPND",6))  return 0;
-  if (!strncasecmp(S,"SOURCE",6))  return 0;
-  if (!strncasecmp(S,"KEYWDS",6))  return 0;
-  if (!strncasecmp(S,"EXPDTA",6))  return 0;
-  if (!strncasecmp(S,"AUTHOR",6))  return 0;
-  if (!strncasecmp(S,"REVDAT",6))  return 0;
-  if (!strncasecmp(S,"SPRSDE",6))  return 0;
-  if (!strncasecmp(S,"JRNL  ",6))  return 0;
-  if (!strncasecmp(S,"REMARK",6))  return 0;
-  if (!strncasecmp(S,"DBREF ",6))  return 0;
-  if (!strncasecmp(S,"SEQADV",6))  return 0;
-  if (!strncasecmp(S,"SEQRES",6))  return 0;
-  if (!strncasecmp(S,"MODRES",6))  return 0;
-  if (!strncasecmp(S,"HET   ",6))  return 0;
-  if (!strncasecmp(S,"HETNAM",6))  return 0;
-  if (!strncasecmp(S,"HETSYN",6))  return 0;
-  if (!strncasecmp(S,"FORMUL",6))  return 0;
-  if (!strncasecmp(S,"HELIX ",6))  return 0;
-  if (!strncasecmp(S,"SHEET ",6))  return 0;
-  if (!strncasecmp(S,"TURN  ",6))  return 0;
-  if (!strncasecmp(S,"SSBOND",6))  return 0;
-  if (!strncasecmp(S,"LINK  ",6))  return 0;
-  if (!strncasecmp(S,"HYDBND",6))  return 0;
-  if (!strncasecmp(S,"SLTBRG",6))  return 0;
-  if (!strncasecmp(S,"CISPEP",6))  return 0;
-  if (!strncasecmp(S,"SITE  ",6))  return 0;
-  if (!strncasecmp(S,"CRYST1",6))  return 0;
-  if (!strncasecmp(S,"CRYST ",6))  return 0;
-  if (!strncasecmp(S,"ORIGX1",6))  return 0;
-  if (!strncasecmp(S,"ORIGX2",6))  return 0;
-  if (!strncasecmp(S,"ORIGX3",6))  return 0;
-  if (!strncasecmp(S,"SCALE1",6))  return 0;
-  if (!strncasecmp(S,"SCALE2",6))  return 0;
-  if (!strncasecmp(S,"SCALE3",6))  return 0;
-  if (!strncasecmp(S,"MTRIX1",6))  return 0;
-  if (!strncasecmp(S,"MTRIX2",6))  return 0;
-  if (!strncasecmp(S,"MTRIX3",6))  return 0;
-  if (!strncasecmp(S,"TVECT ",6))  return 0;
-  if (!strncasecmp(S,"MODEL ",6))  return 0;
-  if (!strncasecmp(S,"ATOM  ",6))  return 0;
-  if (!strncasecmp(S,"SIGATM",6))  return 0;
-  if (!strncasecmp(S,"ANISOU",6))  return 0;
-  if (!strncasecmp(S,"SIGUIJ",6))  return 0;
-  if (!strncasecmp(S,"TER   ",6))  return 0;
-  if (!strncasecmp(S,"HETATM",6))  return 0;
-  if (!strncasecmp(S,"ENDMDL",6))  return 0;
-  if (!strncasecmp(S,"CONECT",6))  return 0;
-  if (!strncasecmp(S,"MASTER",6))  return 0;
-  if (!strncasecmp(S,"END   ",6))  return 0;
-  if (!strncasecmp(S,"USER  ",6))  return 0;
-
-  return  1;
-
-}
diff --git a/mmdb/mmdb_file.h b/mmdb/mmdb_file.h
deleted file mode 100755
index 6489fbd..0000000
--- a/mmdb/mmdb_file.h
+++ /dev/null
@@ -1,650 +0,0 @@
-//  $Id: mmdb_file.h,v 1.30 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    16.05.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_File <interface>
-//       ~~~~~~~~~
-//       Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBFile
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_File__
-#define __MMDB_File__
-
-
-#ifndef __File__
-#include "file_.h"
-#endif
-
-#ifndef  __mmdb_uddata__
-#include "mmdb_uddata.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_Title__
-#include "mmdb_title.h"
-#endif
-
-#ifndef  __MMDB_Cryst__
-#include "mmdb_cryst.h"
-#endif
-
-#ifndef  __MMDB_Chain__
-#include "mmdb_chain.h"
-#endif
-
-#ifndef  __MMDB_Model__
-#include "mmdb_model.h"
-#endif
-
-
-// =======================  CMMDBFile  ===========================
-
-
-// special effect flags
-
-#define MMDBF_AutoSerials             0x00000001
-#define MMDBF_NoCoordRead             0x00000002
-#define MMDBF_SimRWBROOK              0x00000004
-#define MMDBF_PrintCIFWarnings        0x00000008
-#define MMDBF_EnforceSpaces           0x00000010
-#define MMDBF_IgnoreDuplSeqNum        0x00000020
-#define MMDBF_IgnoreSegID             0x00000040
-#define MMDBF_IgnoreElement           0x00000080
-#define MMDBF_IgnoreCharge            0x00000100
-#define MMDBF_IgnoreNonCoorPDBErrors  0x00000200
-#define MMDBF_IgnoreUnmatch           0x00000400
-#define MMDBF_IgnoreBlankLines        0x00000800
-#define MMDBF_IgnoreHash              0x00001000
-#define MMDBF_IgnoreRemarks           0x00002000
-#define MMDBF_AllowDuplChainID        0x00004000
-#define MMDBF_FixSpaceGroup           0x00008000
-#define MMDBF_EnforceAtomNames        0x00010000
-#define MMDBF_EnforceUniqueChainID    0x00020000
-#define MMDBF_DoNotProcessSpaceGroup  0x00040000
-
-// MMDBF_EnforceUniqueChainID   will make MMDB to rename chains on
-//         reading a file such as to maintain chains uniquesness. This
-//         is supposed to work only with 1-letter chain IDs and only
-//         if chain names are interchanged in the file. For example,
-//         if file contains a sequence of chains named
-//
-//              A,B, A,B, A,B, A,B, A,B
-//
-//         and this flag is set on, the resulting chain names in
-//         MMDB will be:
-//
-//              A,B, A0,B0, A1,B1, A2,B2, A3,B3
-//
-
-// file types:
-#define MMDB_FILE_Undefined     -1
-#define MMDB_FILE_PDB            0
-#define MMDB_FILE_CIF            1
-#define MMDB_FILE_Binary         2
-
-// cleanup flags:
-#define PDBCLEAN_ATNAME         0x00000001
-#define PDBCLEAN_TER            0x00000002
-#define PDBCLEAN_CHAIN          0x00000004
-#define PDBCLEAN_CHAIN_STRONG   0x00000008
-#define PDBCLEAN_ALTCODE        0x00000010
-#define PDBCLEAN_ALTCODE_STRONG 0x00000020
-#define PDBCLEAN_SERIAL         0x00000040
-#define PDBCLEAN_SEQNUM         0x00000080
-#define PDBCLEAN_CHAIN_ORDER    0x00000100
-#define PDBCLEAN_CHAIN_ORDER_IX 0x00000200
-#define PDBCLEAN_SOLVENT        0x00000400
-#define PDBCLEAN_INDEX          0x00000800
-#define PDBCLEAN_ELEMENT        0x00001000
-#define PDBCLEAN_ELEMENT_STRONG 0x00002000
-
-
-// crystallographic info inquery
-#define  CRRDY_NotPrecise       0x00000001
-#define  CRRDY_isTranslation    0x00000002
-#define  CRRDY_NoOrthCode       0x00000004
-
-#define  CRRDY_Complete            0
-#define  CRRDY_NoTransfMatrices   -1
-#define  CRRDY_Unchecked          -2
-#define  CRRDY_Ambiguous          -3
-#define  CRRDY_NoCell             -4
-#define  CRRDY_NoSpaceGroup       -5
-
-
-DefineClass(CMMDBFile)
-DefineStreamFunctions(CMMDBFile)
-
-class CMMDBFile : public CUDData  {
-
-  friend class CModel;
-  friend class CChain;
-  friend class CResidue;
-  friend class CAtom;
-  friend class CChannel;
-
-  public :
-
-    CMMDBFile ();
-    CMMDBFile ( RPCStream Object );
-    ~CMMDBFile();
-
-    void  FreeFileMemory();
-
-
-    //  ---------------  Reading/Writing external files  ---------
-
-    void  SetFlag        ( word Flag );
-    void  RemoveFlag     ( word Flag );
-
-    int   ReadPDBASCII   ( cpstr PDBFileName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadPDBASCII1  ( cpstr PDBLFName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadPDBASCII   ( RCFile f );
-
-    int   ReadCIFASCII   ( cpstr CIFFileName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadCIFASCII1  ( cpstr CIFLFName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadCIFASCII   ( RCFile f );
-    int   ReadFromCIF    ( PCMMCIFData CIFD        );
-
-    // adds info from PDB file
-    int   AddPDBASCII1   ( cpstr PDBLFName,
-                           byte gzipMode=GZM_CHECK );
-    int   AddPDBASCII    ( cpstr PDBFileName,
-                           byte gzipMode=GZM_CHECK );
-
-    // auto format recognition
-    int   ReadCoorFile   ( cpstr LFName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadCoorFile1  ( cpstr CFName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadCoorFile   ( RCFile f );
-
-    int   WritePDBASCII  ( cpstr PDBFileName,
-                           byte gzipMode=GZM_CHECK );
-    int   WritePDBASCII1 ( cpstr PDBLFName,
-                           byte gzipMode=GZM_CHECK );
-    void  WritePDBASCII  ( RCFile f );
-
-    int   WriteCIFASCII  ( cpstr CIFFileName,
-                           byte gzipMode=GZM_CHECK );
-    int   WriteCIFASCII1 ( cpstr CIFLFName,
-                           byte gzipMode=GZM_CHECK );
-
-    int   ReadMMDBF      ( cpstr MMDBFileName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadMMDBF1     ( cpstr MMDBLFName,
-                           byte gzipMode=GZM_CHECK );
-    int   ReadMMDBF      ( RCFile f );
-    int   WriteMMDBF     ( cpstr MMDBFileName,
-                           byte gzipMode=GZM_CHECK );
-    int   WriteMMDBF1    ( cpstr MMDBLFName,
-                           byte gzipMode=GZM_CHECK );
-
-    void  GetInputBuffer ( pstr Line, int & count );
-
-    //  PutPDBString adds a PDB-keyworded string
-    // to the existing structure. Note that the string
-    // is namely added meaning that it will be the
-    // last REMARK, last JRNL, last ATOM etc. string
-    // -- always the last one in its group.
-    int   PutPDBString   ( cpstr PDBString );
-
-
-
-    //  PDBCleanup(..) cleans coordinate part to comply with PDB
-    // standards and MMDB "expectations":
-    //
-    //  PDBCLEAN_ATNAME  pads atom names with spaces to form
-    //                   4-symbol names
-    //  PDBCLEAN_TER     inserts TER cards in the end of each chain
-    //  PDBCLEAN_CHAIN   generates 1-character chain ids instead of
-    //                   those many-character
-    //  PDBCLEAN_CHAIN_STRONG generates 1-character chain ids starting
-    //                   from 'A' on for all ids, including the
-    //                   single-character ones
-    //  PDBCLEAN_ALTCODE generates 1-character alternative codes
-    //                   instead of many-character ones
-    //  PDBCLEAN_ALTCODE_STRONG generates 1-character alternative codes
-    //                   from 'A' on for all codes, including the
-    //                   single-character ones
-    //  PDBCLEAN_SERIAL  puts serial numbers in due order
-    //  PDBCLEAN_SEQNUM  renumbers all residues so that they go
-    //                   incrementally-by-one without insertion codes
-    //  PDBCLEAN_CHAIN_ORDER puts chains in order of atom's serial
-    //                   numbers
-    //  PDBCLEAN_CHAIN_ORDER_IX puts chains in order of atom's
-    //                   indices internal to MMDB
-    //  PDBCLEAN_SOLVENT moves solvent chains at the end of each model
-    //
-    //  Return codes (as bits):
-    //  0                Ok
-    //  PDBCLEAN_CHAIN   too many chains for assigning them
-    //                   1-letter codes
-    //  PDBCLEAN_ATNAME  element names were not available
-    //  PDBCLEAN_ALTCODE too many alternative codes encountered.
-    //
-    word  PDBCleanup ( word CleanKey );
-
-    //     Makes all atoms in chain 'chainID', in all models, as
-    //  'Het' atoms if Make is set True, and makes them 'ordinary'
-    //  atoms otherwise. 'Ter' is automatically removed when
-    //  converting to 'Het' atoms, and is automatically added
-    //  when converting to 'ordinary' atoms. This may cause
-    //  disorder in serial numbers -- just call
-    //  PDBClean(PDBCLEAN_SERIAL) when necessary to fix this.
-    void  MakeHetAtoms ( cpstr chainID, Boolean Make );
-
-    //  ---------------  Working with atoms by serial numbers  ---
-
-    PPCAtom GetAtomArray  ()  { return Atom;   }
-    int GetAtomArrayLength()  { return AtmLen; } // strictly not for
-                                             // use in applications!!
-    PCAtom  GetAtomI ( int index );   // returns Atom[index-1]
-
-    //   PutAtom(..) puts atom with the specified properties
-    // into the structure. The current model is used; if no model
-    // is set (crModel==NULL), one is created. Coordinates and
-    // other parameters of the atom need to be set separately.
-    //   The place, at which the atom is put, is determined by
-    // index. If index is positive, then it points onto (index-1)th
-    // element of the Atom array (the index counts 1,2,... and
-    // generally coincides with the atom's serial number). If
-    // there is already an atom at this position in the system,
-    // the new atom will REPLACE it. The corresponding residues
-    // are automatically updated.
-    //   If index is null (=0), the new atom will be put on
-    // the top of the structure, i.e. it will be put into
-    // (index=nAtoms+1)-th position.
-    //   If index is negative, then the new atom is INSERTED
-    // BEFORE the atom in the (-index)th position. For saving
-    // the computational efforts, this WILL NOT cause the
-    // recalculation of all atoms' serial numbers according
-    // to their actual positions. It will be needed, however,
-    // for putting the things in order at a certain point,
-    // especially before writing an output ASCII file. NOTE
-    // that this ordering is never done automatically.
-    //   In a correct PDB file the serial number (serNum) is always
-    // equal to its position (index). However here we allow them
-    // to be different for easing the management of relations,
-    // particularly the connectivity.
-    //
-    //   Limitation: if PutAtom implies creating new
-    // chains/residues, these are always created on the top
-    // of existing chains/residues.
-    int   PutAtom ( int            index,
-                    int            serNum,
-                    const AtomName atomName,
-                    const ResName  resName,
-                    const ChainID  chainID,
-                    int            seqNum,
-                    const InsCode  insCode,
-                    const AltLoc   altLoc,
-                    const SegID    segID,
-                    const Element  element );
-
-    int   PutAtom (
-               int      index,    // same meaning as above
-               PCAtom   A,        // pointer to completed atom class
-               int      serNum=0  // 0 means that the serial number
-                                  // will be set equal to index.
-                                  // Otherwise the serial number
-                                  // is set to the specified
-                                  // value
-                  );
-
-
-    //    RemoveAtom(..) removes atom at the specified index
-    // in the Atom array. This index is always accessible
-    // as Atom[index]->index. If this leaves a residue empty,
-    // the residue is removed. If this leaves an empty chain,
-    // the chain is removed as well; the same happens to the
-    // model.
-    void  RemoveAtom ( int index );
-
-    int   FinishStructEdit();
-
-    void  TrimModelTable();
-
-    //  ----------------  Deleting models  -----------------------
-
-    int  DeleteAllModels  ();
-    Boolean GetNewChainID ( int modelNo, ChainID chID, int length=1 );
-
-    //  ---------------  Enquiring -------------------------------
-
-    int   CrystReady();
-    //    Returns flags:
-    // CRRDY_Complete       if crystallographic information is complete
-    // CRRDY_NotPrecise     if cryst. inf-n is not precise
-    // CRRDY_isTranslation  if cryst. inf-n contains translation
-    // CRRDY_NoOrthCode      no orthogonalization code
-    //    Fatal:
-    // CRRDY_NoTransfMatrices  if transform. matrices were not
-    //                         calculated
-    // CRRDY_Unchecked         if cryst. inf-n was not checked
-    // CRRDY_Ambiguous         if cryst. inf-n is ambiguous
-    // CRRDY_NoCell            if cryst. inf-n is unusable
-    // CRRDY_NoSpaceGroup      if space group is not set
-
-
-    Boolean isCrystInfo   ();  // cell parameters and space group
-    Boolean isCellInfo    ();  // cell param-s a,b,c, alpha,beta,gamma
-    Boolean isSpaceGroup  ();  // space group on CRYST1 card
-    Boolean isTransfMatrix();  // orthogonalizing/fractionalizing
-                               // matrices
-    Boolean isScaleMatrix ();  // SCALEx PDB records
-    Boolean isNCSMatrix   ();  // MTRIXx PDB records
-    int     GetNumberOfNCSMatrices();
-    int     GetNumberOfNCSMates   ();  // Returns the number of
-                                       // NCS mates not given in
-                                       // the file (iGiven==0)
-    Boolean GetNCSMatrix  ( int NCSMatrixNo, // 0..N-1
-                            mat44 & ncs_m, int & iGiven );
-
-    int GetNumberOfSymOps ();  // number of symmetry operations
-    pstr GetSymOp ( int Nop ); // XYZ symmetry operation name
-
-
-    //  -------------  User-Defined Data  ------------------------
-
-    int RegisterUDInteger ( int udr_type, cpstr UDDataID );
-    int RegisterUDReal    ( int udr_type, cpstr UDDataID );
-    int RegisterUDString  ( int udr_type, cpstr UDDataID );
-    int GetUDDHandle      ( int udr_type, cpstr UDDataID );
-
-    //  ----------------------------------------------------------
-
-    void  SetSyminfoLib ( cpstr syminfo_lib );
-    pstr  GetSyminfoLib ();
-    int   SetSpaceGroup ( cpstr spGroup );
-    pstr  GetSpaceGroup ();
-    pstr  GetSpaceGroupFix();
-
-    void  GetAtomStatistics ( RSAtomStat AS );
-
-    void  SetIgnoreSCALEi ( Boolean ignoreScalei );
-
-    //  SetCell(..) is for changing cell parameters
-    void  SetCell ( realtype cell_a,
-                    realtype cell_b,
-                    realtype cell_c,
-                    realtype cell_alpha,
-                    realtype cell_beta,
-                    realtype cell_gamma,
-                    int      OrthCode=0 );
-
-    //  PutCell(..) is for setting cell parameters
-    void  PutCell ( realtype cell_a,
-                    realtype cell_b,
-                    realtype cell_c,
-                    realtype cell_alpha,
-                    realtype cell_beta,
-                    realtype cell_gamma,
-                    int      OrthCode=0 );
-
-    int   GetCell ( realtype & cell_a,
-                    realtype & cell_b,
-                    realtype & cell_c,
-                    realtype & cell_alpha,
-                    realtype & cell_beta,
-                    realtype & cell_gamma,
-                    realtype & vol,
-                    int      & OrthCode );
-
-    int  GetRCell ( realtype & cell_as,
-                    realtype & cell_bs,
-                    realtype & cell_cs,
-                    realtype & cell_alphas,
-                    realtype & cell_betas,
-                    realtype & cell_gammas,
-                    realtype & vols,
-                    int      & OrthCode );
-
-    void GetROMatrix ( mat44 & RO );
-
-    //  GetTMatrix(..) calculates and returns the coordinate
-    //  transformation matrix, which converts orthogonal coordinates
-    //  according to the symmetry operation number Nop and places
-    //  them into unit cell shifted by cellshift_a a's, cellshift_b
-    //  b's and cellshift_c c's.
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    int GetTMatrix ( mat44 & TMatrix, int Nop,
-                     int cellshift_a, int cellshift_b,
-                     int cellshift_c );
-
-    //  GetUCTMatrix(..) calculates and returns the coordinate
-    //  transformation matrix, which converts orthogonal coordinates
-    //  according to the symmetry operation number Nop. Translation
-    //  part of the matrix is being chosen such that point (x,y,z)
-    //  has least distance to the center of primary (333) unit cell,
-    //  and then it is shifted by cellshift_a a's, cellshift_b b's and
-    //  cellshift_c c's.
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    int GetUCTMatrix ( mat44 & TMatrix, int Nop,
-                       realtype x, realtype y, realtype z,
-                       int cellshift_a, int cellshift_b,
-                       int cellshift_c );
-
-    //  GetFractMatrix(..) calculates and returns the coordinate
-    //  transformation matrix, which converts fractional coordinates
-    //  according to the symmetry operation number Nop and places them
-    //  into unit cell shifted by cellshift_a a's, cellshift_b b's
-    //  and cellshift_c c's.
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    int GetFractMatrix ( mat44 & TMatrix, int Nop,
-                         int cellshift_a, int cellshift_b,
-                         int cellshift_c );
-
-
-    //  GetSymOpMatrix(..) returns the transformation matrix for
-    //  Nop-th symmetry operator in the space group
-    //
-    //  Return 0 means everything's fine,
-    //         1 there's no symmetry operation Nop defined
-    //         2 fractionalizing/orthogonalizing matrices were not
-    //           calculated
-    //         3 cell parameters were not set up.
-    //
-    int GetSymOpMatrix ( mat44 & TMatrix, int Nop );
-
-
-    int   AddNCSMatrix    ( mat33 & ncs_m, vect3 & ncs_v, int iGiven );
-    int   GenerateNCSMates(); // 1: no NCS matrices, 0: Ok
-
-    pstr  GetEntryID ();
-    void  SetEntryID ( const IDCode idCode );
-
-    int   GetNofExpDataRecs();
-    pstr  GetExpDataRec ( int recNo );  // 0.. on
-
-    int   GetNofMdlTypeRecs();
-    pstr  GetMdlTypeRec ( int recNo );  // 0.. on
-
-    int   GetFileType() { return FType; }
-
-    void  Copy ( PCMMDBFile MMDBFile );
-
-    void  SetShortBinary();  // leaves only coordinates in binary files
-
-    // -------  user-defined data handlers
-    int   PutUDData ( int UDDhandle, int      iudd );
-    int   PutUDData ( int UDDhandle, realtype rudd );
-    int   PutUDData ( int UDDhandle, cpstr    sudd );
-
-    int   GetUDData ( int UDDhandle, int      & iudd );
-    int   GetUDData ( int UDDhandle, realtype & rudd );
-    int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
-    int   GetUDData ( int UDDhandle, pstr     & sudd );
-
-    // GetStructureTitle() returns the contents of TITLE record
-    // unfolded into single line. If Title is missing, returns
-    // contents of COMPND(:MOLECULE). If COMPND is missing, returns
-    // HEADER. If Header is missing, returns PDB code. If no PDB
-    // code is there, returns "Not available".
-    pstr  GetStructureTitle ( pstr & L );
-
-  protected :
-
-    word       Flags;    // special effect flags
-    int        FType;    // type of last file operation:
-                         //    -1 : none
-                         //     0 : PDB
-                         //     1 : CIF
-                         //     2 : BIN
-                         // encoded as MMDB_FILE_XXXXX above
-
-    CMMDBTitle  Title;   // title section
-    CMMDBCryst  Cryst;   // crystallographic information section
-    CUDRegister UDRegister; // register of user-defined data
-
-    int        nModels;  // number of models
-    PPCModel   Model;    // array of models [0..nModels-1]
-
-    int        nAtoms;   // number of atoms
-    int        AtmLen;   // length of Atom array
-    PPCAtom    Atom;     // array of atoms ordered by serial numbers
-
-    CAtomPath  DefPath;  // default coordinate path
-
-    CClassContainer SA;  // string container for unrecognized strings
-                         // which are between the title and the
-                         // crystallographic sections
-    CClassContainer Footnote;  // string container for footnotes
-    CClassContainer SB;  // string container for unrecognized strings
-                         // which are between the crystallographic and
-                         // the coordinate sections
-    CClassContainer SC;  // string container for unrecognized strings
-                         // following the coordinate section
-
-    //  input buffer
-    int         lcount;  // input line counter
-    char        S[500];  // read buffer
-    PCMMCIFData CIF;     // CIF file manager
-
-    PCModel     crModel; // current model, used at reading a PDB file
-    PCChain     crChain; // current chain, used at reading a PDB file
-    PCResidue   crRes;   // current residue, used at reading a PDB file
-
-    Boolean     Exclude;            // used internally
-    Boolean     ignoreRemarks;      // used temporarily
-    Boolean     allowDuplChID;      // used temporarily
-    Boolean     enforceUniqueChID;  // used temporarily
-
-    void  InitMMDBFile    ();
-    void  FreeCoordMemory ();
-    void  ReadPDBLine     ( RCFile f, pstr L, int maxlen );
-    int   ReadPDBAtom     ( cpstr L );
-    int   ReadCIFAtom     ( PCMMCIFData CIFD   );
-    int   CheckAtomPlace  ( int  index, cpstr L );
-    int   CheckAtomPlace  ( int  index, PCMMCIFLoop Loop );
-    int   SwitchModel     ( cpstr L );
-    int   SwitchModel     ( int nM );
-    int   AllocateAtom    ( int           index,
-                            const ChainID chainID,
-                            const ChainID label_asym_id,
-                            const ResName resName,
-                            const ResName label_comp_id,
-                            int           seqNum,
-                            int           label_seq_id,
-                            int           label_entity_id,
-                            const InsCode insCode,
-                            Boolean       Replace );
-    void  ExpandAtomArray ( int inc );
-    void  AddAtomArray    ( int inc );
-
-    void  ApplyNCSTransform ( int NCSMatrixNo );
-
-    virtual void ResetManager();
-
-    //  ---------------  Stream I/O  -----------------------------
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-    // don't use _ExcludeModel in your applications!
-    int   _ExcludeModel ( int serNum );
-
-    int   CheckInAtom   ( int index, PCAtom A );
-    int   CheckInAtoms  ( int index, PPCAtom A, int natms );
-
-    virtual PCMask GetSelMask ( int selHnd );
-
-  private :
-    int modelCnt;  // used only at reading files
-
-};
-
-
-
-//  isMMDBBIN will return
-//    -1   if file FName does not exist
-//     0   if file FName is likely a MMDB BIN (binary) file
-//     1   if file FName is not a MMDB BIN (binary) file
-//     2   if file FName is likely a MMDB BIN (binary) file,
-//         but of a wrong edition (i.e. produced by a lower
-//         version of MMDB).
-extern int isMMDBBIN ( cpstr FName, byte gzipMode=GZM_CHECK );
-extern int isMMDBBIN ( RCFile f );
-
-//  isPDB will return
-//    -1   if file FName does not exist
-//     0   if file FName is likely a PDB file
-//     1   if file FName is not a PDB file
-extern int isPDB ( cpstr FName, byte gzipMode=GZM_CHECK,
-                   Boolean IgnoreBlankLines=False );
-extern int isPDB ( RCFile f, Boolean IgnoreBlankLines=False );
-
-#endif
-
diff --git a/mmdb/mmdb_graph.cpp b/mmdb/mmdb_graph.cpp
deleted file mode 100755
index d598dbf..0000000
--- a/mmdb/mmdb_graph.cpp
+++ /dev/null
@@ -1,2460 +0,0 @@
-//  $Id: mmdb_graph.cpp,v 1.25 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    22.05.12   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_graph  <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CVertex     ( graph vertex                       )
-//       ~~~~~~~~~  CEdge       ( graph edge                         )
-//                  CGraph      ( structural graph                   )
-//                  CMatch      ( match of structural graphs         )
-//                  CGraphMatch ( CSIA algorithms for graph matching )
-//
-//   (C) E. Krissinel 2000-2012
-//
-//  When used, please cite:
-//
-//   Krissinel, E. and Henrick, K. (2004)
-//   Common subgraph isomorphism detection by backtracking search.
-//   Software - Practice and Experience, 34, 591-607.
-//
-//  =================================================================
-//
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MMDB_Graph__
-#include "mmdb_graph.h"
-#endif
-
-#ifndef  __MMDB_Tables__
-#include "mmdb_tables.h"
-#endif
-
-
-//  ==========================  CVertex  ============================
-
-CVertex::CVertex() : CStream()  {
-  InitVertex();
-}
-
-CVertex::CVertex ( RPCStream Object ) : CStream(Object)  {
-  InitVertex();
-}
-
-CVertex::CVertex ( cpstr chem_elem )
-       : CStream()  {
-  InitVertex();
-  SetVertex ( chem_elem );
-}
-
-CVertex::CVertex ( int vtype )
-       : CStream()  {
-  InitVertex();
-  SetVertex ( vtype );
-}
-
-CVertex::CVertex ( int vtype, cpstr vname )
-       : CStream()  {
-  InitVertex();
-  SetVertex ( vtype,vname );
-}
-
-CVertex::CVertex ( cpstr chem_elem, cpstr vname )
-       : CStream()  {
-  InitVertex ();
-  SetVertex  ( chem_elem  );
-  CreateCopy ( name,vname );
-}
-
-CVertex::~CVertex() {
-  if (name) delete[] name;
-}
-
-void  CVertex::InitVertex()  {
-  name     = NULL;
-  type     = 0;
-  type_ext = 0;
-  property = 0;
-  id       = 0;
-  user_id  = 0;
-}
-
-
-void  CVertex::SetVertex ( cpstr chem_elem )  {
-//   This function generates vertex type according to a chemical
-// element name passed in chem_elem.
-//
-//   The element type has the following meaning:
-//
-//     0xCHSSTTTT
-//
-// where
-//        T - resreved for elemenmt type
-//        S - resreved for symmetry relief
-//        H - reserved for hydrogen bonds
-//        C - resreved for chirality flags
-//
-// Note that when more than 2 symbols are used for chemical element
-// name (custom use), fields S may be reallocated for element type
-// and then symmetry relief becomes impossible.
-//
-  CreateCopy ( name,chem_elem );
-  type = getElementNo ( chem_elem );
-  if (type==ELEMENT_UNKNOWN)  {
-    type = 0;
-    if (name[0])  {
-      type = (int)name[0];
-      if (name[1])  {
-        type = type*256+(int)name[1];
-        if (name[2])  type = type*256+(int)name[2];
-      }
-    }
-    type += nElementNames;
-  }
-}
-
-void  CVertex::SetVertex ( int vtype )  {
-//  This function sets vertex type. See comments above for
-// the general rule for vertex types implied by this code.
-char N[50];
-int  type0;
-  type  = vtype;
-  type0 = vtype & TYPE_MASK;
-  if ((type0>=1) && (type0<=nElementNames))
-    CreateCopy ( name,ElementName[type0-1] );
-  else  {
-    sprintf    ( N,"%i",type );
-    CreateCopy ( name,N );
-  }
-}
-
-void  CVertex::SetType ( int vtype )  {
-  type = vtype;
-}
-
-void  CVertex::SetTypeExt  ( int typeExt )  {
-  type_ext = typeExt;
-}
-
-void  CVertex::SetVertex ( int vtype, cpstr vname )  {
-  type = vtype;
-  CreateCopy ( name,vname );
-}
-
-void  CVertex::SetName ( cpstr vname )  {
-  CreateCopy ( name,vname );
-}
-
-void  CVertex::SetID ( int vid )  {
-  id = vid;
-}
-
-void  CVertex::SetProperty ( int vprop )  {
-  property = vprop;
-}
-
-int   CVertex::GetNBonds()  {
-  return  ((type & HYDROGEN_BOND) >> 24);
-}
-
-void  CVertex::AddBond()  {
-int nb = GetNBonds()+1;
-  type &= ~HYDROGEN_BOND;
-  type |= nb << 24;
-}
-
-void  CVertex::CopyNBonds ( PCVertex V )  {
-int nb = V->GetNBonds();
-  type &= ~HYDROGEN_BOND;
-  type |= nb << 24;
-}
-
-void  CVertex::RemoveChirality()  {
-  type &= CHIRAL_MASK;
-}
-
-void  CVertex::LeaveChirality ( int eltype )  {
-// leaves chirality only on specified elements
-int vtype;
-  vtype = type & CHIRAL_MASK;
-  if (vtype!=eltype)  type = vtype;
-}
-
-void  CVertex::SaveType()  {
-  user_id = type;
-}
-
-void  CVertex::RestoreType()  {
-  type = user_id;
-}
-
-void  CVertex::CopyType ( PCVertex V )  {
-  type = V->type;
-}
-
-
-void  CVertex::Print ( int PKey )  {
-  if (PKey!=0)
-        printf ( "    name    type" );
-  else  printf ( " %10s  %5i",name,type );
-}
-
-void  CVertex::Copy ( PCVertex V )  {
-  CreateCopy ( name,V->name );
-  type     = V->type;
-  type_ext = V->type_ext;
-  property = V->property;
-  id       = V->id;
-  user_id  = V->user_id;
-}
-
-void  CVertex::write ( RCFile f )  {
-int Version=2;
-  f.WriteInt    ( &Version  );
-  f.CreateWrite ( name      );
-  f.WriteInt    ( &type     );
-  f.WriteInt    ( &property );
-  f.WriteInt    ( &id       );
-  f.WriteInt    ( &user_id  );
-  f.WriteInt    ( &type_ext );
-}
-
-void  CVertex::read  ( RCFile f )  {
-int Version;
-  f.ReadInt    ( &Version  );
-  f.CreateRead ( name      );
-  f.ReadInt    ( &type     );
-  f.ReadInt    ( &property );
-  f.ReadInt    ( &id       );
-  f.ReadInt    ( &user_id  );
-  if (Version>1)  f.ReadInt ( &type_ext );
-            else  type_ext = 0;
-}
-
-void  CVertex::mem_write ( pstr S, int & l )  {
-byte Version=2;
-  ::mem_write_byte ( Version,S,l );
-  ::mem_write ( name    ,S,l );
-  ::mem_write ( type    ,S,l );
-  ::mem_write ( property,S,l );
-  ::mem_write ( id      ,S,l );
-  ::mem_write ( user_id ,S,l );
-  ::mem_write ( type_ext,S,l );
-}
-
-void  CVertex::mem_read ( cpstr S, int & l )  {
-byte Version;
-  ::mem_read_byte ( Version,S,l );
-  ::mem_read ( name    ,S,l );
-  ::mem_read ( type    ,S,l );
-  ::mem_read ( property,S,l );
-  ::mem_read ( id      ,S,l );
-  ::mem_read ( user_id ,S,l );
-  ::mem_read ( type_ext,S,l );
-}
-
-MakeStreamFunctions(CVertex);
-
-
-
-//  ===========================  CEdge  =============================
-
-CEdge::CEdge() : CStream()  {
-  InitEdge();
-}
-
-CEdge::CEdge ( RPCStream Object ) : CStream(Object)  {
-  InitEdge();
-}
-
-CEdge::CEdge ( int vx1, int vx2, int btype )  {
-  InitEdge();
-  SetEdge ( vx1,vx2,btype );
-}
-
-CEdge::~CEdge()  {}
-
-void  CEdge::InitEdge()  {
-  v1       = 0;
-  v2       = 0;
-  type     = 0;
-  property = 0;
-}
-
-
-#define NofBondTypes  4
-
-static pstr BondType[NofBondTypes+1] = {
-  pstr("SING"), pstr("DOUB"), pstr("AROM"), pstr("TRIP"),
-  pstr("")  // should be here for safety
-};
-
-
-void  CEdge::SetEdge ( int vx1, int vx2, cpstr btype )  {
-  v1   = vx1;
-  v2   = vx2;
-  type = 0;
-  while (type<NofBondTypes)
-    if (!strncasecmp(btype,BondType[type],4))  break;
-                                         else  type++;
-  if (type>=NofBondTypes)  {
-    type = 0;
-    if (btype[0])  type = (int)btype[0];
-    if (btype[1])  type = type*16+(int)btype[1];
-    if (btype[2])  type = type*16+(int)btype[2];
-    type += NofBondTypes;
-  }
-  type++;
-}
-
-void  CEdge::SetEdge ( int vx1, int vx2, int btype )  {
-  v1   = vx1;
-  v2   = vx2;
-  type = btype;
-}
-
-void  CEdge::SetType ( int btype )  {
-  type = btype;
-}
-
-void  CEdge::SetProperty ( int eprop )  {
-  property = eprop;
-}
-
-void  CEdge::SaveType()  {
-  property = type;
-}
-
-void  CEdge::RestoreType()  {
-  type = property;
-}
-
-void  CEdge::Print ( int PKey )  {
-  if (PKey!=0)
-        printf ( "   v1  v2  type" );
-  else  printf ( " %5i %5i  %5i",v1,v2,type );
-}
-
-void  CEdge::Copy ( PCEdge G )  {
-  v1       = G->v1;
-  v2       = G->v2;
-  type     = G->type;
-  property = G->property;
-}
-
-void  CEdge::write ( RCFile f )  {
-int Version=1;
-  f.WriteInt ( &Version  );
-  f.WriteInt ( &v1       );
-  f.WriteInt ( &v2       );
-  f.WriteInt ( &type     );
-  f.WriteInt ( &property );
-}
-
-void  CEdge::read  ( RCFile f )  {
-int Version;
-  f.ReadInt ( &Version  );
-  f.ReadInt ( &v1       );
-  f.ReadInt ( &v2       );
-  f.ReadInt ( &type     );
-  f.ReadInt ( &property );
-}
-
-void  CEdge::mem_write ( pstr S, int & l )  {
-byte Version=1;
-  ::mem_write_byte ( Version,S,l );
-  ::mem_write ( v1      ,S,l );
-  ::mem_write ( v2      ,S,l );
-  ::mem_write ( type    ,S,l );
-  ::mem_write ( property,S,l );
-}
-
-void  CEdge::mem_read ( cpstr S, int & l )  {
-byte Version;
-  ::mem_read_byte ( Version,S,l );
-  ::mem_read ( v1      ,S,l );
-  ::mem_read ( v2      ,S,l );
-  ::mem_read ( type    ,S,l );
-  ::mem_read ( property,S,l );
-}
-
-
-MakeStreamFunctions(CEdge);
-
-
-
-//  ==========================  CGraph  ============================
-
-CGraph::CGraph() : CStream()  {
-  InitGraph();
-}
-
-CGraph::CGraph ( PCResidue R, cpstr altLoc ) : CStream()  {
-  InitGraph();
-  MakeGraph ( R,altLoc );
-}
-
-CGraph::CGraph ( RPCStream Object ) : CStream(Object)  {
-  InitGraph();
-}
-
-CGraph::~CGraph()  {
-  FreeMemory();
-}
-
-void CGraph::InitGraph()  {
-  nVAlloc      = 0;
-  nEAlloc      = 0;
-  nGAlloc      = 0;
-  nVertices    = 0;
-  nEdges       = 0;
-  nAllVertices = 0;
-  nAllEdges    = 0;
-  Vertex       = NULL;
-  Edge         = NULL;
-  graph        = NULL;
-  name         = NULL;
-  CreateCopy ( name,pstr("UNNAMED") );
-}
-
-void CGraph::FreeMemory()  {
-int i;
-
-  if (Vertex)  {
-    for (i=0;i<nVAlloc;i++)
-      if (Vertex[i])
-        delete Vertex[i];
-    delete[] Vertex;
-  }
-  nVAlloc      = 0;
-  nVertices    = 0;
-  nAllVertices = 0;
-  Vertex       = NULL;
-
-  if (Edge)  {
-    for (i=0;i<nEAlloc;i++)
-      if (Edge[i])
-        delete Edge[i];
-    delete[] Edge;
-  }
-  nEAlloc   = 0;
-  nEdges    = 0;
-  nAllEdges = 0;
-  Edge      = NULL;
-
-  FreeMatrixMemory ( graph,nGAlloc,1,1 );
-  nGAlloc = 0;
-
-  if (name)  delete[] name;
-  name = NULL;
-
-}
-
-void  CGraph::Reset()  {
-  FreeMemory();
-  CreateCopy ( name,pstr("UNNAMED") );
-}
-
-void  CGraph::SetName ( cpstr gname )  {
-  CreateCopy ( name,gname );
-}
-
-
-static int AllocPortion = 100;
-
-void  SetGraphAllocPortion ( int alloc_portion )  {
-  AllocPortion = alloc_portion;
-}
-
-void  CGraph::AddVertex ( PCVertex V )  {
-int        i;
-PCVertex * V1;
-
-  if (nAllVertices>=nVAlloc)  {
-    nVAlloc += AllocPortion;
-    V1       = new PCVertex[nVAlloc];
-    for (i=0;i<nAllVertices;i++)
-      V1[i] = Vertex[i];
-    for (i=nAllVertices;i<nVAlloc;i++)
-      V1[i] = NULL;
-    if (Vertex)  delete[] Vertex;
-    Vertex = V1;
-  }
-  if (Vertex[nAllVertices])
-    delete Vertex[nAllVertices];
-  Vertex[nAllVertices] = V;
-  nAllVertices++;
-  nVertices = nAllVertices;
-
-}
-
-void  CGraph::SetVertices ( PPCVertex V, int vlen )  {
-  if (nVAlloc>0)  FreeMemory();
-  Vertex       = V;
-  nVertices    = vlen;
-  nAllVertices = vlen;
-  nVAlloc      = vlen;
-}
-
-int  CGraph::GetVertexID ( int vertexNo )  {
-  if ((vertexNo>0) && (vertexNo<=nAllVertices))
-        return Vertex[vertexNo-1]->GetID();
-  else  return MinInt4;
-}
-
-int  CGraph::GetNBondedVertices ( int vertexNo )  {
-  if ((vertexNo>0) && (vertexNo<=nAllVertices))  {
-    if (Vertex[vertexNo-1])
-      return Vertex[vertexNo-1]->GetNBonds();
-  }
-  return 0;
-}
-
-int  CGraph::GetBondedVertexID ( int vertexNo, int bond_vx_type,
-                                 int bondNo )  {
-int i,k, v1,v2;
-  if ((vertexNo>0) && (vertexNo<=nAllVertices))  {
-    if (Vertex[vertexNo-1])  {
-      if (Vertex[vertexNo-1]->GetNBonds()>=bondNo)  {
-        k = 0;
-        for (i=0;(i<nAllEdges) && (!k);i++)
-          if (Edge[i])  {
-            v1 = Edge[i]->v1;
-            v2 = Edge[i]->v2;
-            if ((v1==vertexNo) &&
-                ((Vertex[v2-1]->type & TYPE_MASK)==bond_vx_type) &&
-                 (Vertex[v2-1]->GetNBonds()==bondNo))
-               k = v2;
-            if ((v2==vertexNo) &&
-                ((Vertex[v1-1]->type & TYPE_MASK)==bond_vx_type) &&
-                 (Vertex[v2-1]->GetNBonds()==bondNo))
-               k = v1;
-          }
-        if (k)  return Vertex[k-1]->GetID();
-      }
-    }
-  }
-  return MinInt4;
-}
-
-PCVertex CGraph::GetVertex ( int vertexNo )  {
-  if ((vertexNo>0) && (vertexNo<=nAllVertices))
-        return Vertex[vertexNo-1];
-  else  return NULL;
-}
-
-int  CGraph::GetVertexNo ( cpstr vname )  {
-int  i,k;
-  k = 0;
-  if (vname)
-    for (i=0;(i<nAllVertices) && (!k);i++)
-      if (!strcmp(vname,Vertex[i]->name))
-        k = i+1;
-  return k;
-}
-
-PCEdge CGraph::GetEdge ( int edgeNo )  {
-  if ((edgeNo>0) && (edgeNo<=nAllEdges))
-        return Edge[edgeNo-1];
-  else  return NULL;
-}
-
-void  CGraph::AddEdge ( PCEdge G )  {
-int     i;
-PPCEdge G1;
-
-  if (nAllEdges>=nEAlloc)  {
-    nEAlloc += AllocPortion;
-    G1       = new PCEdge[nEAlloc];
-    for (i=0;i<nAllEdges;i++)
-      G1[i] = Edge[i];
-    for (i=nAllEdges;i<nEAlloc;i++)
-      G1[i] = NULL;
-    if (Edge)  delete[] Edge;
-    Edge = G1;
-  }
-  if (Edge[nAllEdges])
-    delete Edge[nAllEdges];
-  Edge[nAllEdges] = G;
-  nAllEdges++;
-  nEdges = nAllEdges;
-
-}
-
-void  CGraph::SetEdges ( PPCEdge G, int glen )  {
-  if (nEAlloc>0)  FreeMemory();
-  Edge      = G;
-  nEdges    = glen;
-  nAllEdges = glen;
-  nEAlloc   = glen;
-}
-
-void  CGraph::GetVertices ( PPCVertex & V, int & nV )  {
-  V  = Vertex;
-  nV = nVertices;
-}
-
-void  CGraph::GetEdges ( PPCEdge & E, int & nE )  {
-  E  = Edge;
-  nE = nEdges;
-}
-
-
-int  CGraph::MakeGraph ( PCResidue R, cpstr altLoc )  {
-int      i,j, a1,a2,e1,e2, nAltLocs,alflag, rc;
-Boolean  B;
-rvector  occupancy;
-AltLoc   aLoc;
-PAltLoc  aL;
-realtype dx,dy,dz, sr;
-PCEdge   G;
-
-  rc = MKGRAPH_Ok;
-  //  reset graph
-  FreeMemory();
-
-  occupancy = NULL;
-  aL        = NULL;
-  R->GetAltLocations ( nAltLocs,aL,occupancy,alflag );
-  if (nAltLocs<=0)  return MKGRAPH_NoAtoms;
-
-  if (altLoc)  strcpy ( aLoc,altLoc );
-         else  aLoc[0] = char(0);
-  if (nAltLocs<=1)  {
-    // Only one alt code is there, check if it is what was ordered
-    if (strcmp(aLoc,aL[0]))  {
-      rc = MKGRAPH_ChangedAltLoc;
-      strcpy ( aLoc,aL[0] );
-    }
-  } else if ((alflag & ALF_Mess) ||
-             ((alflag & ALF_NoEmptyAltLoc) && (!aLoc[0])))  {
-    // There is a mess in the residue alt codes, or empty alt code
-    // does not designate a conformation but ordered. In this
-    // situation build graph for maximal-occupancy conformation
-    // and store its altLoc in aLoc.
-    rc = MKGRAPH_MaxOccupancy;
-    dx = -2.0;
-    for (i=0;i<nAltLocs;i++)
-      if ((aL[i][0]) && (occupancy[i]>dx))  {
-        dx = occupancy[i];
-        strcpy ( aLoc,aL[i] );
-      }
-  }
-
-  SetName ( R->name );
-
-  nVAlloc = R->nAtoms;  // upper estimate for vertices to allocate
-  if (nVAlloc<=0)  {
-    if (aL)  delete[] aL;
-    FreeVectorMemory ( occupancy,0 );
-    return MKGRAPH_NoAtoms;
-  }
-
-  //  allocate vertex array
-  Vertex = new PCVertex[nVAlloc];
-  for (i=0;i<nVAlloc;i++)
-    Vertex[i] = NULL;
-
-  //  make vertices
-  for (i=0;i<R->nAtoms;i++)
-    if (R->atom[i])  {
-      if (!R->atom[i]->Ter)  {
-        if (nAltLocs>1)  {
-          // This is a many-altcode residue. aLoc contains the altcode
-          // that has to be included. Check on it:
-          B = !strcmp(aLoc,R->atom[i]->altLoc);
-          if ((!B) && (!R->atom[i]->altLoc[0]))  {
-            // We got a non-aLoc code that is an "empty-altcode".
-            // Check if this atom has the altcode that we need.
-            for (j=i+1;(j<R->nAtoms) && (!B);j++)
-              if (R->atom[j])  {
-                if ((!R->atom[j]->Ter) &&
-                    (!strcmp(R->atom[j]->name,R->atom[i]->name)))
-                  B = !strcmp(aLoc,R->atom[j]->altLoc);
-              }
-            // if altcode=aLoc is not there for the atom (B is set
-            // False) then we take its "empty-code" location
-            B = !B;
-          }
-        } else
-          B = True;
-        if (B)  {
-          Vertex[nVertices] = new CVertex ( R->atom[i]->element,
-                                            R->atom[i]->name );
-          Vertex[nVertices]->id      = nVertices;
-          Vertex[nVertices]->user_id = i;
-          nVertices++;
-        }
-      }
-    }
-
-  if (nVertices<=0)  {
-    if (aL)  delete[] aL;
-    FreeVectorMemory ( occupancy,0 );
-    return MKGRAPH_NoAtoms;
-  }
-
-  //  make edges
-  nEAlloc = 3*nVertices;
-  Edge    = new PCEdge[nEAlloc];
-  for (i=0;i<nEAlloc;i++)
-    Edge[i] = NULL;
-
-  for (i=0;i<nVertices;i++)  {
-    a1 = Vertex[i]->user_id;
-    e1 = Vertex[i]->type;
-    if (e1>nElementNames)  e1 = 6;
-    e1--;
-    for (j=i+1;j<nVertices;j++)  {
-      a2 = Vertex[j]->user_id;
-      e2 = Vertex[j]->type;
-      if (e2>nElementNames)  e2 = 6;
-      e2--;
-      dx = R->atom[a2]->x - R->atom[a1]->x;
-      dy = R->atom[a2]->y - R->atom[a1]->y;
-      dz = R->atom[a2]->z - R->atom[a1]->z;
-//      sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.15;
-      sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.25;
-      if (dx*dx+dy*dy+dz*dz<sr*sr)  {  // it's a bond
-        G = new CEdge(i+1,j+1,1);
-        AddEdge ( G );
-      }
-    }
-    Vertex[i]->id = i+1;
-  }
-
-  if (aL)  delete[] aL;
-  FreeVectorMemory ( occupancy,0 );
-
-  nAllVertices = nVertices;
-  nAllEdges    = nEdges;
-
-  return rc;
-
-}
-
-int  CGraph::MakeGraph ( PPCAtom atom, int nAtoms )  {
-PCEdge   G;
-char     atomID[100];
-realtype dx,dy,dz, sr;
-int      i,j, a1,a2,e1,e2, rc;
-
-  rc = MKGRAPH_Ok;
-  //  reset graph
-  FreeMemory();
-
-  nVAlloc = nAtoms;  // upper estimate for vertices to allocate
-  if (nVAlloc<=0)  return MKGRAPH_NoAtoms;
-
-  //  allocate vertex array
-  Vertex = new PCVertex[nVAlloc];
-  for (i=0;i<nVAlloc;i++)
-    Vertex[i] = NULL;
-
-  //  make vertices
-  for (i=0;i<nAtoms;i++)
-    if (atom[i])  {
-      if (!atom[i]->Ter)  {
-        Vertex[nVertices] = new CVertex ( atom[i]->element,
-                                 atom[i]->GetAtomIDfmt(atomID) );
-        Vertex[nVertices]->user_id = i;
-        nVertices++;
-      }
-    }
-
-  if (nVertices<=0)  {
-    FreeMemory();
-    return MKGRAPH_NoAtoms;
-  }
-
-  //  make edges
-  nEAlloc = 3*nVertices;  // just an inital guess
-  Edge    = new PCEdge[nEAlloc];
-  for (i=0;i<nEAlloc;i++)
-    Edge[i] = NULL;
-
-  for (i=0;i<nVertices;i++)  {
-    a1 = Vertex[i]->user_id;
-    e1 = Vertex[i]->type;
-    if (e1>nElementNames)  e1 = 6;
-    e1--;
-    for (j=i+1;j<nVertices;j++)  {
-      a2 = Vertex[j]->user_id;
-      e2 = Vertex[j]->type;
-      if (e2>nElementNames)  e2 = 6;
-      e2--;
-      dx = atom[a2]->x - atom[a1]->x;
-      dy = atom[a2]->y - atom[a1]->y;
-      dz = atom[a2]->z - atom[a1]->z;
-      sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.25;
-      if (dx*dx+dy*dy+dz*dz<sr*sr)  {  // it's a bond
-        G = new CEdge(i+1,j+1,1); // don't guess on bond order here
-        AddEdge ( G );
-      }
-    }
-    Vertex[i]->id = i+1;
-  }
-
-  nAllVertices = nVertices;
-  nAllEdges    = nEdges;
-
-  return rc;
-
-}
-
-
-void  CGraph::MakeVertexIDs()  {
-int i;
-  for (i=0;i<nAllVertices;i++)
-    Vertex[i]->id = i+1;
-}
-
-void  CGraph::HideType ( int bond_vx_type )  {
-//  1. Moves vertices bond_vx_type to the end of vertex array
-//  2. Moves edges to bond_vx_type vertices to the end of edge array
-//  3. Saves lengths of full vertex and edge arrays, and redefines
-//     lengths to initial parts of the arrays not containing
-//     bond_vx_type vertices.
-PPCEdge   Edge1;
-PPCVertex Vertex1;
-int       i,k,v1,v2, nEdges1,nVertices1;
-ivector   iv;
-
-  Edge1   = new PCEdge[nEdges];
-  Vertex1 = new PCVertex[nVertices];
-  GetVectorMemory ( iv,nVertices,1 );
-
-  for (i=0;i<nEdges;i++)
-    if (Edge[i])  {
-      v1 = Edge[i]->v1-1;
-      v2 = Edge[i]->v2-1;
-      if (Vertex[v1] && Vertex[v2])  {
-        if ((Vertex[v1]->type & TYPE_MASK)==bond_vx_type)  {
-          Vertex[v2]->AddBond();
-          Vertex[v1]->CopyNBonds ( Vertex[v2] );
-        }
-        if ((Vertex[v2]->type & TYPE_MASK)==bond_vx_type)  {
-          Vertex[v1]->AddBond();
-          Vertex[v2]->CopyNBonds ( Vertex[v1] );
-        }
-      }
-    }
-
-  nVertices1 = 0;
-  for (i=0;i<nVertices;i++)
-    if (Vertex[i])  {
-      if ((Vertex[i]->type & TYPE_MASK)!=bond_vx_type)  {
-        Vertex1[nVertices1++] = Vertex[i];
-        iv[i+1] = nVertices1;
-      }
-    }
-  k = nVertices1;
-  for (i=0;i<nVertices;i++)
-    if (Vertex[i])  {
-      if ((Vertex[i]->type & TYPE_MASK)==bond_vx_type)  {
-        Vertex1[k++] = Vertex[i];
-        iv[i+1] = k;
-      }
-    }
-
-  nEdges1 = 0;
-  for (i=0;i<nEdges;i++)
-    if (Edge[i])  {
-      Edge[i]->v1 = iv[Edge[i]->v1];
-      Edge[i]->v2 = iv[Edge[i]->v2];
-      if (((Vertex1[Edge[i]->v1-1]->type & TYPE_MASK)!=bond_vx_type) &&
-          ((Vertex1[Edge[i]->v2-1]->type & TYPE_MASK)!=bond_vx_type))
-        Edge1[nEdges1++] = Edge[i];
-    }
-  k = nEdges1;
-  for (i=0;i<nEdges;i++)
-    if (Edge[i])  {
-      if (((Vertex1[Edge[i]->v1-1]->type & TYPE_MASK)==bond_vx_type) ||
-          ((Vertex1[Edge[i]->v2-1]->type & TYPE_MASK)==bond_vx_type))
-        Edge1[k++] = Edge[i];
-    }
-
-  nAllVertices = nVertices;
-  nAllEdges    = nEdges;
-  nVAlloc      = nVertices;
-  nEAlloc      = nEdges;
-  nVertices    = nVertices1;
-  nEdges       = nEdges1;
-
-  if (Vertex)  delete[] Vertex;
-  if (Edge)    delete[] Edge;
-  FreeVectorMemory ( iv,1 );
-
-  Vertex = Vertex1;
-  Edge   = Edge1;
-
-}
-
-void  CGraph::ExcludeType ( int type )  {
-int     i,k;
-ivector iv;
-  GetVectorMemory ( iv,nAllVertices,1 );
-  k = 0;
-  for (i=0;i<nAllVertices;i++)
-    if ((Vertex[i]->type & TYPE_MASK)!=type)  {
-      if (k<i)  {
-        Vertex[k] = Vertex[i];
-        Vertex[i] = NULL;
-      }
-      k++;
-      iv[i+1] = k;
-    } else  {
-      delete Vertex[i];
-      Vertex[i] = NULL;
-      iv[i+1]   = 0;
-    }
-  nAllVertices = k;
-  nVertices = nAllVertices;
-  k = 0;
-  for (i=0;i<nAllEdges;i++)
-    if ((iv[Edge[i]->v1]!=0) && (iv[Edge[i]->v2]!=0))  {
-      if (k<i)  {
-        Edge[k] = Edge[i];
-        Edge[i] = NULL;
-      }
-      Edge[k]->v1 = iv[Edge[k]->v1];
-      Edge[k]->v2 = iv[Edge[k]->v2];
-      k++;
-    } else  {
-      delete Edge[i];
-      Edge[i] = NULL;
-    }
-  nAllEdges = k;
-  nEdges = nAllEdges;
-  FreeVectorMemory ( iv,1 );
-}
-
-void CGraph::RemoveChirality()  {
-int i;
-  for (i=0;i<nAllVertices;i++)
-    if (Vertex[i])  Vertex[i]->RemoveChirality();
-}
-
-void CGraph::LeaveChirality ( int eltype )  {
-// leaves chirality for specified atom types
-int i;
-  for (i=0;i<nAllVertices;i++)
-    if (Vertex[i])  Vertex[i]->LeaveChirality ( eltype );
-}
-
-void CGraph::MakeSymmetryRelief ( Boolean noCO2 )  {
-//  This function looks for groups of equivalent vertices
-// attached to a single vertice (e.g. chemical SO3 or
-// PO3 groups), and re-lables them by adding a unique
-// symmetry-relief number. This eliminates equivalent
-// matches (3! for each SO3/PO3 group), and increases
-// vertex diversity, which considerably speeds up matching.
-// The function is cheap and harmless even if such groups
-// of vertices are not found.
-//  If noCO2 is True then CO2 symmetry is not releaved.
-ivector v,vc;
-int     i,j,k,n,m,almask,vjtype, ctype,otype;
-Boolean noOxygens;
-
-  otype = 0;
-  ctype = 0;
-
-  GetVectorMemory ( v ,nVertices,0 );
-  GetVectorMemory ( vc,nVertices,1 );
-
-  for (i=1;i<=nVertices;i++)
-    vc[i] = 0;
-
-  for (j=0;j<nEdges;j++)  {
-    if ((Edge[j]->v1>0) && (Edge[j]->v1<=nVertices))
-      vc[Edge[j]->v1]++;
-    if ((Edge[j]->v2>0) && (Edge[j]->v2<=nVertices))
-      vc[Edge[j]->v2]++;
-  }
-
-  almask = ~ATOM_LEAVING;
-
-  if (noCO2)  {
-    ctype = getElementNo ( "C" );
-    otype = getElementNo ( "O" );
-  }
-
-  noOxygens = False;
-
-  for (i=1;i<=nVertices;i++)
-    if (vc[i]>1)  {  // vertex at more than 1 edge
-      // v[] will list connected vertices, k will be their number
-      k = 0;
-      for (j=0;j<nEdges;j++)  {
-        if ((Edge[j]->v1==i) && (vc[Edge[j]->v2]==1) && (k<nVertices))
-          v[k++] = Edge[j]->v2-1;
-        if ((Edge[j]->v2==i) && (vc[Edge[j]->v1]==1) && (k<nVertices))
-          v[k++] = Edge[j]->v1-1;
-      }
-      if (k>1)  {
-        if (noCO2) noOxygens = ((Vertex[i-1]->type & almask)==ctype);
-        // A group of vertices with single connection is
-        // identified. Assign symmetry relief modifiers
-        // to *equivalent* vertices in the group
-        for (j=0;j<k;j++)
-          if ((v[j]>=0) && (v[j]<nVertices))  {
-            vjtype = Vertex[v[j]]->type & almask;
-            if ((!noOxygens) || (vjtype!=otype))  {
-              n = 1; // symmetry relief modifier
-              for (m=j+1;m<k;m++)
-                if ((v[m]>=0) && (v[m]<nVertices))  {
-                  if (Vertex[v[j]]->type==
-                      (Vertex[v[m]]->type & almask))  {
-                    Vertex[v[m]]->type |= (n << 16);
-                    n++;
-                    v[m] = -1;
-                  }
-                }
-            }
-          }
-      }
-    }
-
-  FreeVectorMemory ( v ,0 );
-  FreeVectorMemory ( vc,1 );
-
-}
-
-int  CGraph::Build ( Boolean bondOrder )  {
-int i,j, rc;
-
-  if (nVertices<=0)  return 2;
-
-  if (nGAlloc<nVertices)  {
-    FreeMatrixMemory ( graph,nGAlloc,1,1 );
-    nGAlloc = nVertices;
-    GetMatrixMemory ( graph,nGAlloc,nGAlloc,1,1 );
-  }
-
-  for (i=1;i<=nVertices;i++)
-    for (j=1;j<=nVertices;j++)
-      graph[i][j] = 0;
-
-  rc = 0;
-  if (bondOrder)  {
-
-    for (i=0;(i<nEdges) && (!rc);i++)
-      if ((Edge[i]->v1>=1) && (Edge[i]->v1<=nVertices) &&
-          (Edge[i]->v2>=1) && (Edge[i]->v2<=nVertices))  {
-        graph[Edge[i]->v1][Edge[i]->v2] = Edge[i]->type;
-        graph[Edge[i]->v2][Edge[i]->v1] = Edge[i]->type;
-      } else
-        rc = 1;
-
-  } else  {
-
-    for (i=0;i<nEdges;i++)
-      if ((Edge[i]->v1>=1) && (Edge[i]->v1<=nVertices) &&
-          (Edge[i]->v2>=1) && (Edge[i]->v2<=nVertices))  {
-        graph[Edge[i]->v1][Edge[i]->v2] = 1;
-        graph[Edge[i]->v2][Edge[i]->v1] = 1;
-      } else
-        rc = 1;
-
-  }
-
-  return rc;
-
-}
-
-
-const int ring_mask[] = {
-  0x00000000,
-  0x00000000,
-  0x00000000,
-  0x00000001,
-  0x00000002,
-  0x00000004,
-  0x00000008,
-  0x00000010,
-  0x00000020,
-  0x00000040,
-  0x00000080
-};
-
-void CGraph::IdentifyRings()  {
-CGraphMatch GM;
-CGraph      ring;
-ivector     F1,F2;
-AtomName    aname;
-realtype    p1,p2;
-int         i,j,n,nrings,nv;
-
-  Build ( False );
-
-  for (i=0;i<nVertices;i++)
-    Vertex[i]->type_ext = 0;
-
-  GM.SetFlag ( GMF_UniqueMatch );
-
-  for (n=3;n<=10;n++)  {
-
-    ring.Reset();
-
-    for (i=1;i<=n;i++)  {
-      sprintf ( aname,"C%i",i );
-      ring.AddVertex ( new CVertex("C",aname) );
-    }
-
-    ring.MakeVertexIDs();
-
-    for (i=1;i<=n;i++)  {
-      j = i+1;
-      if (j>n) j = 1;
-      ring.AddEdge ( new CEdge(i,j,1) );
-    }
-
-    ring.Build ( False );
-
-    GM.MatchGraphs ( this,&ring,n,False,EXTTYPE_Ignore );
-
-    nrings = GM.GetNofMatches();
-    for (i=0;i<nrings;i++)  {
-      GM.GetMatch ( i,F1,F2,nv,p1,p2 );
-      for (j=1;j<nv;j++)
-        Vertex[F1[j]-1]->type_ext |= ring_mask[n];
-    }
-
-  }
-
-}
-
-void CGraph::markConnected ( int vno, int cno )  {
-int i;
-
-  Vertex[vno]->type_ext = cno;
-  for (i=0;i<nVertices;i++)
-    if (graph[vno+1][i+1] && (!Vertex[i]->type_ext))
-      markConnected ( i,cno );
-
-}
-
-
-int  CGraph::IdentifyConnectedComponents()  {
-// Returns the number of connected components and sets
-// Vertex[]->type_ext equal to component number >=1.
-int nComponents,i;
-
-  nComponents = 0;
-
-  Build ( False );
-
-  for (i=0;i<nVertices;i++)
-    Vertex[i]->type_ext = 0;
-
-  i = 0;
-  while (i<nVertices)  {
-    while (i<nVertices)
-      if (Vertex[i]->type_ext)  i++;
-                          else  break;
-    if (i<nVertices)  {
-      nComponents++;
-      markConnected ( i,nComponents );
-    }
-  }
-
-  return nComponents;
-
-}
-
-
-
-void  CGraph::Print()  {
-int i;
-
-  printf ( " =====  Graph %s \n\n",name );
-
-  if (nVertices>0) {
-    printf ( "  Vertices:\n""  ##   " );
-    Vertex[0]->Print(1);
-    printf ( "\n" );
-    for (i=0;i<nVertices;i++) {
-      printf ( " %4i  ",i+1 );
-      Vertex[i]->Print(0);
-      printf ( "\n" );
-    }
-  }
-
-  if (nEdges>0) {
-    printf ( "  Edges:\n""  ##   " );
-    Edge[0]->Print(1);
-    printf ( "\n" );
-    for (i=0;i<nEdges;i++) {
-      printf ( " %4i  ",i+1 );
-      Edge[i]->Print(0);
-      printf ( "\n" );
-    }
-  }
-
-
-}
-
-void  CGraph::Print1()  {
-int i,j;
-  for (i=0;i<nVertices;i++)  {
-    printf ( " %4i %5i %3i %7s ",
-             i+1,Vertex[i]->id,Vertex[i]->type,Vertex[i]->name );
-    for (j=0;j<nEdges;j++)
-      if (Edge[j]->v1==i+1)
-        printf ( " %4i(%i)",Edge[j]->v2,Edge[j]->type );
-      else if (Edge[j]->v2==i+1)
-        printf ( " %4i(%i)",Edge[j]->v1,Edge[j]->type );
-    printf ( "\n" );
-  }
-}
-
-
-void  CGraph::Copy ( PCGraph G )  {
-int     i;
-
-  FreeMemory();
-
-  CreateCopy ( name,G->name );
-  nVertices    = G->nVertices;
-  nEdges       = G->nEdges;
-  nAllVertices = G->nAllVertices;
-  nAllEdges    = G->nAllEdges;
-  if (nAllVertices>0)  {
-    nVAlloc = nAllVertices;
-    Vertex  = new PCVertex[nVAlloc];
-    for (i=0;i<nAllVertices;i++)  {
-      Vertex[i] = new CVertex();
-      Vertex[i]->Copy ( G->Vertex[i] );
-    }
-  }
-  if (nAllEdges>0)  {
-    nEAlloc = nAllEdges;
-    Edge    = new PCEdge[nEAlloc];
-    for (i=0;i<nAllEdges;i++)  {
-      Edge[i] = new CEdge();
-      Edge[i]->Copy ( G->Edge[i] );
-    }
-  }
-
-}
-
-void  CGraph::write ( RCFile f )  {
-int     i;
-int     Version=2;
-Boolean bondOrder=False;
-  f.WriteInt    ( &Version      );
-  f.WriteBool   ( &bondOrder    );
-  f.CreateWrite ( name          );
-  f.WriteInt    ( &nVertices    );
-  f.WriteInt    ( &nEdges       );
-  f.WriteInt    ( &nAllVertices );
-  f.WriteInt    ( &nAllEdges    );
-  for (i=0;i<nAllVertices;i++)
-    StreamWrite ( f,Vertex[i] );
-  for (i=0;i<nAllEdges;i++)
-    StreamWrite ( f,Edge[i] );
-}
-
-void  CGraph::read ( RCFile f )  {
-int     i,Version;
-Boolean bondOrder;
-
-  FreeMemory();
-
-  f.ReadInt    ( &Version   );
-  f.ReadBool   ( &bondOrder );
-  f.CreateRead ( name       );
-  f.ReadInt    ( &nVertices );
-  f.ReadInt    ( &nEdges    );
-  if (Version>1)  {
-    f.ReadInt  ( &nAllVertices );
-    f.ReadInt  ( &nAllEdges    );
-  } else  {
-    nAllVertices = nVertices;
-    nAllEdges    = nEdges;
-  }
-  if (nAllVertices>0)  {
-    nVAlloc = nAllVertices;
-    Vertex  = new PCVertex[nVAlloc];
-    for (i=0;i<nAllVertices;i++)  {
-      Vertex[i] = NULL;
-      StreamRead ( f,Vertex[i] );
-    }
-  }
-  if (nAllEdges>0)  {
-    nEAlloc = nAllEdges;
-    Edge    = new PCEdge[nEAlloc];
-    for (i=0;i<nAllEdges;i++)  {
-      Edge[i] = NULL;
-      StreamRead ( f,Edge[i] );
-    }
-  }
-
-//  Build ( bondOrder );
-
-}
-
-void  CGraph::mem_write ( pstr S, int & l )  {
-int     i,k;
-byte    Version=2;
-Boolean bondOrder=False;
-
-  ::mem_write_byte ( Version,S,l );
-  ::mem_write ( bondOrder   ,S,l );
-  ::mem_write ( name        ,S,l );
-  ::mem_write ( nVertices   ,S,l );
-  ::mem_write ( nEdges      ,S,l );
-  ::mem_write ( nAllVertices,S,l );
-  ::mem_write ( nAllEdges   ,S,l );
-  for (i=0;i<nAllVertices;i++)
-    if (Vertex[i])  {
-      k = 1;
-      ::mem_write ( k,S,l );
-      Vertex[i]->mem_write ( S,l );
-    } else  {
-      k = 0;
-      ::mem_write ( k,S,l );
-    }
-  for (i=0;i<nAllEdges;i++)
-    if (Edge[i])  {
-      k = 1;
-      ::mem_write ( k,S,l );
-      Edge[i]->mem_write ( S,l );
-    } else  {
-      k = 0;
-      ::mem_write ( k,S,l );
-    }
-
-}
-
-void  CGraph::mem_read ( cpstr S, int & l )  {
-int     i,k;
-byte    Version;
-Boolean bondOrder;
-
-  FreeMemory();
-
-  ::mem_read_byte ( Version,S,l );
-  ::mem_read ( bondOrder   ,S,l );
-  ::mem_read ( name        ,S,l );
-  ::mem_read ( nVertices   ,S,l );
-  ::mem_read ( nEdges      ,S,l );
-  ::mem_read ( nAllVertices,S,l );
-  ::mem_read ( nAllEdges   ,S,l );
-  if (nAllVertices>0)  {
-    nVAlloc = nAllVertices;
-    Vertex  = new PCVertex[nVAlloc];
-    for (i=0;i<nAllVertices;i++)  {
-      ::mem_read ( k,S,l );
-      if (k)  {
-        Vertex[i] = new CVertex();
-        Vertex[i]->mem_read ( S,l );
-      } else
-        Vertex[i] = NULL;
-    }
-  }
-  if (nAllEdges>0)  {
-    nEAlloc = nAllEdges;
-    Edge    = new PCEdge[nEAlloc];
-    for (i=0;i<nAllEdges;i++)  {
-      ::mem_read ( k,S,l );
-      if (k)  {
-        Edge[i] = new CEdge();
-        Edge[i]->mem_read ( S,l );
-      } else  {
-        Edge[i] = NULL;
-      }
-    }
-  }
-
-//  Build ( bondOrder );
-
-}
-
-MakeStreamFunctions(CGraph);
-
-
-//  ==========================  CMatch  ============================
-
-CMatch::CMatch() : CStream()  {
-  InitMatch();
-}
-
-CMatch::CMatch ( RPCStream Object ) : CStream ( Object )  {
-  InitMatch();
-}
-
-CMatch::CMatch ( ivector FV1, ivector FV2, int nv, int n, int m )  {
-int i;
-  if (FV1 && FV2)  {
-    n1     = n;
-    n2     = m;
-    nAlloc = n;
-    GetVectorMemory ( F1,nAlloc,1 );
-    GetVectorMemory ( F2,nAlloc,1 );
-    mlength = nv;
-    for (i=1;i<=mlength;i++)  {
-      F1[i] = FV1[i];
-      F2[i] = FV2[i];
-    }
-  } else
-    InitMatch();
-}
-
-void  CMatch::InitMatch()  {
-  mlength = 0;
-  n1      = 0;
-  n2      = 0;
-  nAlloc  = 0;
-  F1      = NULL;
-  F2      = NULL;
-}
-
-CMatch::~CMatch()  {
-  FreeVectorMemory ( F1,1 );
-  FreeVectorMemory ( F2,1 );
-}
-
-void CMatch::SetMatch ( ivector FV1, ivector FV2, int nv, int n, int m )  {
-int i;
-  if (FV1 && FV2)  {
-    if (nv>nAlloc)  {
-      FreeVectorMemory ( F1,1 );
-      FreeVectorMemory ( F2,1 );
-      nAlloc = n;
-      GetVectorMemory  ( F1,nAlloc,1 );
-      GetVectorMemory  ( F2,nAlloc,1 );
-    }
-    n1 = n;
-    n2 = m;
-    mlength = nv;
-    for (i=1;i<=mlength;i++)  {
-      F1[i] = FV1[i];
-      F2[i] = FV2[i];
-    }
-  } else  {
-    FreeVectorMemory ( F1,1 );
-    FreeVectorMemory ( F2,1 );
-    mlength = 0;
-    n1 = 0;
-    n2 = 0;
-  }
-}
-
-
-Boolean CMatch::isMatch ( ivector FV1, ivector FV2, int nv )  {
-int     i,j;
-Boolean B;
-  if (FV1 && FV2 && (nv<=mlength))  {
-    B = True;
-    for (i=1;(i<=nv) && B;i++)  {
-      B = False;
-      for (j=1;(j<=mlength) && (!B);j++)
-        B = (FV1[i]==F1[j]) && (FV2[i]==F2[j]);
-    }
-    return B;
-  }
-  return False;
-}
-
-Boolean CMatch::isCombination ( ivector FV1, ivector FV2, int nv )  {
-int     i,j;
-Boolean B;
-  if (FV1 && FV2 && (nv==mlength))  {
-    B = True;
-    for (i=1;(i<=nv) && B;i++)  {
-      B = False;
-      for (j=1;(j<=mlength) && (!B);j++)
-        B = (FV1[i]==F1[j]);
-      if (B)  {
-        B = False;
-        for (j=1;(j<=mlength) && (!B);j++)
-          B = (FV2[i]==F2[j]);
-      }
-    }
-    return B;
-  }
-  return False;
-}
-
-
-void CMatch::GetMatch ( ivector  & FV1, ivector  & FV2, int & nv,
-                        realtype & p1,  realtype & p2 )  {
-  FV1 = F1;
-  FV2 = F2;
-  nv  = mlength;
-  p1  = mlength;
-  if (p1>0.0)  p1 /= n1;
-  p2  = mlength;
-  if (p2>0.0)  p2 /= n2;
-}
-
-void CMatch::write ( RCFile f )  {
-int i;
-int Version=1;
-  f.WriteInt ( &Version );
-  f.WriteInt ( &mlength );
-  f.WriteInt ( &n1      );
-  f.WriteInt ( &n2      );
-  for (i=1;i<=mlength;i++)  {
-    f.WriteInt ( &(F1[i]) );
-    f.WriteInt ( &(F2[i]) );
-  }
-}
-
-void CMatch::read ( RCFile f )  {
-int i,Version;
-  FreeVectorMemory ( F1,1 );
-  FreeVectorMemory ( F2,1 );
-  f.ReadInt ( &Version );
-  f.ReadInt ( &mlength );
-  f.ReadInt ( &n1      );
-  f.ReadInt ( &n2      );
-  if (mlength>0)  {
-    nAlloc = n1;
-    GetVectorMemory ( F1,nAlloc,1 );
-    GetVectorMemory ( F2,nAlloc,1 );
-    for (i=1;i<=mlength;i++)  {
-      f.ReadInt ( &(F1[i]) );
-      f.ReadInt ( &(F2[i]) );
-    }
-  }
-}
-
-void CMatch::mem_write ( pstr S, int & l )  {
-int i;
-  ::mem_write ( mlength,S,l );
-  ::mem_write ( n1     ,S,l );
-  ::mem_write ( n2     ,S,l );
-  for (i=1;i<=mlength;i++)  {
-    ::mem_write ( F1[i],S,l );
-    ::mem_write ( F2[i],S,l );
-  }
-}
-
-void CMatch::mem_read ( cpstr S, int & l )  {
-int i;
-  FreeVectorMemory ( F1,1 );
-  FreeVectorMemory ( F2,1 );
-  ::mem_read ( mlength,S,l );
-  ::mem_read ( n1     ,S,l );
-  ::mem_read ( n2     ,S,l );
-  if (mlength>0)  {
-    nAlloc = n1;
-    GetVectorMemory ( F1,nAlloc,1 );
-    GetVectorMemory ( F2,nAlloc,1 );
-    for (i=1;i<=mlength;i++)  {
-      ::mem_read ( F1[i],S,l );
-      ::mem_read ( F2[i],S,l );
-    }
-  }
-}
-
-
-MakeStreamFunctions(CMatch);
-
-
-
-//  ========================  CGraphMatch  ==========================
-
-CGraphMatch::CGraphMatch()
-           : CStream()  {
-  InitGraphMatch();
-}
-
-CGraphMatch::CGraphMatch ( RPCStream Object )
-           : CStream ( Object )  {
-  InitGraphMatch();
-}
-
-CGraphMatch::~CGraphMatch()  {
-  FreeMemory();
-}
-
-void  CGraphMatch::InitGraphMatch()  {
-  G1           = NULL;
-  G2           = NULL;
-  n            = 0;
-  m            = 0;
-  P            = NULL;
-  nAlloc       = 0;
-  mAlloc       = 0;
-  nMatches     = 0;
-  maxNMatches  = -1;  // unlimited
-  Match        = NULL;
-  nMAlloc      = 0;
-  flags        = 0;
-  swap         = False;
-  wasFullMatch = False;
-  maxMatch     = 0;
-  timeLimit    = 0;  // no time limit
-  Stop         = False;
-  stopOnMaxNMathches = False;
-  F1           = NULL;
-  F2           = NULL;
-  iF1          = NULL;
-  ix           = NULL;
-#ifndef _UseRecursion
-  jj           = NULL;
-#endif
-}
-
-
-void  CGraphMatch::SetFlag ( word flag )  {
-  flags |= flag;
-}
-
-void  CGraphMatch::RemoveFlag ( word flag )  {
-  flags &= ~flag;
-}
-
-void  CGraphMatch::SetMaxNofMatches ( int maxNofMatches,
-                                      Boolean stopOnMaxN )  {
-  maxNMatches        = maxNofMatches;
-  stopOnMaxNMathches = stopOnMaxN;
-}
-
-void  CGraphMatch::SetTimeLimit ( int maxTimeToRun )  {
-  timeLimit = maxTimeToRun;
-}
-
-void  CGraphMatch::Reset()  {
-  FreeMemory();
-}
-
-void  CGraphMatch::FreeMemory()  {
-int i;
-
-  if (P) {
-    FreeMatrixMemory ( P[1],nAlloc,1,0 );
-    FreeRecHeap      ();
-    P = P + 1;
-    delete[] P;
-    P = NULL;
-  }
-
-  FreeMatrixMemory ( iF1,nAlloc,1,1 );
-
-  FreeVectorMemory ( F1 ,1 );
-  FreeVectorMemory ( F2 ,1 );
-  FreeVectorMemory ( ix ,1 );
-  nAlloc = 0;
-  mAlloc = 0;
-
-  if (Match)  {
-    for (i=0;i<nMAlloc;i++)
-      if (Match[i])  delete Match[i];
-    delete[] Match;
-  }
-  Match    = NULL;
-  nMatches = 0;
-  nMAlloc  = 0;
-
-#ifndef _UseRecursion
-  FreeVectorMemory ( jj,1 );
-#endif
-
-}
-
-void  CGraphMatch::FreeRecHeap()  {
-int i;
-  if (P)
-    for (i=2;i<=nAlloc;i++)
-      FreeMatrixMemory ( P[i],nAlloc,1,0 );
-}
-
-
-void  CGraphMatch::GetMemory()  {
-int i;
-
-  FreeMemory();
-
-  P = new imatrix[n];
-  P = P-1;
-  GetMatrixMemory ( P[1],n,m+1,1,0 );
-  for (i=2;i<=n;i++)
-    P[i] = NULL;
-
-  GetMatrixMemory ( iF1,n,n,1,1 );
-
-  GetVectorMemory ( F1,n,1 );
-  GetVectorMemory ( F2,n,1 );
-  GetVectorMemory ( ix,n,1 );
-
-#ifndef _UseRecursion
-  GetVectorMemory ( jj,n,1 );
-#endif
-
-  nAlloc = n;
-  mAlloc = m;
-
-}
-
-void  CGraphMatch::GetRecHeap()  {
-int i,j;
-  for (i=2;i<=n;i++)  {
-    P[i] = new ivector[nAlloc];
-    P[i] = P[i]-1;
-    for (j=1;j<=n;j++)
-      GetVectorMemory ( P[i][j],P[1][j][0]+1,0 );
-    for (j=n+1;j<=nAlloc;j++)
-      P[i][j] = NULL;
-  }
-}
-
-
-void  CGraphMatch::MatchGraphs ( PCGraph Gh1, PCGraph Gh2,
-                                 int     minMatch,
-                                 Boolean vertexType,
-                                 int     vertexExt )  {
-//  MatchGraphs looks for maximal common subgraphs of size
-//  not less than minMatch. The number of found subgraphs
-//  is returned by GetNofMatches(), the subgraph vertices
-//  are returned by GetMatch(..). Control parameters:
-//      vertexType   True if vertex type should be taken
-//                   into account and False otherwise
-//      vertexExt    key to use extended vertex types (defined
-//                   as type_ext in CVertex).
-int  n1;
-
-  if (Gh1->nVertices<=Gh2->nVertices)  {
-    G1   = Gh1;
-    G2   = Gh2;
-    swap = False;
-  } else  {
-    G1   = Gh2;
-    G2   = Gh1;
-    swap = True;
-  }
-  n  = G1->nVertices;
-  m  = G2->nVertices;
-  V1 = G1->Vertex;
-  V2 = G2->Vertex;
-  c1 = G1->graph;
-  c2 = G2->graph;
-
-  nMatches = 0;
-
-  if (n<=0)  return;
-
-  if ((n>nAlloc) || (m>mAlloc))  GetMemory();
-                           else  FreeRecHeap();
-
-  n1 = Initialize ( vertexType,vertexExt );
-  if (n1<=0)  return;
-
-  GetRecHeap();
-
-  maxMatch  = IMax(1,IMin(n,minMatch));
-  Stop      = False;
-  startTime = time(NULL);
-
-  //    Use of Backtrack(..) and Ullman() is completely
-  //  equivalent. One of them should be commented.
-
-  if (minMatch<n)  {
-
-    if (n1>=minMatch)  Backtrack1 ( 1,n1 );
-
-  } else if (n1>=n)  {
-
-   #ifdef _UseRecursion
-    Backtrack ( 1 );
-   #else
-    Ullman();
-   #endif
-
-  }
-
-}
-
-
-int  CGraphMatch::Initialize ( Boolean vertexType, int vertexExt )  {
-ivector jF1;
-int     i,j,v1type,v1type_ext,v2type_ext,almask,iW,pl;
-
-  wasFullMatch = False;
-
-  jF1 = iF1[1];
-  for (i=1;i<=n;i++)
-    jF1[i] = i;
-
-  almask = ~ATOM_LEAVING;
-
-/*  -- experiment for symmetry reliefs
-int v2type,v1type_sr,srmask;
-  srmask = ~SYMREL_MASK;
-
-  for (i=1;i<=n;i++)  {
-    if (vertexType) {
-      ix[i]  = 0;
-      v1type = V1[i-1]->type & almask;
-      v1type_sr = v1type & srmask;
-      pl     = 0;
-      for (j=1;j<=m;j++)  {
-        v2type = V2[j-1]->type & almask;
-        if ((v1type==v2type) ||
-            (v1type_sr==v2type) ||
-            (v1type==(v2type & srmask)))
-          P[1][i][++pl] = j;
-      }
-      P[1][i][0] = pl;
-      if (pl)  ix[i] = i;
-    } else {
-      ix[i] = i;
-      for (j=1;j<=m;j++)
-        P[1][i][j] = j;
-      P[1][i][0] = m;
-    }
-    F1[i] = 0;
-    F2[i] = 0;
-  }
- */
-
-  for (i=1;i<=n;i++)  {
-    ix[i]      = 0;
-    v1type     = V1[i-1]->type & almask;
-    v1type_ext = V1[i-1]->type_ext;
-    pl         = 0;
-    for (j=1;j<=m;j++)
-      if ((v1type==(V2[j-1]->type & almask)) || (!vertexType))  {
-        if (vertexExt==EXTTYPE_Ignore)
-          P[1][i][++pl] = j;
-        else  {
-          v2type_ext = V2[j-1]->type_ext;
-          if ((!v1type_ext) && (!v2type_ext))
-            P[1][i][++pl] = j;
-          else
-            switch (vertexExt)  {
-              default :
-              case EXTTYPE_Ignore   : P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_Equal    : if (v1type_ext==v2type_ext)
-                                        P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_AND      : if (v1type_ext & v2type_ext)
-                                        P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_OR       : if (v1type_ext | v2type_ext)
-                                        P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_XOR      : if (v1type_ext ^ v2type_ext)
-                                        P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_NotEqual : if (v1type_ext!=v2type_ext)
-                                        P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_NotAND   : if ((v1type_ext & v2type_ext)
-                                              ==0)
-                                        P[1][i][++pl] = j;
-                                  break;
-              case EXTTYPE_NotOR    : if ((v1type_ext | v2type_ext)
-                                              ==0)
-                                        P[1][i][++pl] = j;
-            }
-        }
-      }
-    P[1][i][0] = pl;
-    if (pl)  ix[i] = i;
-    F1[i] = 0;
-    F2[i] = 0;
-  }
-  /*
-  } else  {
-    for (i=1;i<=n;i++)  {
-      ix[i] = i;
-      for (j=1;j<=m;j++)
-        P[1][i][j] = j;
-      P[1][i][0] = m;
-      F1[i] = 0;
-      F2[i] = 0;
-    }
-  }
-  */
-
-  i = 1;
-  j = n;
-  while (i<j)
-    if (ix[j]==0)  // make sure that j points on a true-containing
-      j--;         // row of P[1]
-    else  {
-      if (ix[i]==0)  {        // swap lower empty row of P[1]
-        iW     = ix[i];       // with the lth one, which
-        ix[i]  = ix[j];       // is surely not empty
-        ix[j]  = iW;
-        iW     = jF1[i];
-        jF1[i] = jF1[j];
-        jF1[j] = iW;
-      }
-      i++;
-    }
-
-  if (ix[i]==0)  return i-1;
-           else  return i;
-
-}
-
-
-#ifdef _UseRecursion
-
-void  CGraphMatch::Backtrack ( int i )  {
-//   Recursive version of Ullman's algorithm for exact
-// (structure-to-structure or substructure-to-structure)
-// matching
-int     i1,pli,cntj,j,k,pl1,pl2,cntl,l,c1ik;
-ivector c1i,c2j;
-ivector p1,p2;
-
-  if (Stop)  return;
-  if (timeLimit>0)
-    Stop = (difftime(time(NULL),startTime)>timeLimit);
-
-  F1[i] = i;
-  pli   = P[i][i][0];
-
-  if (i>=n)  {
-
-    for (cntj=1;(cntj<=pli) && (!Stop);cntj++)  {
-      F2[n] = P[n][n][cntj];
-      CollectMatch ( n );
-    }
-
-  } else  {
-
-    i1  = i+1;
-    c1i = c1[i];
-
-    for (cntj=1;(cntj<=pli) && (!Stop);cntj++)  {
-      j     = P[i][i][cntj];
-      F2[i] = j;  // mapped F1[i]:F2[i], i.e. i:j
-      // Forward checking
-      c2j   = c2[j];
-      pl2   = 1;
-      for (k=i1;(k<=n) && (pl2>0);k++)  {
-        p1   = P[i][k];
-        p2   = P[i1][k];
-        c1ik = c1i[k];
-        pl1  = p1[0];
-        pl2  = 0;
-        for (cntl=1;cntl<=pl1;cntl++)  {
-          l = p1[cntl];
-          if ((c1ik==c2j[l]) && // check that bonds are compatible
-              (l!=j))           // and make sure jth vertex is excluded
-            p2[++pl2] = l;
-        }
-        p2[0] = pl2;  //  new length of P-row
-      }
-      if (pl2>0)  Backtrack ( i1 );
-    }
-
-  }
-
-}
-
-#else
-
-void  CGraphMatch::Ullman()  {
-//   A non-recursive translation of Ullman's Backtrack.
-// It might give some gain in performance, although tests
-// on SGI machine show that the gain is negligible, (if
-// there is any at all) if compiler's optimization is
-// switched on.
-int     i,pl,i1,pli,cntj,j,pl1,pl2,k,cntl,l,l1,cik;
-ivector ci,cj;
-ivector p1,p2;
-
-  if (Stop)  return;
-  if (timeLimit>0)
-    Stop = (difftime(time(NULL),startTime)>timeLimit);
-
-  i     = 1;
-  jj[1] = 1;
-  pl    = P[1][1][0];
-
-  do  {
-
-    F1[i] = i;
-    pli   = P[i][i][0];
-
-    if (i>=n)  {
-
-      for (cntj=jj[n];(cntj<=pli) && (!Stop);cntj++)  {
-        jj[n]++;
-        F2[n] = P[n][n][cntj];
-        CollectMatch ( n );
-      }
-
-    } else  {
-
-      i1  = i+1;
-      ci  = c1[i];
-      for (cntj=jj[i];(cntj<=pli) && (!Stop);cntj++)  {
-        jj[i]++;
-        j     = P[i][i][cntj];
-        F2[i] = j;
-        // Forward checking
-        cj    = c2[j];
-        pl2   = 1;
-        for (k=i1;(k<=n) && (pl2>0);k++)  {
-          p1  = P[i][k];
-          p2  = P[i1][k];
-          cik = ci[k];
-          pl1 = p1[0];
-          pl2 = 0;
-          for (cntl=1;cntl<=pl1;cntl++)  {
-            l = p1[cntl];
-            if ((cik==cj[l]) && // check that bonds are compatible
-                (l!=j))         // and make sure jth vertex is excluded
-              p2[++pl2] = l;
-          }
-          p2[0] = pl2;  //  new length of P-row
-        }
-        if (pl2>0)  {
-          i++;
-          jj[i] = 1;
-          i++;        // in order to compensate the following decrement
-          break;
-        }
-      }
-
-    }
-    i--;
-
-  } while ((!Stop) && ((jj[1]<=pl) || (i>1)));
-
-}
-
-#endif
-
-void  CGraphMatch::Backtrack1 ( int i, int k0 )  {
-//   Recursive version of CSIA algorithm for partial
-// (substructure-to-substructure) matching
-int     i1,pl0,cntj,j,k,pl1,pl2,cntl,l,c1ik,ii,iW,k1;
-ivector jF1,c1i,c2j;
-ivector p0,p1,p2;
-
-  if (Stop)  return;
-  if (timeLimit>0)
-    Stop = (difftime(time(NULL),startTime)>timeLimit);
-
-  jF1 = iF1[i];
-
-  if (i>=k0)  {
-
-    F1[i] = jF1[i];
-    p0    = P[i][jF1[i]];
-    pl0   = p0[0];
-
-    // collect matches of k0-th (the upmost) level
-    if (pl0>0)  {
-      maxMatch = k0;
-      for (cntj=1;cntj<=pl0;cntj++)  {
-        F2[k0] = p0[cntj];
-        CollectMatch ( k0 );
-      }
-    }
-
-  } else  {
-
-    i1  = i+1;
-
-    pl0 = P[i][jF1[i]][0];
-    j   = i;
-    for (k=i1;k<=k0;k++)
-      if (P[i][jF1[k]][0]<pl0)  {
-        pl0 = P[i][jF1[k]][0];
-        j   = k;
-      }
-    if (j>i)  {
-      iW     = jF1[i];
-      jF1[i] = jF1[j];
-      jF1[j] = iW;
-    }
-
-    F1[i] = jF1[i];
-    p0    = P[i][jF1[i]];
-    pl0   = p0[0];
-
-    c1i   = c1[jF1[i]];
-
-    //  1. Find all matches that include jF1[i]th vertex of graph G1
-
-    for (cntj=1;(cntj<=pl0) && (!Stop);cntj++)  {
-      j = p0[cntj];
-      F2[i] = j;   // mapped F1[i]:F2[i], i.e. iF1[i][i]:j
-      // Forward checking
-      c2j = c2[j];
-      k1  = k0;   // k1 is the limit for match size
-      for (k=i1;(k<=k0) && (k1>=maxMatch);k++)  {
-        ix[k] = 0;
-        p1    = P[i] [jF1[k]];
-        p2    = P[i1][jF1[k]];
-        c1ik  = c1i  [jF1[k]];
-        pl1   = p1[0];
-        pl2   = 0;
-        for (cntl=1;cntl<=pl1;cntl++)  {
-          l = p1[cntl];
-          if ((c1ik==c2j[l]) && // check that bonds are compatible
-              (l!=j))           // and make sure jth vertex is excluded
-            p2[++pl2] = l;
-        }
-        p2[0] = pl2;  //  new length of P-row
-        if (pl2>0)  {
-          ix[k] = k;
-        } else if (wasFullMatch)  {
-          k1 = maxMatch-1;  // we are not interested in partial
-        } else  {           //   match anymore
-          k1--;
-        }
-      }
-      if (k1>=maxMatch)  {
-        // shift unmatching vertices to the end
-        for (ii=1;ii<=n;ii++)
-          iF1[i1][ii] = jF1[ii];
-        k = i1;
-        l = k0;
-        while (k<l)
-          if (ix[l]==0) // make sure that l points on a true-containing
-            l--;        // row of P[i1]
-          else  {
-            if (ix[k]==0)  {         // swap lower empty row of P[i1]
-              iW         = ix[k];    // with the lth one, which
-              ix[k]      = ix[l];    // is surely not empty
-              ix[l]      = iW;
-              iW         = iF1[i1][k];
-              iF1[i1][k] = iF1[i1][l];
-              iF1[i1][l] = iW;
-            }
-            k++;
-          }
-        if (ix[i1])  Backtrack1 ( i1,k1 );
-        else if (i>=maxMatch)  {
-          CollectMatch ( i );  // collect match of ith level
-          maxMatch = i;
-        }
-      }
-    }
-
-    //  2. Find all matches that do not include jF1[i]th vertex
-    //     of graph G1
-
-    if (k0>maxMatch)  {
-      //   Shift jF1[i]th vertex to the end
-      iW      = jF1[i];
-      jF1[i]  = jF1[k0];
-      jF1[k0] = iW;
-      Backtrack1 ( i,k0-1 );
-    }
-
-  }
-
-}
-
-
-void  CGraphMatch::CollectMatch ( int nm )  {
-int      i;
-Boolean  B;
-PPCMatch M1;
-
-  if (maxNMatches==0)  return;
-
-  // find out if this should be a new match
-  if (nMatches>0)  {
-    // a match is already found; check with it
-    if (nm<Match[0]->mlength)  return;
-    if (nm>Match[0]->mlength)  {
-      nMatches = 0;
-    } else if (flags & GMF_UniqueMatch)  {
-      // check if such a match was already found
-      B = False;
-      for (i=0;(i<nMatches) && (!B);i++)
-        B = Match[i]->isMatch(F1,F2,nm);
-      if (B)  return;  // repeating match -- just quit.
-    } else if (flags & GMF_NoCombinations)  {
-      // check if such a match was already found
-      B = False;
-      for (i=0;(i<nMatches) && (!B);i++)
-        B = Match[i]->isCombination(F1,F2,nm);
-      if (B)  return;  // repeating match -- just quit.
-    }
-  }
-
-  if (nMatches>=nMAlloc)  {
-    if ((nMAlloc<maxNMatches) || (maxNMatches<=0))  {
-      if (maxNMatches>0)  nMAlloc  = IMin(maxNMatches,nMAlloc+100);
-                    else  nMAlloc += 100;
-      M1 = new PCMatch[nMAlloc];
-      for (i=0;i<nMatches;i++)
-        M1[i] = Match[i];
-      for (i=nMatches;i<nMAlloc;i++)
-        M1[i] = NULL;
-      if (Match)  delete[] Match;
-      Match = M1;
-    } else
-      nMatches--;
-  }
-
-  if (!Match[nMatches])
-        Match[nMatches] = new CMatch ( F1,F2,nm,n,m );
-  else  Match[nMatches]->SetMatch ( F1,F2,nm,n,m );
-
-  if (nm==n)  wasFullMatch = True;
-
-  if (nm>maxMatch)  maxMatch = nm;
-
-  nMatches++;
-
-  if (stopOnMaxNMathches && (maxNMatches>0) &&
-      (nMatches>=maxNMatches))
-    Stop = True;
-
-}
-
-void  CGraphMatch::PrintMatches()  {
-int i,j,k;
-  if (nMatches<=0)
-    printf ( "\n\n *** NO MATCHES FOUND\n\n" );
-  else  {
-    if (flags & GMF_UniqueMatch)
-          printf ( "\n\n *** FOUND Unique Matches\n\n" );
-    else  printf ( "\n\n *** FOUND Matches\n\n" );
-    printf ( "    ##     Vertices\n" );
-    for (i=0;i<nMatches;i++)  {
-      printf ( " %5i  ",i+1 );
-      k = 8;
-      for (j=1;j<=Match[i]->mlength;j++)  {
-        if (swap)
-             printf ( " (%i,%i)",Match[i]->F2[j],Match[i]->F1[j] );
-        else printf ( " (%i,%i)",Match[i]->F1[j],Match[i]->F2[j] );
-        k += 8;
-        if (k>70)  {
-          printf ( "\n" );
-          k = 8;
-        }
-      }
-      printf ( "\n" );
-    }
-  }
-  printf ( "\n **************************\n" );
-}
-
-void  CGraphMatch::GetMatch ( int MatchNo, ivector  & FV1,
-                              ivector  & FV2, int & nv,
-                              realtype & p1, realtype & p2 ) {
-// do not allocate or dispose FV1 and FV2 in application!
-// FV1/p1 will always correspond to Gh1, and FV2/p2 -
-// to Gh2 as specified in MatchGraphs(..)
-  if ((MatchNo<0) || (MatchNo>=nMatches))  {
-    FV1 = NULL;
-    FV2 = NULL;
-    nv  = 0;
-    p1  = 0.0;
-    p2  = 0.0;
-  } else if (swap)
-       Match[MatchNo]->GetMatch ( FV2,FV1,nv,p2,p1 );
-  else Match[MatchNo]->GetMatch ( FV1,FV2,nv,p1,p2 );
-
-}
-
-
-void  CGraphMatch::write ( RCFile f )  {
-int i;
-int Version=1;
-  f.WriteInt  ( &Version  );
-  f.WriteInt  ( &nMatches );
-  f.WriteWord ( &flags    );
-  f.WriteBool ( &swap     );
-  for (i=0;i<nMatches;i++)
-    Match[i]->write ( f );
-}
-
-void  CGraphMatch::read ( RCFile f )  {
-int i,Version;
-  FreeMemory ();
-  f.ReadInt  ( &Version  );
-  f.ReadInt  ( &nMatches );
-  f.ReadWord ( &flags    );
-  f.ReadBool ( &swap     );
-  if (nMatches>0)  {
-    nMAlloc = nMatches;
-    Match   = new PCMatch[nMatches];
-    for (i=0;i<nMatches;i++)  {
-      Match[i] = new CMatch();
-      Match[i]->read ( f );
-    }
-  }
-}
-
-
-void  CGraphMatch::mem_write ( pstr S, int & l )  {
-int i;
-  ::mem_write ( nMatches,S,l );
-  ::mem_write ( flags   ,S,l );
-  ::mem_write ( swap    ,S,l );
-  for (i=0;i<nMatches;i++)
-    Match[i]->mem_write ( S,l );
-}
-
-void  CGraphMatch::mem_read ( cpstr S, int & l )  {
-int i;
-  FreeMemory ();
-  ::mem_read ( nMatches,S,l );
-  ::mem_read ( flags   ,S,l );
-  ::mem_read ( swap    ,S,l );
-  if (nMatches>0)  {
-    nMAlloc = nMatches;
-    Match   = new PCMatch[nMatches];
-    for (i=0;i<nMatches;i++)  {
-      Match[i] = new CMatch();
-      Match[i]->mem_read ( S,l );
-    }
-  }
-}
-
-MakeStreamFunctions(CGraphMatch);
-
-
-
-// =============================================================
-
-/*
-static char Mol1[][3] = {
-  "C", "C", "C", "C", "C", "C" };
-
-static int  Bond1[] = {
-  1, 2,
-  1, 6,
-  2, 3,
-  3, 4,
-  4, 5,
-  5, 6
-};
-
-static char Mol2[][3] = {
-  "C", "C", "C", "C", "C", "C",
-  "C", "C", "C", "C", "C", "C" };
-
-static int  Bond2[] = {
-  1, 2,
-  1, 6,
-  2, 3,
-  3, 4,
-  4, 5,
-  5, 6,
-  1, 7,
-  2, 8,
-  3, 9,
-  4, 10,
-  5, 11,
-  6, 12
-};
-
-
-static char Mol1[][3] = {
-  "C", "C", "N", "C" };
-
-static int  Bond1[] = {
-  1, 2,
-  2, 3,
-  3, 4
-};
-
-static char Mol2[][3] = {
-  "C", "C", "N", "C" };
-
-static int  Bond2[] = {
-  1, 2,
-  2, 3,
-  2, 4,
-  3, 4
-};
-
-void  TestGraphMatch()  {
-int         i,k1,k2, nv1,nb1, nv2,nb2;
-PCVertex    V;
-PCEdge      G;
-CGraph      G1,G2;
-CGraphMatch U;
-
-  G1.Reset   ();
-  G1.SetName ( "#1" );
-
-  nv1 = sizeof(Mol1)/3;
-  for (i=0;i<nv1;i++)  {
-    V = new CVertex();
-    V->SetVertex ( Mol1[i] );
-    G1.AddVertex ( V );
-  }
-  nb1 = sizeof(Bond1)/(2*sizeof(int));
-  k1  = 0;
-  k2  = 1;
-  for (i=0;i<nb1;i++)  {
-    G = new CEdge();
-    G->SetEdge ( Bond1[k1],Bond1[k2],1 );
-    G1.AddEdge ( G );
-    k1 += 2;
-    k2 += 2;
-  }
-
-  G2.Reset   ();
-  G2.SetName ( "#2" );
-
-  nv2 = sizeof(Mol2)/3;
-  for (i=0;i<nv2;i++)  {
-    V = new CVertex();
-    V->SetVertex ( Mol2[i] );
-    G2.AddVertex ( V );
-  }
-  nb2 = sizeof(Bond2)/(2*sizeof(int));
-  k1  = 0;
-  k2  = 1;
-  for (i=0;i<nb2;i++)  {
-    G = new CEdge();
-    G->SetEdge ( Bond2[k1],Bond2[k2],1 );
-    G2.AddEdge ( G );
-    k1 += 2;
-    k2 += 2;
-  }
-
-  G1.Build();
-  G2.Build();
-
-  U.MatchGraphs ( &G1,&G2,nv1 );
-
-  U.PrintMatches();
-
-
-}
-*/
-
diff --git a/mmdb/mmdb_graph.h b/mmdb/mmdb_graph.h
deleted file mode 100755
index 70aa523..0000000
--- a/mmdb/mmdb_graph.h
+++ /dev/null
@@ -1,484 +0,0 @@
-//  $Id: mmdb_graph.h,v 1.23 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_graph  <interface>
-//       ~~~~~~~~~
-//  **** Classes :  CVertex     ( graph vertex                        )
-//       ~~~~~~~~~  CEdge       ( graph edge                          )
-//                  CGraph      ( structural graph                    )
-//                  CMatch      ( match of structural graphs          )
-//                  CGraphMatch ( CSIA algorithms for graphs matching )
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  When used, please cite:
-//
-//   Krissinel, E. and Henrick, K. (2004)
-//   Common subgraph isomorphism detection by backtracking search.
-//   Software - Practice and Experience, 34, 591-607.
-//
-//  =================================================================
-//
-
-#ifndef  __MMDB_Graph__
-#define  __MMDB_Graph__
-
-
-#ifndef  __TIME_H
-#include <time.h>
-#endif
-
-#ifndef  __MMDB_Atom__
-#include "mmdb_atom.h"
-#endif
-
-//  ==========================  CVertex  ============================
-
-DefineClass(CVertex);
-
-#define  CHIRAL_RIGHT      0x10000000
-#define  CHIRAL_LEFT       0x20000000
-#define  ATOM_LEAVING      0x40000000
-#define  HYDROGEN_BOND     0x0F000000
-#define  SYMREL_MASK       0x00FF0000
-#define  CHIRAL_MASK       0xCFFFFFFF
-#define  TYPE_MASK         0x00FFFFFF
-
-class CVertex : public CStream  {
-
-  friend class CGraph;
-  friend class CGraphMatch;
-  friend class CSBase0;
-
-  public:
-
-    CVertex ();
-    CVertex ( RPCStream Object );
-    CVertex ( int  vtype, cpstr vname );
-    CVertex ( int  vtype );
-    CVertex ( cpstr chem_elem );
-    CVertex ( cpstr chem_elem, cpstr name );
-    ~CVertex();
-
-    void  SetVertex  ( cpstr chem_elem );
-    void  SetVertex  ( int vtype, cpstr vname );
-    void  SetVertex  ( int vtype   );
-    void  SetType    ( int vtype   );
-    void  SetTypeExt ( int typeExt );
-
-    void  RemoveChirality();
-    void  LeaveChirality ( int eltype );
-
-    void  SetName     ( cpstr vname );
-    void  SetProperty ( int vprop  );
-    void  SetID       ( int vid    );
-    void  SetUserID   ( int vid    ) { user_id = vid; }
-    void  AddBond     ();
-    void  CopyNBonds  ( PCVertex V );
-    int   GetProperty () { return property; }
-    int   GetID       () { return id;       }
-    int   GetUserID   () { return user_id;  }
-    cpstr GetName     () { return name;     }
-    int   GetType     () { return type;     }
-    int   GetTypeExt  () { return type_ext; }
-    int   GetNBonds   ();
-
-    void  SaveType    ();  // in userid
-    void  RestoreType ();  // from userid
-    void  CopyType    ( PCVertex V );
-
-    virtual void Print ( int PKey );
-
-    virtual void Copy ( PCVertex V );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-    void  mem_read  ( cpstr S, int & l );
-    void  mem_write ( pstr S, int & l );
-
-  protected:
-    pstr name;     // name may be general, "C", "Hg", "Cl" etc.
-    int  type;     // type of vertex, see comments in mmdb_graph.cpp
-    int  type_ext; // vertex type extention
-    int  property; // flagwise properties -- user-defined
-    int  id;       // a graph-defined vertex id
-    int  user_id;  // a user-defined vertex id
-
-    void InitVertex();
-
-};
-
-DefineStreamFunctions(CVertex);
-
-
-
-//  ===========================  CEdge  =============================
-
-#define BOND_SINGLE    1
-#define BOND_DOUBLE    2
-#define BOND_AROMATIC  3
-#define BOND_TRIPLE    4
-
-DefineClass(CEdge);
-
-class CEdge : public CStream  {
-
-  friend class CGraph;
-  friend class CGMatch;
-  friend class CSBase0;
-
-  public:
-
-    CEdge ();
-    CEdge ( RPCStream Object );
-    CEdge ( int vx1, int vx2, int btype );  // vx1,vx2 are numbered
-                                            // as 1,2,3 on and refer
-                                            // to vertices in the order
-                                            // as they were added to
-                                            // the graph; btype>0
-    ~CEdge();
-
-    void  SetEdge ( int vx1, int vx2, cpstr btype );
-    void  SetEdge ( int vx1, int vx2, int  btype ); // btype>0
-
-    void  SetType     ( int btype );
-    void  SetProperty ( int eprop );
-    void  SaveType    ();  // in property
-    void  RestoreType ();  // from property
-
-    inline int GetVertex1  () { return v1;       }
-    inline int GetVertex2  () { return v2;       }
-    inline int GetType     () { return type;     }
-    inline int GetProperty () { return property; }
-
-    virtual void Print ( int PKey );
-
-    virtual void Copy  ( PCEdge G );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-    void  mem_read  ( cpstr S, int & l );
-    void  mem_write ( pstr S, int & l );
-
-  protected:
-    int  v1,v2;  //  >=1
-    int  type;
-    int  property;
-
-    void  InitEdge();
-
-};
-
-DefineStreamFunctions(CEdge);
-
-
-
-//  ==========================  CGraph  ============================
-
-#define MKGRAPH_Ok             0
-#define MKGRAPH_NoAtoms        -1
-#define MKGRAPH_ChangedAltLoc  1
-#define MKGRAPH_MaxOccupancy   2
-
-DefineClass(CGraph);
-
-class CGraph : public CStream  {
-
-  friend class CGraphMatch;
-  friend class CSBase0;
-
-  public :
-
-    CGraph ();
-    CGraph ( PCResidue R, cpstr altLoc=NULL );
-    CGraph ( RPCStream Object );
-    ~CGraph();
-
-    void  Reset   ();
-    void  SetName ( cpstr gname );
-    pstr  GetName () { return name; }
-
-    //   AddVertex(..) and AddEdge(..) do not copy the objects, but
-    // take them over. This means that application should forget
-    // about pointers to V and G once they were given to CGraph.
-    // Vertices and edges  must be allocated newly prior each call
-    // to AddVertex(..) and AddEdge(..).
-    void  AddVertex   ( PCVertex  V );
-    void  AddEdge     ( PCEdge    G );
-    void  SetVertices ( PPCVertex V, int vlen );
-    void  SetEdges    ( PPCEdge   G, int glen );
-
-    void  RemoveChirality();
-    void  LeaveChirality ( int eltype );
-
-    //   MakeGraph(..) makes a graph corresponding to residue R.
-    // The graphs vertices then correspond to the residue's atoms
-    // (CVertex::userid points to atom R->atom[CVertex::userid]),
-    // edges are calculated as chemical bonds between atoms basing
-    // on the table of cut-off distances.
-    //   altCode specifies a particular conformation that should be
-    // used for making the graph. If it is set to "" or NULL ("empty"
-    // altcode) but the residue does not have conformation which
-    // contains *only* ""-altcode atoms, a conformation corresponding
-    // to maximal occupancy will be used. The same will happen if
-    // altcode information in residue is not correct, whatever altCode
-    // is specified.
-    //   After making the graph, Build(..) should be called as usual
-    // before graph matching.
-    //   Non-negative return means that graph has been made.
-    // MakeGraph(..) may return:
-    //   MKGRAPH_Ok             everything is Ok
-    //   MKGRAPH_NoAtoms        residue does not have atoms, graph
-    //                          is not made
-    //   MKGRAPH_ChangedAltLoc  a different altcode was used because
-    //                          the residue has only one altcode and
-    //                          that is different of
-    //   MKGRAPH_MaxOccupancy   a maximal-occupancy conformation has
-    //                          been chosen because of default
-    //                          ""-altcode supplied or incorrect
-    //                          altcode information in the residue
-    int   MakeGraph   ( PCResidue R, cpstr altLoc=NULL );
-
-    int   MakeGraph   ( PPCAtom atom, int nAtoms );
-
-    void  HideType    ( int bond_vx_type );
-    void  ExcludeType ( int type );
-
-    void  MakeSymmetryRelief ( Boolean noCO2 );
-    void  IdentifyRings      ();
-    int   IdentifyConnectedComponents();  // returns their number >= 1
-
-    int   Build       ( Boolean bondOrder );  // returns 0 if Ok
-
-    void  MakeVertexIDs      ();  // simply numbers vertices as 1.. on
-    int   GetVertexID        ( int vertexNo );
-    int   GetVertexNo        ( cpstr vname  );
-    // GetBondedVertexID(..) works after MoveType(..)
-    int   GetNBondedVertices ( int vertexNo );
-    int   GetBondedVertexID  ( int vertexNo, int bond_vx_type,
-                               int bondNo );
-
-    PCVertex   GetVertex ( int vertexNo );  // 1<=vertexNo<=nVertices
-    inline int GetNofVertices() { return nVertices; }
-
-    PCEdge    GetEdge    ( int edgeNo );    // 1<=edgeNo<=nEdges
-    inline int GetNofEdges() { return nEdges;    }
-
-    void  GetVertices ( PPCVertex & V, int & nV );
-    void  GetEdges    ( PPCEdge   & E, int & nE );
-
-    virtual void Print();
-    void  Print1();
-
-    virtual void Copy ( PCGraph G );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-    void  mem_read  ( cpstr S, int & l );
-    void  mem_write ( pstr S, int & l );
-
-  protected :
-    pstr      name;
-    int       nVertices,nEdges, nAllVertices,nAllEdges;
-    PPCVertex Vertex;
-    PPCEdge   Edge;
-    imatrix   graph;
-
-    void  InitGraph ();
-    void  FreeMemory();
-
-    void  markConnected ( int vno, int cno );
-
-  private :
-    int  nVAlloc,nEAlloc,nGAlloc;
-
-};
-
-DefineStreamFunctions(CGraph);
-
-
-//  ==========================  CMatch  ============================
-
-DefineClass(CMatch);
-DefineStreamFunctions(CMatch);
-
-class CMatch : public CStream  {
-
-  friend class CGraphMatch;
-
-  public :
-
-    CMatch ();
-    CMatch ( RPCStream Object );
-    CMatch ( ivector FV1, ivector FV2, int nv, int n, int m );
-    ~CMatch();
-
-    // FV1[] and FV2[] are copied into internal buffers
-    void SetMatch ( ivector FV1, ivector FV2, int nv, int n, int m );
-
-    Boolean isMatch       ( ivector FV1, ivector FV2, int nv );
-    Boolean isCombination ( ivector FV1, ivector FV2, int nv );
-
-    // do not allocate or dispose FV1 and FV2 in application!
-    void GetMatch ( ivector & FV1, ivector & FV2, int & nv,
-                    realtype & p1, realtype & p2 );
-
-    void read  ( RCFile f );
-    void write ( RCFile f );
-
-    void mem_read  ( cpstr S, int & l );
-    void mem_write ( pstr S, int & l );
-
-  protected :
-    int     n1,n2,mlength;
-    ivector F1,F2;
-
-    void InitMatch();
-
-  private :
-    int nAlloc;
-
-};
-
-
-//  =======================  CGraphMatch  =========================
-
-#define  _UseRecursion
-
-#define  GMF_UniqueMatch     0x00000001
-#define  GMF_NoCombinations  0x00000002
-
-#define  EXTTYPE_Ignore      0
-#define  EXTTYPE_Equal       1
-#define  EXTTYPE_AND         2
-#define  EXTTYPE_OR          3
-#define  EXTTYPE_XOR         4
-#define  EXTTYPE_NotEqual    5
-#define  EXTTYPE_NotAND      6
-#define  EXTTYPE_NotOR       7
-
-
-DefineClass(CGraphMatch);
-
-class CGraphMatch : public CStream  {
-
-  public :
-
-    CGraphMatch ();
-    CGraphMatch ( RPCStream Object );
-    ~CGraphMatch();
-
-    void SetFlag          ( word flag );
-    void RemoveFlag       ( word flag );
-    void SetMaxNofMatches ( int maxNofMatches, Boolean stopOnMaxN );
-    void SetTimeLimit     ( int maxTimeToRun=0 );
-    Boolean GetStopSignal () { return Stop; }
-
-    void Reset();
-
-    //  MatchGraphs looks for maximal common subgraphs of size
-    //  not less than minMatch. The number of found subgraphs
-    //  is returned by GetNofMatches(), the subgraph vertices
-    //  are returned by GetMatch(..). Control parameters:
-    //      vertexType   True if vertex type should be taken
-    //                   into account and False otherwise
-    //      vertexExt    key to use extended vertex types (defined
-    //                   as type_ext in CVertex).
-    void MatchGraphs    ( PCGraph Gh1, PCGraph Gh2, int minMatch,
-                          Boolean vertexType=True,
-                          int     vertexExt=EXTTYPE_Ignore );
-    void PrintMatches   ();
-    int  GetNofMatches  () { return nMatches; }
-    int  GetMaxMatchSize() { return maxMatch; }
-
-    // do not allocate or dispose FV1 and FV2 in application!
-    // FV1/p1 will always correspond to Gh1, and FV2/p2 -
-    // to Gh2 as specified in MatchGraphs(..)
-    void GetMatch ( int MatchNo, ivector & FV1, ivector & FV2,
-                    int & nv, realtype & p1, realtype & p2 );
-
-    void read  ( RCFile f );
-    void write ( RCFile f );
-
-    void mem_read  ( cpstr S, int & l );
-    void mem_write ( pstr  S, int & l );
-
-  protected :
-    PCGraph   G1,G2;
-    PPCVertex V1;
-    PPCVertex V2;
-    imatrix   c1,c2;
-    Boolean   swap;
-#ifndef _UseRecursion
-    ivector   jj;
-#endif
-    int       n,m;
-
-    imatrix3  P;
-    imatrix   iF1;
-    ivector   F1,F2,ix;
-
-    int       nMatches,maxNMatches;
-    PPCMatch  Match;
-    Boolean   wasFullMatch,Stop,stopOnMaxNMathches;
-    word      flags;
-    int       maxMatch,timeLimit;
-
-    void    InitGraphMatch();
-    void    FreeMemory    ();
-    void    FreeRecHeap   ();
-    void    GetMemory     ();
-    void    GetRecHeap    ();
-    int     Initialize    ( Boolean vertexType, int vertexExt );
-#ifdef _UseRecursion
-    void    Backtrack     ( int i );          // exact matching
-#else
-    void    Ullman        ();
-#endif
-    void    Backtrack1    ( int i, int k0 );  // exact/partial matching
-    void    CollectMatch  ( int nm );
-
-  private :
-    int     nAlloc,mAlloc,nMAlloc;
-    time_t  startTime;
-
-};
-
-DefineStreamFunctions(CGraphMatch);
-
-extern void  SetGraphAllocPortion ( int alloc_portion );
-
-/*
-extern void  TestGraphMatch();
-*/
-
-
-#endif
diff --git a/mmdb/mmdb_manager.cpp b/mmdb/mmdb_manager.cpp
deleted file mode 100755
index 77e46f1..0000000
--- a/mmdb/mmdb_manager.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-//  $Id: mmdb_manager.cpp,v 1.25 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    23.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_manager  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBManager  ( MMDB file manager class )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MMDB_Manager__
-#include "mmdb_manager.h"
-#endif
-
-
-//  =====================   CMMDBManager   =======================
-
-CMMDBManager::CMMDBManager() : CMMDBBondManager()  {
-}
-
-CMMDBManager::CMMDBManager ( RPCStream Object )
-            : CMMDBBondManager(Object)  {
-}
-
-CMMDBManager::~CMMDBManager()  {}
-
-void  CMMDBManager::Copy ( PCMMDBManager MMDB, word CopyMask )  {
-PCModel  model;
-PPCChain chain;
-PCChain  ch;
-ChainID  chID;
-int      i,j, nchains;
-
-  if (CopyMask & MMDBFCM_Flags)  Flags = MMDB->Flags;
-
-  if (CopyMask & MMDBFCM_Title)  Title.Copy ( &(MMDB->Title) );
-  if (CopyMask & MMDBFCM_Cryst)  Cryst.Copy ( &(MMDB->Cryst) );
-
-  if (CopyMask & MMDBFCM_Coord)  {
-
-    FreeCoordMemory    ();
-    DeleteAllSelections();
-
-    nAtoms = MMDB->nAtoms;
-    AtmLen = nAtoms;
-    if (nAtoms>0)  {
-      Atom = new PCAtom[AtmLen];
-      for (i=0;i<nAtoms;i++)  {
-        if (MMDB->Atom[i])  {
-          Atom[i] = newCAtom();
-          Atom[i]->Copy ( MMDB->Atom[i] );
-          // the internal atom references are installed
-          // by residue classes when they are read in
-          // model->chain below
-          Atom[i]->SetAtomIndex ( i+1 );
-        } else
-          Atom[i] = NULL;
-      }
-    }
-
-    nModels = MMDB->nModels;
-    if (nModels>0)  {
-      Model = new PCModel[nModels];
-      for (i=0;i<nModels;i++)  {
-        if (MMDB->Model[i])  {
-          Model[i] = newCModel();
-          Model[i]->SetMMDBManager ( this,0 );
-          Model[i]->_copy ( MMDB->Model[i] );
-        } else
-          Model[i] = NULL;
-      }
-    }
-
-    crModel = NULL;
-    crChain = NULL;
-    crRes   = NULL;
-
-    if (MMDB->crModel)  {
-
-      for (i=0;i<nModels;i++)
-        if (Model[i])  {
-          if (Model[i]->serNum==MMDB->crModel->serNum)  {
-            crModel = Model[i];
-            break;
-          }
-        }
-
-      if (crModel && crModel->Chain && MMDB->crChain)
-        for (i=0;i<crModel->nChains;i++)
-          if (crModel->Chain[i])  {
-            if (!strcmp(crModel->Chain[i]->chainID,
-                        MMDB->crModel->Chain[i]->chainID))  {
-              crChain = crModel->Chain[i];
-              break;
-            }
-          }
-
-      if (crChain && crChain->Residue && MMDB->crRes)
-        for (i=0;i<crChain->nResidues;i++)
-          if (crChain->Residue[i])  {
-            if ((!strcmp(crChain->Residue[i]->name,
-                         MMDB->crRes->name))                       &&
-                (crChain->Residue[i]->seqNum==MMDB->crRes->seqNum) &&
-                (!strcmp(crChain->Residue[i]->insCode,
-                         MMDB->crRes->insCode)))  {
-              crRes = crChain->Residue[i];
-              break;
-            }
-          }
-    }
-
-    /*
-    if ((MMDB->nSelections>0) && MMDB->Mask)  {
-      nSelections = MMDB->nSelections;
-      if (nSelections>0)  {
-        Mask      = new PCMask [nSelections];
-        SelAtom   = new PPCAtom[nSelections];
-        nSelAtoms = new int    [nSelections];
-        for (i=0;i<nSelections;i++)  {
-          Mask[i] = new CMask();
-          Mask[i]->CopyMask ( MMDB->Mask[i] );
-          nSelAtoms[i] = MMDB->nSelAtoms[i];
-          if (nSelAtoms[i]>0)  {
-            SelAtom[i] = new PCAtom[nSelAtoms[i]];
-            for (j=0;j<nSelAtoms[i];j++)
-              SelAtom[i][j] = Atom[MMDB->SelAtom[i][j]->index];
-          } else
-            SelAtom[i] = NULL;
-        }
-      }
-    }
-    */
-
-  } else if (CopyMask & (MMDBFCM_HetInfo | MMDBFCM_SecStruct |
-                          MMDBFCM_Links | MMDBFCM_CisPeps |
-                          MMDBFCM_ChainAnnot))  {
-
-    for (i=0;i<MMDB->nModels;i++)
-      if (MMDB->Model[i])  {
-
-        model = GetModel ( i+1 );
-        if (!model)  {
-          model = new CModel( NULL,i+1 );
-          AddModel ( model );
-        }
-
-        if (CopyMask & MMDBFCM_HetInfo)
-          model->CopyHets ( MMDB->Model[i] );
-        if (CopyMask & MMDBFCM_SecStruct)
-          model->CopySecStructure ( MMDB->Model[i] );
-        if (CopyMask & MMDBFCM_Links)  {
-          model->CopyLinks  ( MMDB->Model[i] );
-          model->CopyLinkRs ( MMDB->Model[i] );
-        }
-        if (CopyMask & MMDBFCM_CisPeps)
-          model->CopyCisPeps ( MMDB->Model[i] );
-        if (CopyMask & MMDBFCM_ChainAnnot)  {
-          MMDB->GetChainTable ( i+1,chain,nchains );
-          for (j=0;j<nchains;j++)
-            if (chain[j])  {
-              chain[j]->GetChainID ( chID );
-              ch = model->GetChain ( chID );
-              if (!ch)  {
-                ch = new CChain();
-                ch->SetChainID ( chID );
-                model->AddChain ( ch );
-              }
-              ch->CopyAnnotations ( chain[j] );
-            }
-
-        }
-
-      }
-
-  }
-
-  if (CopyMask & MMDBFCM_SA)  SA.Copy ( &(MMDB->SA) );
-  if (CopyMask & MMDBFCM_SB)  SB.Copy ( &(MMDB->SB) );
-  if (CopyMask & MMDBFCM_SC)  SC.Copy ( &(MMDB->SC) );
-  if (CopyMask & MMDBFCM_Footnotes)
-                       Footnote.Copy ( &(MMDB->Footnote) );
-
-  if (CopyMask & MMDBFCM_Buffer)  {
-    lcount = MMDB->lcount;
-    strncpy ( S,MMDB->S,sizeof(S) );
-  }
-
-}
-
-void  CMMDBManager::Delete ( word DelMask )  {
-PPCModel model;
-PPCChain chain;
-int      i,j,nm, nchains;
-
-  if (DelMask & MMDBFCM_Flags)  Flags = 0;
-
-  if (DelMask & MMDBFCM_Title)        Title.Copy ( NULL );
-  if (DelMask & MMDBFCM_TitleKeepBM)  Title.FreeMemory ( True );
-  if (DelMask & MMDBFCM_Cryst)        Cryst.Copy ( NULL );
-
-  if (DelMask & MMDBFCM_Coord)  {
-    FreeCoordMemory    ();
-    DeleteAllSelections();
-  }
-
-  if (DelMask & MMDBFCM_SecStruct)  {
-    GetModelTable ( model,nm );
-    if (model)
-      for (i=0;i<nm;i++)
-        if (model[i])
-          model[i]->RemoveSecStructure();
-  }
-
-  if (DelMask & MMDBFCM_HetInfo)  {
-    GetModelTable ( model,nm );
-    if (model)
-      for (i=0;i<nm;i++)
-        if (model[i])
-          model[i]->RemoveHetInfo();
-  }
-
-  if (DelMask & MMDBFCM_Links)  {
-    GetModelTable ( model,nm );
-    if (model)
-      for (i=0;i<nm;i++)
-        if (model[i])  {
-          model[i]->RemoveLinks ();
-          model[i]->RemoveLinkRs();
-        }
-  }
-
-  if (DelMask & MMDBFCM_CisPeps)  {
-    GetModelTable ( model,nm );
-    if (model)
-      for (i=0;i<nm;i++)
-        if (model[i])
-          model[i]->RemoveCisPeps();
-  }
-
-  if (DelMask & MMDBFCM_ChainAnnot)  {
-    nm = GetNumberOfModels();
-    for (i=1;i<=nm;i++)  {
-      GetChainTable ( i,chain,nchains );
-      if (chain)
-        for (j=0;j<nchains;j++)
-          if (chain[j])
-            chain[j]->FreeAnnotations();
-    }
-  }
-
-  if (DelMask & MMDBFCM_SA)        SA.FreeContainer();
-  if (DelMask & MMDBFCM_SB)        SB.FreeContainer();
-  if (DelMask & MMDBFCM_SC)        SC.FreeContainer();
-  if (DelMask & MMDBFCM_Footnotes) Footnote.FreeContainer();
-
-  if (DelMask & MMDBFCM_Buffer)  {
-    lcount = 0;
-    S[0]   = char(0);
-  }
-
-}
-
-PCTitleContainer CMMDBManager::GetRemarks()  {
-  return Title.GetRemarks();
-}
-
-
-PCTitleContainer CMMDBManager::GetJournal()  {
-  return Title.GetJournal();
-}
-
-realtype CMMDBManager::GetResolution()  {
-  return Title.GetResolution();
-}
-
-int CMMDBManager::ParseBiomolecules()  {
-  return Title.ParseBiomolecules();
-}
-
-int CMMDBManager::GetNofBiomolecules()  {
-  return Title.GetNofBiomolecules();
-}
-
-void CMMDBManager::GetBiomolecules ( PPCBiomolecule & BM,
-                                     int & nBMs )  {
-  Title.GetBiomolecules ( BM,nBMs );
-}
-
-PCBiomolecule CMMDBManager::GetBiomolecule ( int bmNo )  {
-  return Title.GetBiomolecule ( bmNo );
-}
-
-PCMMDBManager CMMDBManager::MakeBiomolecule ( int bmNo, int modelNo ) {
-PCMMDBManager M;
-PPCChain      ch;
-PCChain       chain;
-PCModel       model;
-PCBiomolecule BM;
-int           i,j,k,n,n0,nChains;
-
-  BM = Title.GetBiomolecule ( bmNo );
-  if (!BM)  return NULL;
-
-  GetChainTable ( modelNo,ch,nChains );
-  if ((!ch) || (nChains<=0))  return NULL;
-
-  n0    = 0;
-  model = new CModel();
-
-  for (i=0;(i<BM->nBMAs) && (n0>=0);i++)
-    if (BM->BMApply[i])  {
-      for (j=0;(j<BM->BMApply[i]->nMatrices) && (n0>=0);j++)
-        for (k=0;(k<BM->BMApply[i]->nChains) && (n0>=0);k++)  {
-          n0 = -1;
-          for (n=0;(n<nChains) && (n0<0);n++)
-            if (!strcmp(ch[n]->GetChainID(),BM->BMApply[i]->chain[k]))
-              n0 = n;
-          if (n0>=0)  {
-            chain = new CChain();
-            chain->Copy ( ch[n0] );
-            chain->ApplyTransform ( BM->BMApply[i]->tm[j] );
-            model->AddChain ( chain );
-          }
-        }
-    }
-
-  if (n0>=0)  {
-    M = new CMMDBManager();
-    M->AddModel ( model );
-    M->PDBCleanup ( PDBCLEAN_SERIAL | PDBCLEAN_INDEX );
-  } else  {
-    delete model;
-    M = NULL;
-  }
-
-  return M;
-
-}
-
-
-//  -------------------  Stream functions  ----------------------
-
-
-void  CMMDBManager::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CMMDBBondManager::write ( f );
-}
-
-void  CMMDBManager::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CMMDBBondManager::read ( f );
-}
-
-
-MakeStreamFunctions(CMMDBManager)
diff --git a/mmdb/mmdb_manager.h b/mmdb/mmdb_manager.h
deleted file mode 100755
index fd04b58..0000000
--- a/mmdb/mmdb_manager.h
+++ /dev/null
@@ -1,122 +0,0 @@
-//  $Id: mmdb_manager.h,v 1.23 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    23.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_manager <interface>
-//       ~~~~~~~~~
-//       Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBManager  ( MMDB file manager )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Manager__
-#define __MMDB_Manager__
-
-#ifndef  __MMDB_BondMngr__
-#include "mmdb_bondmngr.h"
-#endif
-
-
-// =======================  CMMDBManager  ===========================
-
-
-// copy masks
-#define MMDBFCM_All            0xFFFFFFFF
-#define MMDBFCM_Title          0x00000001
-#define MMDBFCM_TitleKeepBM    0x00000002
-#define MMDBFCM_Cryst          0x00000004
-#define MMDBFCM_Coord          0x00000008
-#define MMDBFCM_SecStruct      0x00000010
-#define MMDBFCM_HetInfo        0x00000020
-#define MMDBFCM_Links          0x00000040
-#define MMDBFCM_CisPeps        0x00000080
-#define MMDBFCM_SA             0x00000100
-#define MMDBFCM_SB             0x00000200
-#define MMDBFCM_SC             0x00000400
-#define MMDBFCM_Footnotes      0x00000800
-#define MMDBFCM_ChainAnnot     0x00001000
-#define MMDBFCM_Flags          0x00002000
-#define MMDBFCM_Buffer         0x80000000
-#define MMDBFCM_Top            0xFFFFFFF7
-
-DefineStreamFunctions(CMMDBManager)
-
-class CMMDBManager : public CMMDBBondManager  {
-
-  public :
-
-    CMMDBManager ();
-    CMMDBManager ( RPCStream Object );
-    ~CMMDBManager();
-
-
-    //  ---------------  Copying/Deleting  -----------------------
-
-    //   Copy(..) will transfer different sort of information
-    // between two MMDB's according to the copy mask given
-    // (cf. MMDBFCM_XXXXX values). Note that the copying content
-    // replaces the corresponding information (e.g. copying
-    // coordinates will replace existing coordinates rather than
-    // add to them).
-    void  Copy   ( PCMMDBManager MMDB, word CopyMask );
-
-    //   Delete(..) deletes different sort of information from
-    // the MMDB according to the delete mask given.
-    void  Delete ( word DelMask );  // DelMask is the same as CopyMask
-
-    PCTitleContainer GetRemarks();
-    PCTitleContainer GetJournal();
-
-    realtype GetResolution(); // -1.0 means no resolution record in file
-
-    int   ParseBiomolecules(); // returns the number of biomolecules,
-                               // -2 for general format error
-                               // -3 for errors in BIOMT records
-    int   GetNofBiomolecules();
-    void  GetBiomolecules   ( PPCBiomolecule & BM, int & nBMs );
-
-    PCBiomolecule GetBiomolecule ( int bmNo ); // bmno=0,1,..
-                               // returns NULL if bmNo is incorrect
-    PCMMDBManager MakeBiomolecule ( int bmNo, int modelNo=1 );
-
-
-
-  protected :
-
-    //  ---------------  Stream I/O  -----------------------------
-    void  write  ( RCFile f );
-    void  read   ( RCFile f );
-
-};
-
-#endif
-
diff --git a/mmdb/mmdb_mask.cpp b/mmdb/mmdb_mask.cpp
deleted file mode 100755
index 9f50748..0000000
--- a/mmdb/mmdb_mask.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-//  $Id: mmdb_mask.cpp,v 1.20 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDB_Mask  <implementation>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CMask  ( atom selection mask  )
-//       ~~~~~~~~~
-//
-//  (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MMDB_Mask__
-#include "mmdb_mask.h"
-#endif
-
-
-//  ====================  CMask  ========================
-
-CMask::CMask() : CStream()  {
-  InitMask();
-}
-
-CMask::CMask ( RPCStream Object ) : CStream(Object)  {
-  InitMask();
-}
-
-CMask::~CMask()  {
-  ClearMask();
-}
-
-void CMask::InitMask()  {
-  mlen = 0;
-  m    = NULL;
-}
-
-void CMask::SetMaskBit ( int BitNo )  {
-int n,i;
-  n = BitNo/(8*sizeof(word));
-  Expand ( n+1 );
-  i = BitNo - n*(8*sizeof(word));
-  m[n] |= ((word)1 << i);
-}
-
-void CMask::Expand ( int n )  {
-wvector m1;
-int     i;
-  if (mlen<n)  {
-    m1 = new word[n];
-    for (i=0;i<mlen;i++)
-      m1[i] = m[i];
-    for (i=mlen;i<n;i++)
-      m1[i] = 0;
-    if (m)  delete[] m;
-    m    = m1;
-    mlen = n;
-  }
-}
-
-void  CMask::NewMask ( PPCMask Mask, int nMasks )  {
-int  i,nlen;
-word w;
-  ClearMask();
-  if (Mask && (nMasks>0))  {
-    nlen = 0;
-    w    = 0;
-    while (w==0)  {
-      for (i=0;i<nMasks;i++)
-        if (Mask[i])  {
-          if (nlen<Mask[i]->mlen)
-            w |= Mask[i]->m[nlen];
-        }
-      nlen++;
-      w = ~w;
-    }
-    Expand ( nlen );
-    i    = nlen-1;
-    m[i] = 1;
-    while (!(m[i] & w))
-      m[i] <<= 1;
-  } else  {
-    Expand ( 1 );
-    m[0] = 1;
-  }
-}
-
-void  CMask::CopyMask ( PCMask Mask )  {
-int i;
-  if (mlen!=Mask->mlen)  ClearMask();
-  if (Mask)  {
-    mlen = Mask->mlen;
-    if (mlen>0)  {
-      m = new word[mlen];
-      for (i=0;i<mlen;i++)
-        m[i] = Mask->m[i];
-    }
-  }
-}
-
-void  CMask::SetMask ( PCMask Mask )  {
-int i;
-  if (Mask) {
-    Expand ( Mask->mlen );
-    for (i=0;i<Mask->mlen;i++)
-      m[i] |= Mask->m[i];
-  }
-}
-
-void  CMask::RemoveMask ( PCMask Mask )  {
-int i,l;
-  if (Mask) {
-    l = IMin(mlen,Mask->mlen);
-    for (i=0;i<l;i++)
-      m[i] &= ~Mask->m[i];
-  }
-}
-
-void  CMask::SelMask ( PCMask Mask )  {
-int i,l;
-  if (Mask)  {
-    l = IMin(mlen,Mask->mlen);
-    for (i=0;i<l;i++)
-      m[i] &= Mask->m[i];
-    for (i=l;i<mlen;i++)
-      m[i] = 0;
-  } else
-    ClearMask();
-}
-
-void  CMask::XadMask ( PCMask Mask )  {
-int i;
-  if (Mask) {
-    Expand ( Mask->mlen );
-    for (i=0;i<Mask->mlen;i++)
-      m[i] ^= Mask->m[i];
-  }
-}
-
-void  CMask::ClearMask()  {
-  if (m)  delete[] m;
-  m = NULL;
-  mlen = 0;
-}
-
-void  CMask::NegMask()  {
-int i;
-  for (i=0;i<mlen;i++)
-    m[i] = ~m[i];
-}
-
-Boolean  CMask::CheckMask ( PCMask Mask )  {
-int i,l;
-  if (Mask)  {
-    i = 0;
-    l = IMin(mlen,Mask->mlen);
-    while ((i<l) && (!(m[i] & Mask->m[i])))  i++;
-    return (i<l);
-  } else
-    return False;
-}
-
-Boolean  CMask::isMask()  {
-int i=0;
-  while ((i<mlen) && (!m[i]))  i++;
-  return (i<mlen);
-}
-
-pstr  CMask::Print ( pstr S )  {
-int  i,j,k;
-word w;
-  j = 0;
-  for (i=0;i<mlen;i++)  {
-    w = 1;
-    for (k=0;k<8*(int)sizeof(word);k++)  {
-      if (w & m[i])  S[j] = '1';
-               else  S[j] = '0';
-      w <<= 1;
-      j++;
-    }
-  }
-  S[j] = char(0);
-  return S;
-}
-
-void  CMask::write ( RCFile f )  {
-int i;
-  f.WriteInt ( &mlen );
-  for (i=0;i<mlen;i++)
-    f.WriteWord ( &(m[i]) );
-}
-
-void  CMask::read ( RCFile f )  {
-int i;
-  if (m)  {
-    delete[] m;
-    m = NULL;
-  }
-  f.ReadInt ( &mlen );
-  if (mlen>0)  {
-    m = new word[mlen];
-    for (i=0;i<mlen;i++)
-      f.ReadWord ( &(m[i]) );
-  }
-}
-
-
-MakeStreamFunctions(CMask)
-
-
diff --git a/mmdb/mmdb_mmcif.cpp b/mmdb/mmdb_mmcif.cpp
deleted file mode 100755
index 65b2823..0000000
--- a/mmdb/mmdb_mmcif.cpp
+++ /dev/null
@@ -1,3671 +0,0 @@
-//  $Id: mmdb_mmcif.cpp,v 1.24 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2013.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    07.02.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_MMCIF  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMCIFCategory ( mmCIF category    )
-//       ~~~~~~~~~  CMMCIFStruct   ( mmCIF structure   )
-//                  CMMCIFLoop     ( mmCIF loop        )
-//                  CMMCIFData     ( mmCIF data block  )
-//                  CMMCIFFile     ( mmCIF file        )
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __TIME_H
-#include <time.h>
-#endif
-
-#ifndef  __MMDB_MMCIF__
-#include "mmdb_mmcif.h"
-#endif
-
-
-
-//  ======================  SortTags  ===============================
-
-void  SortTags ( psvector tag, int len, ivector index )  {
-int  i,k,l,l1,l2;
-  if (len==1)  {
-    index[0] = 0;
-    return;
-  }
-  if (strcasecmp(tag[0],tag[1])<0)  {
-    index[0] = 0;
-    index[1] = 1;
-  } else  {
-    index[0] = 1;
-    index[1] = 0;
-  }
-  for (k=2;k<len;k++)  {
-    l2 = k-1;
-    if (strcasecmp(tag[k],tag[index[0]])<0)       l2 = 0;
-    else if (strcasecmp(tag[k],tag[index[l2]])>0) l2 = k;
-    else  {
-      l1 = 0;
-      while (l1<l2-1)  {
-        l = (l1+l2)/2;
-        if (strcasecmp(tag[k],tag[index[l]])<0)  l2 = l;
-                                           else  l1 = l;
-      }
-    }
-    for (i=k;i>l2;i--)
-      index[i] = index[i-1];
-    index[l2] = k;
-  }
-}
-
-
-
-//  ======================  CMMCIFCategory  ==========================
-
-
-CMMCIFCategory::CMMCIFCategory() : CStream()  {
-  InitMMCIFCategory();
-}
-
-CMMCIFCategory::CMMCIFCategory ( cpstr N ) : CStream()  {
-  InitMMCIFCategory();
-  SetCategoryName ( N );
-}
-
-CMMCIFCategory::CMMCIFCategory ( RPCStream Object )
-              : CStream(Object)  {
-  InitMMCIFCategory();
-}
-
-CMMCIFCategory::~CMMCIFCategory()  {
-  FreeMemory();
-}
-
-void CMMCIFCategory::InitMMCIFCategory()  {
-  name       = NULL;
-  nTags      = 0;
-  tag        = NULL;
-  index      = NULL;
-  nAllocTags = 0;
-}
-
-void CMMCIFCategory::FreeMemory()  {
-int i;
-  if (name)  delete[] name;
-  name = NULL;
-  for (i=0;i<nAllocTags;i++)
-    if (tag[i])  delete[] tag[i];
-  FreeVectorMemory ( tag  ,0 );
-  FreeVectorMemory ( index,0 );
-  nTags      = 0;
-  nAllocTags = 0;
-}
-
-void CMMCIFCategory::SetCategoryName ( cpstr N )  {
-  if (N[0])  CreateCopy ( name,N );
-  else  {
-    CreateCopy ( name,pstr(" ") );
-    name[0] = char(1);  // no category name
-  }
-}
-
-void CMMCIFCategory::ExpandTags ( int nTagsNew )  {
-int      i,nAT;
-psvector tag1;
-ivector  index1;
-  if (nTagsNew>nAllocTags)  {
-    nAT = nTagsNew + IMin(nAllocTags/2+1,20);
-    GetVectorMemory ( tag1  ,nAT,0 );
-    GetVectorMemory ( index1,nAT,0 );
-    for (i=0;i<nAllocTags;i++)  {
-      tag1  [i] = tag  [i];
-      index1[i] = index[i];
-    }
-    for (i=nAllocTags;i<nAT;i++)  {
-      tag1  [i] = NULL;
-      index1[i] = i;
-    }
-    FreeVectorMemory ( tag  ,0 );
-    FreeVectorMemory ( index,0 );
-    tag        = tag1;
-    index      = index1;
-    nAllocTags = nAT;
-  }
-}
-
-pstr CMMCIFCategory::GetTag ( int tagNo )  {
-  if ((tagNo>=0) && (tagNo<nTags))  return tag[tagNo];
-  return NULL;
-}
-
-void CMMCIFCategory::Sort()  {
-//  Sorts tags for easing the search
-int i,k;
-  if (nAllocTags>0)  {
-    k = 0;
-    if (!index)
-      GetVectorMemory ( index,nAllocTags,0 );
-    for (i=0;i<nTags;i++)
-      if (tag[i])  {
-        if (k<i)  {
-          tag[k] = tag[i];
-          tag[i] = NULL;
-        }
-        k++;
-      }
-    nTags = k;
-    SortTags ( tag,nTags,index );
-  }
-}
-
-void CMMCIFCategory::Optimize()  {
-int      i,k;
-psvector tag1;
-  k = 0;
-  for (i=0;i<nTags;i++)
-    if (tag[i])  k++;
-  if (k<=0)  FreeMemory();
-  else if (k!=nAllocTags)  {
-    GetVectorMemory  ( tag1,k,0 );
-    FreeVectorMemory ( index,0 );
-    k = 0;
-    for (i=0;i<nTags;i++)
-      if (tag[i])
-        tag1[k++] = tag[i];
-    FreeVectorMemory ( tag,0 );
-    tag        = tag1;
-    nTags      = k;
-    nAllocTags = nTags;
-    Sort();
-  }
-}
-
-int  CMMCIFCategory::GetTagNo ( cpstr ttag )  {
-//   Binary search for index of tag ttag in tag[].
-// Return:
-//    >=0 : position of the tag found
-//     <0 : the tag was not found, it could be inserted before
-//          (-RC-1)th element, where RC is the return value
-int l1,l2,l,k;
-
-  if (!tag)    return -1;
-
-  if (!index)  Sort();
-
-  l = 0;
-  l1 = 0;
-  l2 = nTags-1;
-  k  = 1;
-  while (l1<l2-1)  {
-    l = (l1+l2)/2;
-    k = strcasecmp ( ttag,tag[index[l]] );
-    if (k<0)      l2 = l;
-    else if (k>0) l1 = l;
-    else {
-      l1 = l;
-      break;
-    }
-  }
-
-  if (k==0)  return index[l];    // is at RCth position
-  k = strcasecmp ( ttag,tag[index[l1]] );
-  if (k==0)  return index[l1];   // is at RCth position
-  if (k<0)   return -1;          // would be at (-RC-1)th position
-  if (l2!=l1)  {
-    k = strcasecmp ( ttag,tag[index[l2]] );
-    if (k==0)  return index[l2]; // is at RCth position
-    if (k>0)   return -2-l2;     // would be at l2+1=(-RC-1)th position
-  }
-
-  return -2-l1;                  // would be at l1+1=(-RC-1)th position
-
-}
-
-int  CMMCIFCategory::AddTag ( cpstr ttag )  {
-//  return -1: the tag has been added on the top of array;
-//             index is added and sorted automatically
-//        >=0: the tag is already in the array -- its position
-//             is returned
-int  i1,i;
-  if (!tag)  {
-    ExpandTags ( 3 );  // get space for first 3 tags
-    CreateCopy ( tag[0],ttag );
-    nTags  = 1;
-    return -nTags;  // the tag has been added on the top of array
-  }
-  i1 = GetTagNo ( ttag );
-  if (i1>=0)  return i1;  // non-negative returns mean that
-                          // the tag is already in the array
-  i1 = -i1-1;  // otherwise the tag has to be added and indexed at here
-  // put new tag on the top of array and update index
-  ExpandTags ( nTags+1 );
-  CreateCopy ( tag[nTags],ttag );
-  for (i=nTags;i>i1;i--)
-    index[i] = index[i-1];
-  index[i1] = nTags;
-  nTags++;
-  return -nTags; // the tag has been added on the top of array
-}
-
-void CMMCIFCategory::PrintTags()  {
-int i;
-  Sort();
-  printf ( " Unsorted tags:\n" );
-  for (i=0;i<nTags;i++)
-    if (tag[i])
-      printf ( "  %s.%s\n",name,tag[i] );
-  if (index)  {
-    printf ( " Sorted tags:\n" );
-    for (i=0;i<nTags;i++)
-      if (tag[index[i]])
-        printf ( "  %s.%s\n",name,tag[index[i]] );
-  }
-}
-
-Boolean CMMCIFCategory::CheckTags ( cpstr * tagList )  {
-int i;
-  i = 0;
-  while (tagList[i][0])  {
-    if (GetTagNo(tagList[i])<0)  return False;
-    i++;
-  }
-  return True;
-}
-
-void  CMMCIFCategory::PutCategoryName ( cpstr newName )  {
-  CreateCopy ( name,newName );
-}
-
-void  CMMCIFCategory::Copy ( PCMMCIFCategory Category )  {
-int i;
-  FreeMemory();
-  if (Category)  {
-    CreateCopy ( name,Category->name );
-    nTags      = Category->nTags;
-    nAllocTags = nTags;
-    if (nTags>0) {
-      GetVectorMemory ( tag  ,nAllocTags,0 );
-      GetVectorMemory ( index,nAllocTags,0 );
-      for (i=0;i<nTags;i++)  {
-        tag[i]   = NULL;
-        CreateCopy ( tag[i],Category->tag[i] );
-        index[i] = Category->index[i];
-      }
-    }
-  }
-}
-
-
-void CMMCIFCategory::write ( RCFile f )  {
-int i;
-  if (!index)  Sort();
-  f.CreateWrite ( name   );
-  f.WriteInt    ( &nTags );
-  for (i=0;i<nTags;i++)
-    f.CreateWrite ( tag[i] );
-  f.WriteVector ( index,nTags,0 );
-}
-
-void CMMCIFCategory::read ( RCFile f )  {
-int i;
-  FreeMemory   ();
-  f.CreateRead ( name   );
-  f.ReadInt    ( &nTags );
-  nAllocTags = nTags;
-  if (nTags>0) {
-    GetVectorMemory ( tag,nTags,0 );
-    for (i=0;i<nTags;i++)  {
-      tag[i] = NULL;
-      f.CreateRead ( tag[i] );
-    }
-  }
-  f.CreateReadVector ( index,0 );
-}
-
-MakeStreamFunctions(CMMCIFCategory);
-
-
-
-//  ======================  CMMCIFStruct  ===========================
-
-
-CMMCIFStruct::CMMCIFStruct() : CMMCIFCategory() {
-  InitMMCIFStruct();
-}
-
-CMMCIFStruct::CMMCIFStruct ( cpstr N ) : CMMCIFCategory(N) {
-  InitMMCIFStruct();
-}
-
-CMMCIFStruct::CMMCIFStruct ( RPCStream Object ) : CMMCIFCategory(Object)  {
-  InitMMCIFStruct();
-}
-
-CMMCIFStruct::~CMMCIFStruct()  {
-  FreeMemory();
-}
-
-void CMMCIFStruct::FreeMemory()  {
-int i;
-  for (i=0;i<nAllocTags;i++)
-    if (field[i]) delete[] field[i];
-  FreeVectorMemory ( field,0 );
-  CMMCIFCategory::FreeMemory();
-}
-
-void CMMCIFStruct::InitMMCIFStruct()  {
-  field = NULL;
-}
-
-void CMMCIFStruct::Optimize()  {
-int      i,k;
-psvector f1;
-  k = 0;
-  for (i=0;i<nTags;i++)
-    if (!tag[i])  {
-      if (field[i])  delete[] field[i];
-      field[i] = NULL;
-    } else if (!field[i])  {
-      delete[] tag[i];
-      tag[i] = NULL;
-    } else
-      k++;
-  if (k<=0)  FreeMemory();
-  else if (k!=nAllocTags)  {
-    f1 = new pstr[k];
-    k  = 0;
-    for (i=0;i<nTags;i++)
-      if (tag[i])
-        f1[k++] = field[i];
-    FreeVectorMemory ( field,0 );
-    field = f1;
-    CMMCIFCategory::Optimize();
-  }
-}
-
-void CMMCIFStruct::AddField ( cpstr F, cpstr T, Boolean Concatenate )  {
-psvector field1;
-int      i,nAT;
-pstr     nf;
-
-  nAT = nAllocTags;
-  i   = AddTag ( T );
-
-  if (i<0) {
-    // The tag was not in the list, but has been added on the top
-    // of list. Now expand the field list and put new field on
-    // the top of it.
-    if (nAllocTags>nAT)  {
-      GetVectorMemory ( field1,nAllocTags,0 );
-      for (i=0;i<nTags-1;i++)
-        field1[i] = field[i];
-      for (i=nTags-1;i<nAllocTags;i++)
-        field1[i] = NULL;
-      FreeVectorMemory ( field,0 );
-      field = field1;
-    }
-    i        = nTags-1;
-    field[i] = NULL;
-  }
-
-  if (!F)  {
-    if ((!Concatenate) || (!field[i]))  {
-      CreateCopy ( field[i],pstr(" ?") );
-      field[i][0] = char(2);
-    }
-  } else if ((!Concatenate) || (!field[i]))
-    CreateCopy ( field[i],F );
-  else  {
-    nf = new char[strlen(field[i])+strlen(F)+1];
-    strcpy ( nf,field[i] );
-    strcat ( nf,F        );
-    delete[] field[i];
-    field[i] = nf;
-  }
-
-}
-
-pstr CMMCIFStruct::GetField ( int tagNo )  {
-  if ((tagNo>=0) && (tagNo<nTags))  return field[tagNo];
-  return NULL;
-}
-
-int  CMMCIFStruct::GetString ( pstr & S, cpstr TName,
-                               Boolean Remove )  {
-int k = GetTagNo ( TName );
-  if (S)  delete[] S;
-  S = NULL;
-  if (!field)     return CIFRC_NoField;
-  if (k<0)        return CIFRC_NoTag;
-  if (!field[k])  return CIFRC_NoField;
-  if (field[k][0]==char(2))  {
-    if (Remove)  {
-      delete[] field[k];
-      field[k] = NULL;
-    }
-  } else if (Remove)  {
-    S = field[k];
-    field[k] = NULL;
-  } else
-    CreateCopy ( S,field[k] );
-  return 0;
-}
-
-pstr CMMCIFStruct::GetString ( cpstr TName, int & RC )  {
-int k = GetTagNo ( TName );
-  if (k<0)  {
-    RC = CIFRC_NoTag;
-    return NULL;
-  }
-  if (!field)  {
-    RC = CIFRC_NoField;
-    return NULL;
-  }
-  if (!field[k])  {
-    RC = CIFRC_NoField;
-    return NULL;
-  }
-  RC = 0;
-  if (field[k][0]==char(2))  return NULL;
-  return field[k];
-}
-
-int  CMMCIFStruct::DeleteField ( cpstr TName )  {
-int k = GetTagNo ( TName );
-  if ((k>=0) && (field)) {
-    if (field[k])  delete[] field[k];
-    field[k] = NULL;
-  }
-  return k;
-}
-
-int  CMMCIFStruct::GetReal ( realtype & R, cpstr TName,
-                             Boolean Remove )  {
-pstr endptr;
-int  RC;
-int  k = GetTagNo ( TName );
-  R = 0.0;
-  if (!field)                return CIFRC_NoField;
-  if (k<0)                   return CIFRC_NoTag;
-  if (!field[k])             return CIFRC_NoField;
-  if (field[k][0]==char(2))  return CIFRC_NoData;
-  R = strtod ( field[k],&endptr );
-  if (endptr==field[k])  RC = CIFRC_WrongFormat;
-  else  {
-    RC = 0;
-    if (Remove)  {
-      delete[] field[k];
-      field[k] = NULL;
-    }
-  }
-  return RC;
-}
-
-int  CMMCIFStruct::GetInteger ( int & I, cpstr TName,
-                                Boolean Remove )  {
-pstr endptr;
-int  RC;
-int  k = GetTagNo ( TName );
-  I = 0;
-  if (!field)                return CIFRC_NoField;
-  if (k<0)                   return CIFRC_NoTag;
-  if (!field[k])             return CIFRC_NoField;
-  if (field[k][0]==char(2))  {
-    if (field[k][1]=='.')  I = MinInt4;
-    return CIFRC_NoData;
-  }
-  I = mround ( strtod(field[k],&endptr) );
-  if (endptr==field[k])  RC = CIFRC_WrongFormat;
-  else  {
-    RC = 0;
-    if (Remove)  {
-      delete[] field[k];
-      field[k] = NULL;
-    }
-  }
-  return RC;
-}
-
-
-void CMMCIFStruct::PutString ( cpstr S, cpstr T,
-                               Boolean NonBlankOnly )  {
-pstr p;
-  if (!S)  PutNoData ( CIF_NODATA_QUESTION,T );
-  else  {
-    p = pstr(S);
-    if (NonBlankOnly)
-      while (*p==' ')  p++;
-    if (!(*p))  PutNoData ( CIF_NODATA_DOT,T );
-          else  AddField  ( S,T,False );
-  }
-}
-
-void CMMCIFStruct::PutDate ( cpstr T )  {
-time_t t;
-tm *   tstruct;
- char   S[100];
-  t       = time ( NULL );
-  tstruct = localtime(&t);
-  if (tstruct)
-        sprintf ( S,"%4i-%02i-%02i",
-            tstruct->tm_year+1900,tstruct->tm_mon+1,tstruct->tm_mday );
-  else  strcpy  ( S,"YYYY-MM-DD" );
-  AddField ( S,T,False );
-}
-
-
-void CMMCIFStruct::PutNoData ( int NoDataType, cpstr T )  {
-char S[10];
-  S[0] = char(2);
-  if (NoDataType==CIF_NODATA_DOT)  S[1] = '.';
-                             else  S[1] = '?';
-  S[2] = char(0);
-  AddField ( S,T,False );
-}
-
-
-void CMMCIFStruct::PutReal ( realtype R, cpstr T, int prec )  {
-char rS[100];
-  sprintf  ( rS,"%.*g",prec,R );
-  AddField ( rS,T,False );
-}
-
-void CMMCIFStruct::PutReal ( realtype R, cpstr T, cpstr format )  {
-char rS[100];
-  sprintf  ( rS,format,R );
-  AddField ( DelSpaces(rS,' '),T,False );
-}
-
-void CMMCIFStruct::PutInteger ( int I, cpstr T )  {
-char iS[100];
-  if (I>MinInt4)  {
-    sprintf  ( iS,"%i",I );
-    AddField ( iS,T,False );
-  } else
-    PutNoData ( CIF_NODATA_DOT,T );
-}
-
-
-
-#define  NODATA_Q  pstr("?")
-#define  NODATA_P  pstr(".")
-
-Boolean CMMCIFStruct::WriteMMCIFStruct ( cpstr FName,
-                                         byte gzipMode )  {
-CFile f;
-  f.assign ( FName,True,False,gzipMode );
-  if (f.rewrite())  {
-    WriteMMCIF ( f );
-    f.shut();
-    return True;
-  } else
-    return False;
-}
-
-#define _max_output_line_width 256
-
-void CMMCIFStruct::WriteMMCIF ( RCFile f )  {
-int   i,j,k,l,m,n;
-pstr  F;
-
-  // calculate maximal length of tags
-  l = 0;
-  for (i=0;i<nTags;i++)
-    l = IMax(l,strlen(tag[i]));
-  l += 1;  // add one space separator
-
-  // calculate maximal space left for data
-  m  = _max_output_line_width - l;
-  // subtract category name width
-  if (name[0]!=char(1))  m -= strlen(name);
-
-  // start outout
-  f.LF();
-  for (i=0;i<nTags;i++)  {  // for each tag
-
-    // print category name, if not hidden, and dot
-    if (name[0]!=char(1))  {
-      f.Write ( name      );
-      f.Write ( pstr(".") );
-    }
-
-    // print tag, checking for duplicate tag flag
-    F = strchr ( tag[i],'\1' );
-    if (F)  {
-      *F = char(0);
-      f.Write ( tag[i] );
-      *F = '\1';
-    } else
-      f.Write ( tag[i] );
-
-    // print field
-    if (field[i])  {  // field is defined
-      F = field[i];
-      if (strchr(F,'\n') || strstr(F,"\" "))  {
-        f.Write ( pstr("\n;")   );
-        f.Write ( F             );
-        f.Write ( pstr("\n;\n") );
-      } else {
-        n = strlen(F);
-        if (n>m)  // wrap around if field is too long
-          f.Write ( pstr("\n ") );
-        else {
-          k = l-strlen(tag[i]);
-          for (j=0;j<k;j++)
-            f.Write ( pstr(" ") );
-        }
-        if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) ||
-            strchr(F,' '))  {
-          f.Write ( pstr("\"")   );
-          f.Write ( field[i]     );
-          f.Write ( pstr("\"\n") );
-        } else if (field[i][0]==char(2))  {
-          f.WriteLine ( &(field[i][1]) );
-        } else if (!field[i][0])  {
-          f.WriteLine ( NODATA_P );
-        } else
-          f.WriteLine ( field[i] );
-      }
-
-    } else  {  // field if not defined, put question mark
-
-      k = l-strlen(tag[i]);
-      for (j=0;j<k;j++)
-        f.Write ( pstr(" ") );
-      f.WriteLine ( NODATA_Q );
-
-    }
-
-  }
-
-}
-
-void CMMCIFStruct::Copy ( PCMMCIFCategory Struct )  {
-int i;
-  CMMCIFCategory::Copy ( Struct );
-  if (nTags>0)  {
-    GetVectorMemory ( field,nTags,0 );
-    for (i=0;i<nTags;i++)  {
-      field[i] = NULL;
-      CreateCopy ( field[i],PCMMCIFStruct(Struct)->field[i] );
-    }
-  }
-}
-
-void CMMCIFStruct::write ( RCFile f )  {
-int i;
-  CMMCIFCategory::write ( f );
-  for (i=0;i<nTags;i++)
-    f.CreateWrite ( field[i] );
-}
-
-void CMMCIFStruct::read ( RCFile f )  {
-int i;
-  CMMCIFCategory::read ( f );
-  if (nTags>0)  {
-    GetVectorMemory ( field,nTags,0 );
-    for (i=0;i<nTags;i++)  {
-      field[i] = NULL;
-      f.CreateRead ( field[i] );
-    }
-  }
-}
-
-
-MakeStreamFunctions(CMMCIFStruct);
-
-
-
-//  ======================  CMMCIFLoop  ==============================
-
-
-CMMCIFLoop::CMMCIFLoop() : CMMCIFCategory()  {
-  InitMMCIFLoop();
-}
-
-CMMCIFLoop::CMMCIFLoop ( cpstr N ) : CMMCIFCategory(N)  {
-  InitMMCIFLoop();
-}
-
-CMMCIFLoop::CMMCIFLoop ( RPCStream Object ) : CMMCIFCategory(Object)  {
-  InitMMCIFLoop();
-}
-
-CMMCIFLoop::~CMMCIFLoop()  {
-  FreeMemory();
-}
-
-void CMMCIFLoop::InitMMCIFLoop()  {
-  nRows      = 0;
-  field      = NULL;
-  iColumn    = 0;
-  nAllocRows = 0;
-}
-
-void CMMCIFLoop::FreeMemory()  {
-  DeleteFields();
-  CMMCIFCategory::FreeMemory();
-}
-
-void CMMCIFLoop::Optimize()  {
-int      i,j,nT,nR,k,m;
-Boolean  empty;
-psmatrix f1;
-
-  if (!field)  {
-    CMMCIFCategory::Optimize();  // optimize tags
-    return;
-  }
-
-  // first check for empty columns
-  nT = 0;
-  for (i=0;i<nTags;i++)
-    if (!tag[i])  {
-      for (j=0;j<nRows;j++)  // delete ith column of field
-        if (field[j])  {
-          if (field[j][i])
-            delete[] field[j][i];
-          field[j][i] = NULL;
-        }
-    } else  {
-      empty = True;
-      j = 0;
-      while ((j<nRows) && empty)  {  // check if ith column is empty
-        if (field[j])
-          empty = !field[j][i];
-        j++;
-      }
-      if (empty)  {    // if ith column is empty, delete its tag
-        delete[] tag[i];
-        tag[i] = NULL;
-      } else           // otherwise count ith tag
-        nT++;
-    }
-
-  // now check for empty rows
-  nR = 0;
-  for (j=0;j<nRows;j++)
-    if (field[j])  {
-      i = 0;
-      while ((i<nTags) && (!field[j][i])) i++;
-      if (i>=nTags)  {
-        delete[] field[j];  // delete empty row
-        field[j] = NULL;
-      } else
-        nR++;             // count non-empty row
-    }
-  if ((nT<=0) || (nR<=0))
-    FreeMemory();  // the loop is completely empty
-  else if ((nT!=nTags) || (nR!=nAllocRows))  {
-    f1 = new psvector[nR];
-    m  = 0;
-    for (j=0;j<nRows;j++)
-      if (field[j])  {
-        f1[m] = new pstr[nT];
-        k = 0;
-        for (i=0;i<nTags;i++)
-          if (tag[i])
-            f1[m][k++] = field[j][i];
-        m++;
-        delete[] field[j];
-      }
-    if (field)  delete[] field;
-    field = f1;
-    nRows = nR;
-    nAllocRows = nRows;
-    CMMCIFCategory::Optimize();  // optimize tags
-  }
-
-}
-
-void CMMCIFLoop::DeleteFields()  {
-int i,j;
-  if (field)  {
-    for (i=0;i<nAllocRows;i++)
-      if (field[i])  {
-        for (j=0;j<nTags;j++)
-          if (field[i][j])  delete[] field[i][j];
-        delete[] field[i];
-      }
-    delete[] field;
-    field      = NULL;
-    nRows      = 0;
-    nAllocRows = 0;
-  }
-}
-
-void CMMCIFLoop::AddLoopTag ( cpstr T, Boolean Remove )  {
-psmatrix  f1;
-int       i,j,nT1;
-  if (Remove)  {
-    DeleteFields();
-    AddTag ( T );
-  } else  {
-    f1    = field;
-    field = NULL;
-    i     = AddTag ( T );
-    if ((f1) && (i<0))  {
-      // The tag was added on the top of tag array. Create
-      // and fill new fields.
-      field = new psvector[nAllocRows];
-      nT1   = nTags-1;
-      for (i=0;i<nAllocRows;i++)
-        if (f1[i])  {
-          field[i] = new pstr[nTags];
-          for (j=0;j<nT1;j++)
-            field[i][j] = f1[i][j];
-          field[i][nT1] = NULL;
-          f1[i] = NULL;
-        } else
-          field[i] = NULL;
-      delete[] f1;
-    } else
-      // The tag was already in the category. Just restore fields.
-      field = f1;
-  }
-}
-
-
-void CMMCIFLoop::ExpandRows ( int nRowsNew )  {
-int      nAR,i;
-psmatrix field1;
-  if (nRowsNew>nAllocRows)  {
-    nAR    = nRowsNew + IMin(nAllocRows/2+10,2000);
-    field1 = new psvector[nAR];
-    for (i=0;i<nAllocRows;i++)
-      field1[i] = field[i];
-    for (i=nAllocRows;i<nAR;i++)
-      field1[i] = NULL;
-    if (field)  delete[] field;
-    field      = field1;
-    nAllocRows = nAR;
-  }
-}
-
-void CMMCIFLoop::AddString ( cpstr S, Boolean NonBlankOnly )  {
-int  i;
-pstr p;
-  if (!S)  AddNoData ( CIF_NODATA_QUESTION );
-  else  {
-    p = pstr(S);
-    if (NonBlankOnly)
-      while (*p==' ')  p++;
-    if (!(*p))  AddNoData ( CIF_NODATA_DOT );
-    else  {
-      if (iColumn==0)  {  // start a new row
-        ExpandRows ( nRows+1 );
-        field[nRows] = new pstr[nTags];
-        for (i=0;i<nTags;i++)
-          field[nRows][i] = NULL;
-        nRows++;
-      }
-      CreateCopy ( field[nRows-1][iColumn],S );
-      iColumn++;
-      if (iColumn>=nTags) iColumn = 0;
-    }
-  }
-}
-
-void CMMCIFLoop::AddNoData ( int NoDataType )  {
-char S[10];
-  S[0] = char(2);
-  if (NoDataType==CIF_NODATA_DOT)  S[1] = '.';
-                             else  S[1] = '?';
-  S[2] = char(0);
-  AddString ( S );
-}
-
-void CMMCIFLoop::AddReal ( realtype R, int prec )  {
-char rS[100];
-  sprintf ( rS,"%.*g",prec,R );
-  AddString ( rS );
-}
-
-void CMMCIFLoop::AddReal ( realtype R, cpstr format )  {
-char rS[100];
-  sprintf ( rS,format,R );
-  AddString ( DelSpaces(rS,' ') );
-}
-
-void CMMCIFLoop::AddInteger ( int I )  {
-char iS[100];
-  if (I>MinInt4)  {
-    sprintf ( iS,"%i",I );
-    AddString ( iS );
-  } else
-    AddNoData ( CIF_NODATA_DOT );
-}
-
-
-pstr CMMCIFLoop::GetField ( int rowNo, int tagNo )  {
-  if ((tagNo>=0) && (tagNo<nTags) &&
-      (rowNo>=0) && (rowNo<nRows))  {
-    if (field[rowNo])  return field[rowNo][tagNo];
-  }
-  return NULL;
-}
-
-int  CMMCIFLoop::GetString ( pstr & S, cpstr TName, int nrow,
-                             Boolean Remove)  {
-int k = GetTagNo ( TName );
-  if (S)  delete[] S;
-  S = NULL;
-  if (k<0)                       return CIFRC_NoTag;
-  if ((nrow<0) || (nrow>=nRows)) return CIFRC_WrongIndex;
-  if (!field[nrow])              return CIFRC_NoField;
-  if (!field[nrow][k])           return CIFRC_NoField;
-  if (field[nrow][k][0]==char(2))  {
-    if (Remove)  {
-      delete[] field[nrow][k];
-      field[nrow][k] = NULL;
-    }
-  } else if (Remove)  {
-    S = field[nrow][k];
-    field[nrow][k] = NULL;
-  } else
-    CreateCopy ( S,field[nrow][k] );
-  return 0;
-}
-
-pstr CMMCIFLoop::GetString ( cpstr TName, int nrow, int & RC )  {
-int k = GetTagNo ( TName );
-  if (k<0)  {
-    RC = CIFRC_NoTag;
-    return NULL;
-  }
-  if ((nrow<0) || (nrow>=nRows))  {
-    RC = CIFRC_WrongIndex;
-    return NULL;
-  }
-  if (!field[nrow])  {
-    RC = CIFRC_NoField;
-    return NULL;
-  }
-  if (!field[nrow][k])  {
-    RC = CIFRC_NoField;
-    return NULL;
-  }
-  RC = 0;
-  // char(2) means the field was either '.' or '?'
-  if (field[nrow][k][0]==char(2))  return NULL;
-  return field[nrow][k];
-}
-
-//  CopyString() does nothing if RC is not 0
-void CMMCIFLoop::CopyString   ( pstr  buf,   int maxlength,
-                                cpstr TName, int nrow, int & RC )  {
-pstr p;
-int  k;
-
-  if (RC)  return;
-
-  k = GetTagNo ( TName );
-  if (k<0)  {
-    RC = CIFRC_NoTag;
-    buf[0] = char(0);
-    return;
-  }
-  if ((nrow<0) || (nrow>=nRows))  {
-    RC = CIFRC_WrongIndex;
-    buf[0] = char(0);
-    return;
-  }
-  if (!field[nrow])  {
-    RC = CIFRC_NoField;
-    buf[0] = char(0);
-    return;
-  }
-  p = field[nrow][k];
-  if (!p)  {
-    RC = CIFRC_NoField;
-    buf[0] = char(0);
-    return;
-  }
-
-  // char(2) means the field was either '.' or '?'
-  if (p[0]==char(2))  {
-    buf[0] = p[0];
-    buf[1] = char(0);
-  } else
-    strncpy ( buf,p,IMin(maxlength,strlen(p)+1) );
-
-}
-
-
-
-int CMMCIFLoop::DeleteField ( cpstr TName, int nrow )  {
-int k = GetTagNo ( TName );
-  if (k<0)  return CIFRC_NoTag;
-  if ((nrow<0) || (nrow>=nRows))
-            return CIFRC_WrongIndex;
-  if (field[nrow])  {
-    if (field[nrow][k])  delete[] field[nrow][k];
-    field[nrow][k] = NULL;
-  }
-  return k;
-}
-
-int CMMCIFLoop::DeleteRow ( int nrow )  {
-int i;
-  if ((nrow<0) || (nrow>=nRows))
-            return CIFRC_WrongIndex;
-  if (field[nrow])  {
-    for (i=0;i<nTags;i++)
-      if (field[nrow][i])  {
-        delete[] field[nrow][i];
-        field[nrow][i] = NULL;
-      }
-    delete[] field[nrow];
-    field[nrow] = NULL;
-  }
-  return 0;
-}
-
-int  CMMCIFLoop::GetReal ( realtype & R, cpstr TName, int nrow,
-                           Boolean Remove )  {
-pstr endptr;
-int  k = GetTagNo ( TName );
-  if (k<0)  return CIFRC_NoTag;
-  if ((nrow<0) || (nrow>=nRows))
-            return CIFRC_WrongIndex;
-  R = 0.0;
-  if (!field[nrow])                return CIFRC_NoField;
-  if (!field[nrow][k])             return CIFRC_NoField;
-  if (field[nrow][k][0]==char(2))  return CIFRC_NoField;
-  R = strtod ( field[nrow][k],&endptr );
-  if (endptr==field[nrow][k])      return CIFRC_WrongFormat;
-  if (Remove)  {
-    delete[] field[nrow][k];
-    field[nrow][k] = NULL;
-  }
-  return 0;
-}
-
-void CMMCIFLoop::CopyReal ( realtype & R, cpstr TName, int nrow,
-                            int & RC )  {
-pstr endptr;
-int  k;
-
-  if (RC)  return;
-
-//  R = 0.0;
-  k = GetTagNo ( TName );
-
-  if (k<0)                              RC = CIFRC_NoTag;
-  else if ((nrow<0) || (nrow>=nRows))   RC = CIFRC_WrongIndex;
-  else if (!field[nrow])                RC = CIFRC_NoField;
-  else if (!field[nrow][k])             RC = CIFRC_NoField;
-  else if (field[nrow][k][0]==char(2))  RC = CIFRC_NoField;
-  else  {
-    R = strtod ( field[nrow][k],&endptr );
-    if (endptr==field[nrow][k])  RC = CIFRC_WrongFormat;
-  }
-
-}
-
-void CMMCIFLoop::CopyInteger ( int & I, cpstr TName, int nrow,
-                               int & RC )  {
-pstr endptr;
-int  k;
-
-  if (RC)  return;
-
-  I = 0;
-  k = GetTagNo ( TName );
-
-  if (k<0)                              RC = CIFRC_NoTag;
-  else if ((nrow<0) || (nrow>=nRows))   RC = CIFRC_WrongIndex;
-  else if (!field[nrow])                RC = CIFRC_NoField;
-  else if (!field[nrow][k])             RC = CIFRC_NoField;
-  else if (field[nrow][k][0]==char(2))  RC = CIFRC_NoField;
-  else  {
-    I = mround ( strtod ( field[nrow][k],&endptr ) );
-    if (endptr==field[nrow][k])  RC = CIFRC_WrongFormat;
-  }
-
-}
-
-int  CMMCIFLoop::GetInteger ( int & I, cpstr TName, int nrow,
-                              Boolean Remove )  {
-pstr endptr;
-int  k = GetTagNo ( TName );
-  if (k<0)  return CIFRC_NoTag;
-  if ((nrow<0) || (nrow>=nRows))
-            return CIFRC_WrongIndex;
-  I = 0;
-  if (!field[nrow])                return CIFRC_NoField;
-  if (!field[nrow][k])             return CIFRC_NoField;
-  if (field[nrow][k][0]==char(2))  {
-    if (field[nrow][k][1]=='.')  I = MinInt4;
-    return CIFRC_NoField;
-  }
-  I = mround ( strtod(field[nrow][k],&endptr) );
-  if (endptr==field[nrow][k])      return CIFRC_WrongFormat;
-  if (Remove)  {
-    delete[] field[nrow][k];
-    field[nrow][k] = NULL;
-  }
-  return 0;
-}
-
-
-int  CMMCIFLoop::GetSVector ( psvector & S, cpstr TName,
-                              int i1, int i2, Boolean Remove )  {
-int j,k,r1,r2;
-  r1 = IMin(i1,i2);
-  r2 = IMin(IMax(i1,i2),nRows-1);
-  if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
-  k = GetTagNo ( TName );
-  if (k<0)  return CIFRC_NoTag;
-  if (!S)
-    GetVectorMemory ( S,r2-r1+1,r1 );
-  if (Remove)  {
-    for (j=r1;j<=r2;j++)
-      if (field[j])  {
-        S[j] = field[j][k];
-        field[j][k] = NULL;
-        if (S[j])  {
-          if (S[j][0]==char(2))  {
-            delete[] S[j];
-            S[j] = NULL;
-          }
-        }
-      } else
-        S[j] = NULL;
-  } else  {
-    for (j=r1;j<=r2;j++)  {
-      S[j] = NULL;
-      if (field[j])  {
-        if (field[j][k])  {
-          if (field[j][k][0]!=char(2))
-            CreateCopy ( S[j],field[j][k] );
-        }
-      }
-    }
-  }
-  return 0;
-}
-
-int  CMMCIFLoop::GetRVector ( rvector & R, cpstr TName,
-                              int i1, int i2, Boolean Remove )  {
-int  j,k,r1,r2,RC;
-pstr endptr;
-  r1 = IMin(i1,i2);
-  r2 = IMin(IMax(i1,i2),nRows-1);
-  if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
-  k = GetTagNo ( TName );
-  if (k<0)  return CIFRC_NoTag;
-  if (!R)
-    GetVectorMemory ( R,r2-r1+1,r1 );
-  RC = 0;
-  for (j=r1;j<=r2;j++)  {
-    R[j] = 0.0;
-    if (field[j])  {
-      if (field[j][k])  {
-        R[j] = strtod ( field[j][k],&endptr );
-        if (endptr==field[j][k])  RC = CIFRC_WrongFormat;
-        if (Remove)  {
-          delete[] field[j][k];
-          field[j][k] = NULL;
-        }
-      }
-    }
-  }
-  return RC;
-}
-
-int  CMMCIFLoop::GetIVector ( ivector & I, cpstr TName,
-                              int i1, int i2, Boolean Remove )  {
-int  j,k,r1,r2,RC;
-pstr endptr;
-  r1 = IMin(i1,i2);
-  r2 = IMin(IMax(i1,i2),nRows-1);
-  if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
-  k = GetTagNo ( TName );
-  if (k<0)    return CIFRC_NoTag;
-  if (!I)
-    GetVectorMemory ( I,r2-r1+1,r1 );
-  RC = 0;
-  for (j=r1;j<=r2;j++)  {
-    I[j] = 0;
-    if (field[j])  {
-      if (field[j][k])  {
-        I[j] = mround ( strtod(field[j][k],&endptr) );
-        if (endptr==field[j][k]) RC = CIFRC_WrongFormat;
-        if (Remove)  {
-          delete[] field[j][k];
-          field[j][k] = NULL;
-        }
-      }
-    }
-  }
-  return RC;
-}
-
-
-void CMMCIFLoop::PutString ( cpstr S, cpstr T, int nrow )  {
-psmatrix field1;
-int      nT,nR,iT,i,j;
-  nT = nTags;
-  nR = nRows;
-  iT = AddTag ( T );
-  if (iT<0)  iT = nTags-1;
-  if (nTags>nT)  {
-    // a new tag has been added; all field must be reallocated.
-    nRows      = IMax(nR,nrow+1);  // nrow is indexed like 0,1,...
-    nAllocRows = IMax(nR,nrow+IMin(nR/2+1,2000));
-    field1     = new psvector[nAllocRows];
-    for (i=0;i<nR;i++)
-      if (field[i])  {
-        field1[i] = new pstr[nTags];
-        for (j=0;j<nT;j++)
-          field1[i][j] = field[i][j];
-        for (j=nT;j<nTags;j++)
-          field1[i][j] = NULL;
-        delete[] field[i];
-      } else
-        field1[i] = NULL;
-    for (i=nR;i<nRows;i++)
-      field1[i] = NULL;
-    if (field)  delete[] field;
-    field = field1;
-  } else if (nrow>=nR)  {
-    // only new rows are to be added
-    ExpandRows ( nrow+1 );
-    nRows++;
-  }
-  if (!field[nrow])  {
-    field[nrow] = new pstr[nTags];
-    for (j=0;j<nTags;j++)
-      field[nrow][j] = NULL;
-  }
-  CreateCopy ( field[nrow][iT],S );
-  iColumn = iT+1;
-  if (iColumn>=nTags) iColumn = 0;
-}
-
-
-void CMMCIFLoop::PutNoData ( int NoDataType, cpstr T, int nrow )  {
-char S[10];
-  S[0] = char(2);
-  if (NoDataType==CIF_NODATA_DOT)  S[1] = '.';
-                             else  S[1] = '?';
-  S[2] = char(0);
-  PutString ( S,T,nrow );
-}
-
-
-void CMMCIFLoop::PutReal ( realtype R, cpstr T, int nrow, int prec )  {
-char rS[100];
-  sprintf ( rS,"%.*g",prec,R );
-  PutString ( rS,T,nrow );
-}
-
-void CMMCIFLoop::PutReal ( realtype R, cpstr T, int nrow,
-                           cpstr format )  {
-char rS[100];
-  sprintf ( rS,format,R );
-  PutString ( DelSpaces(rS,' '),T,nrow );
-}
-
-void CMMCIFLoop::PutInteger ( int I, cpstr T, int nrow )  {
-char iS[100];
-  if (I>MinInt4)  {
-    sprintf ( iS,"%i",I );
-    PutString ( iS,T,nrow );
-  } else
-    PutNoData ( CIF_NODATA_DOT,T,nrow );
-}
-
-void CMMCIFLoop::PutSVector ( psvector S, cpstr T, int i1, int i2 )  {
-int i,j,k;
-  PutString ( S[i2],T,i2 );
-  if (iColumn==0)  k = nTags-1;
-             else  k = iColumn-1;
-  for (i=i2-1;i>=i1;i--)  {
-    if (!field[i])  {
-      field[i] = new pstr[nTags];
-      for (j=0;j<nTags;j++)
-        field[i][j] = NULL;
-    }
-    CreateCopy ( field[i][k],S[i] );
-  }
-}
-
-void CMMCIFLoop::PutRVector ( rvector R, cpstr T,
-                              int i1, int i2, int prec )  {
-int  i,j,k;
-char rS[100];
-  PutReal ( R[i2],T,i2,prec );
-  if (iColumn==0)  k = nTags-1;
-             else  k = iColumn-1;
-  for (i=i2-1;i>=i1;i--)  {
-    if (!field[i])  {
-      field[i] = new pstr[nTags];
-      for (j=0;j<nTags;j++)
-        field[i][j] = NULL;
-    }
-    sprintf ( rS,"%.*g",prec,R[i] );
-    CreateCopy ( field[i][k],rS );
-  }
-}
-
-void CMMCIFLoop::PutIVector ( ivector I, cpstr T,
-                              int i1, int i2 )  {
-int  l,j,k;
-char iS[100];
-  PutInteger ( I[i2],T,i2 );
-  if (iColumn==0)  k = nTags-1;
-             else  k = iColumn-1;
-  for (l=i2-1;l>=i1;l--)  {
-    if (!field[l])  {
-      field[l] = new pstr[nTags];
-      for (j=0;j<nTags;j++)
-        field[l][j] = NULL;
-    }
-    sprintf ( iS,"%i",I[l] );
-    CreateCopy ( field[l][k],iS );
-  }
-}
-
-Boolean CMMCIFLoop::WriteMMCIFLoop ( cpstr FName,
-                                     byte gzipMode )  {
-CFile f;
-  f.assign ( FName,True,False,gzipMode );
-  if (f.rewrite())  {
-    WriteMMCIF ( f );
-    f.shut();
-    return True;
-  } else
-    return False;
-}
-
-void CMMCIFLoop::WriteMMCIF ( RCFile f )  {
-int     i,j,k,m,n;
-ivector l;
-pstr    F;
-
-  // write loop keyword
-  f.Write ( pstr("\nloop_\n") );
-
-  GetVectorMemory ( l,nTags,0 );
-  k = 0;
-  for (i=0;i<nTags;i++)  {
-    if (name[0]!=char(1))  {
-      f.Write ( name      );
-      f.Write ( pstr(".") );
-    }
-    F = strchr ( tag[i],'\1' );
-    if (F)  {
-      *F = char(0);
-      f.WriteLine ( tag[i] );
-      *F = '\1';
-    } else
-      f.WriteLine ( tag[i] );
-    l[i] = 0;
-    for (j=0;j<nRows;j++)
-      if (field[j])  {
-        if (field[j][i])  {
-          F = field[j][i];
-          if (strchr(F,'\n') || strstr(F,"\" "))
-                                   l[i] = 10001;
-          else if (F[0]==char(2))  l[i] = IMax(l[i],1);
-          else if (((F[0]=='.') || (F[0]=='?')) &&
-                   (!F[1]))        l[i] = IMax(l[i],3);
-          else  {
-            if (strchr(F,' '))  m = 2;
-                          else  m = 0;
-            l[i] = IMax(l[i],strlen(F)+m);
-          }
-        }
-      }
-    l[i] = IMax(l[i],1);
-    k += l[i]+1;
-    if (k>_max_output_line_width)  {
-      l[i] = -l[i];
-      k = 0;
-    }
-  }
-  for (i=0;i<nRows;i++)  {
-    m = 0;  // counts symbols in the string
-    k = 0;  // rest of left-aligned fields to fill with spaces
-    for (j=0;j<nTags;j++)  {
-      n = k;
-      k = l[j];   // length of the field
-      if (k<0)  k = -k;
-      m += k+1;
-      if (m>_max_output_line_width)  {
-        f.LF();
-        m = k+1;
-      } else
-        while (n>0) {
-          f.Write ( pstr(" ") );
-          n--;
-        }
-      if (field[i])  {
-        if (field[i][j])  {
-          F = field[i][j];
-          if (k>10000)  {
-            if (F[0]==char(2))  {
-              f.Write     ( pstr(" ") );
-              f.WriteLine ( &(F[1])   );
-            } else if (!F[0])  {
-              f.Write     ( pstr(" ") );
-              f.WriteLine ( NODATA_P  );
-            } else  {
-              f.Write     ( pstr(";") );
-              f.WriteLine ( F         );
-              f.WriteLine ( pstr(";") );
-            }
-            m = 0;
-            k = 0;
-          } else if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) ||
-                     strchr(F,' '))  {
-            f.Write ( pstr(" \"") );
-            f.Write ( F           );
-            f.Write ( pstr("\"")  );
-            k -= strlen(F)+2;
-          } else if (F[0]==char(2))  {
-            f.Write ( pstr(" ") );
-            f.Write ( &(F[1])   );
-            k--;
-          } else if (!F[0])  {
-            f.Write ( pstr(" ") );
-            f.Write ( NODATA_P  );
-            k--;
-          } else  {
-            f.Write ( pstr(" ") );
-            f.Write ( F         );
-            k -= strlen(F);
-          }
-        } else  {
-          f.Write ( pstr(" ") );
-          f.Write ( NODATA_Q  );
-          k--;
-        }
-      } else  {
-        f.Write ( pstr(" ") );
-        f.Write ( NODATA_Q  );
-        k--;
-      }
-    }
-    if (m) f.LF();
-  }
-
-}
-
-
-void CMMCIFLoop::Copy ( PCMMCIFCategory Loop )  {
-int i,j;
-  CMMCIFCategory::Copy ( Loop );
-  nRows      = PCMMCIFLoop(Loop)->nRows;
-  nAllocRows = nRows;
-  if ((nTags>0) && (nRows>0))  {
-    field = new psvector[nRows];
-    for (i=0;i<nRows;i++)  {
-      if (PCMMCIFLoop(Loop)->field[i])  {
-        field[i] = new pstr[nTags];
-        for (j=0;j<nTags;j++)  {
-          field[i][j] = NULL;
-          CreateCopy ( field[i][j],PCMMCIFLoop(Loop)->field[i][j] );
-        }
-      } else
-        field[i] = NULL;
-    }
-  }
-  iColumn = PCMMCIFLoop(Loop)->iColumn;
-}
-
-
-void CMMCIFLoop::write ( RCFile f )  {
-int i,j;
-  CMMCIFCategory::write ( f );
-  f.WriteInt ( &nRows );
-  if ((nTags>0) && (nRows>0))
-    for (i=0;i<nRows;i++)
-      if (field[i])  {
-        j = 1;
-        f.WriteInt ( &j );
-        for (j=0;j<nTags;j++)
-          f.CreateWrite ( field[i][j] );
-      } else  {
-        j = 0;
-        f.WriteInt ( &j );
-      }
-  f.WriteInt ( &iColumn );
-}
-
-void CMMCIFLoop::read ( RCFile f )  {
-int i,j;
-  CMMCIFCategory::read ( f );
-  f.ReadInt ( &nRows );
-  nAllocRows = nRows;
-  if ((nTags>0) && (nRows>0))  {
-    field = new psvector[nRows];
-    for (i=0;i<nRows;i++)  {
-      f.ReadInt ( &j );
-      if (j)  {
-        field[i] = new pstr[nTags];
-        for (j=0;j<nTags;j++)  {
-          field[i][j] = NULL;
-          f.CreateRead ( field[i][j] );
-        }
-      } else
-        field[i] = NULL;
-    }
-  }
-  f.ReadInt ( &iColumn );
-}
-
-
-MakeStreamFunctions(CMMCIFLoop)
-
-
-
-//  ======================  CMMCIFData  =============================
-
-
-CMMCIFData::CMMCIFData() : CStream()  {
-  InitMMCIFData();
-}
-
-CMMCIFData::CMMCIFData ( cpstr N ) : CStream()  {
-  InitMMCIFData();
-  CreateCopy ( name,N );
-}
-
-CMMCIFData::CMMCIFData ( RPCStream Object ) : CStream(Object)  {
-  InitMMCIFData();
-}
-
-CMMCIFData::~CMMCIFData() {
-  FreeMemory(0);
-}
-
-void CMMCIFData::InitMMCIFData()  {
-  name         = NULL;
-  nCategories  = 0;
-  Category     = NULL;
-  index        = NULL;
-  flags        = 0;
-  Warning      = 0;
-  loopNo       = 0;
-  tagNo        = 0;
-  WrongCat     = NULL;
-  WrongTag     = NULL;
-  nWrongFields = 0;
-}
-
-void CMMCIFData::FreeMemory ( int key )  {
-int i;
-  if (name)  delete[] name;
-  name = NULL;
-  if (Category)  {
-    for (i=0;i<nCategories;i++)
-      if (Category[i]) delete Category[i];
-    delete[] Category;
-    Category = NULL;
-  }
-  nCategories = 0;
-  FreeVectorMemory ( index,0 );
-  if (key==0)  FreeWrongFields();
-}
-
-void CMMCIFData::FreeWrongFields()  {
-int i;
-  if (WrongCat)  {
-    for (i=0;i<nWrongFields;i++)
-      if (WrongCat[i])  delete[] WrongCat[i];
-    delete[] WrongCat;
-  }
-  if (WrongTag)  {
-    for (i=0;i<nWrongFields;i++)
-      if (WrongTag[i])  delete[] WrongTag[i];
-    delete[] WrongTag;
-  }
-  WrongCat     = NULL;
-  WrongTag     = NULL;
-  nWrongFields = 0;
-}
-
-
-void  CMMCIFData::SetPrintWarnings ( Boolean SPW )  {
-  if (SPW)  SetFlag    ( CIFFL_PrintWarnings );
-      else  RemoveFlag ( CIFFL_PrintWarnings );
-}
-
-void  CMMCIFData::SetStopOnWarning ( Boolean SOW )  {
-  if (SOW)  SetFlag    ( CIFFL_StopOnWarnings );
-      else  RemoveFlag ( CIFFL_StopOnWarnings );
-}
-
-void  CMMCIFData::SetFlag ( int F )  {
-  flags |= F;
-}
-
-void  CMMCIFData::RemoveFlag ( int F )  {
-  flags &= ~F;
-}
-
-void  CMMCIFData::SetWrongFields ( cpstr *cats, cpstr *tags )  {
-int i,lc,lt;
-  FreeWrongFields();
-  if ((!cats) || (!tags))  return;
-  lc = 0;
-  while (cats[lc]) lc++;
-  lt = 0;
-  while (tags[lt]) lt++;
-  nWrongFields = IMax(lc,lt);
-  if (nWrongFields>0)  {
-    WrongCat = new pstr[nWrongFields];
-    WrongTag = new pstr[nWrongFields];
-    for (i=0;i<nWrongFields;i++)  {
-      WrongCat[i] = NULL;
-      WrongTag[i] = NULL;
-      if (cats[i])  {
-        if (cats[i][0])  CreateCopy ( WrongCat[i],cats[i] );
-      }
-      if (!WrongCat[i])  {
-        CreateCopy ( WrongCat[i],pstr(" ") );
-        WrongCat[i][0] = char(1);
-      }
-      if (tags[i])  CreateCopy ( WrongTag[i],tags[i]  );
-              else  CreateCopy ( WrongTag[i],pstr("") );
-    }
-  }
-}
-
-Boolean CMMCIFData::CheckWrongField ( cpstr C, cpstr T )  {
-int i;
-  for (i=0;i<nWrongFields;i++)
-    if ((!strcasecmp(C,WrongCat[i])) &&
-        (!strcasecmp(T,WrongTag[i])))  return True;
-  return False;
-}
-
-#define _max_buf_len   500
-
-static char  _err_string[_max_buf_len+1];
-static int   _err_line;
-
-
-int  CMMCIFData::ReadMMCIFData ( cpstr FName, byte gzipMode )  {
-CFile f;
-char  S[_max_buf_len+1];
-int   RC,lcount;
-  f.assign ( FName,True,False,gzipMode );
-  if (f.reset(True))  {
-    S[0]   = char(0);
-    lcount = 0;
-    RC     = ReadMMCIFData ( f,S,lcount );
-    f.shut();
-    return RC;
-  } else  {
-    _err_string[0] = char(0);
-    _err_line      = 0;
-    Warning = CIFRC_CantOpenFile;
-    return CIFRC_CantOpenFile;
-  }
-}
-
-
-// ---------------  General I/O functions
-
-int  CMMCIFData::ReadMMCIFData ( RCFile f, pstr S, int & lcount )  {
-pstr p;
-int  i,llen;
-pstr L;
-
-  FreeMemory(1);
-  Warning = 0;
-  loopNo  = 0;
-  tagNo   = 0;
-
-  // 1. Look for 'data_' tag
-  do {
-    p = &(S[0]);
-    while ((*p==' ') || (*p==char(9)))  p++;
-    if (strncmp(p,"data_",5))  {
-      f.ReadLine ( S,_max_buf_len );
-      lcount++;
-      p = NULL;
-    }
-  } while ((!p) && (!f.FileEnd()));
-
-  if (!p)  {
-    strcpy ( _err_string,S );
-    _err_line = lcount;
-    if (flags & CIFFL_PrintWarnings)
-      printf ( "\n **** mmCIF READ ERROR "
-               "<<line %i: no 'data_XXXX' tag found>>\n",lcount );
-    return CIFRC_NoDataLine;
-  }
-
-  llen = _max_buf_len;
-  L    = new char[llen];
-  i    = 0;
-  p   += 5;
-  while ((*p) && (*p!=' ') && (*p!=char(9)))  {
-    L[i++] = *p;
-    p++;
-  }
-  L[i] = char(0);
-  CreateCopy ( name,L );
-
-
-  // 2. Loop over tags until next 'data_' or end of file
-
-  while (p)  {
-
-    // skip spaces
-    while ((*p==' ') || (*p==char(9)))  p++;
-
-    if ((*p) && (*p!='#'))  {  // this is not a comment, continue
-      if (*p=='_')
-        GetDataItem ( f,S,L,p,lcount,llen );
-      else if (!strncmp(p,"loop_",5))
-        GetLoop ( f,S,L,p,lcount,llen );
-      else if (!strncmp(p,"data_",5))  {
-        p = NULL;
-        break;
-      } else  {
-        // if got to here, the file is corrupted
-        strcpy ( _err_string,S );
-        _err_line = lcount;
-        Warning |= CIFW_UnrecognizedItems;
-        if (flags & CIFFL_PrintWarnings)
-          printf ( "\n **** mmCIF READ WARNING "
-                   "<<line %i: unrecognized string>>\n%s\n",
-                   lcount,S );
-        while ((*p) && (*p!=' ') && (*p!=char(9)))
-          if (*p=='#')  *p = char(0);
-                  else  p++;
-      }
-    } else
-      *p = char(0);
-
-    if (Warning && (flags & CIFFL_StopOnWarnings))  {
-      if (L)  delete[] L;
-      return Warning;
-    }
-
-    if (!(*p))  {
-      if (!f.FileEnd())  {
-        f.ReadLine ( S,_max_buf_len );
-        lcount++;
-        p = &(S[0]);
-      } else
-        p = NULL;
-    }
-
-  }
-
-  if (L)  delete[] L;
-
-  Optimize();  // get rid of over-allocated fields.
-
-  return Warning;
-
-}
-
-
-void CMMCIFData::GetDataItem ( RCFile f, pstr S, pstr & L,
-                               pstr & p, int & lcount, int & llen )  {
-PCMMCIFStruct Struct;
-char          T[100];
-int           RC,i;
-
-  i = 0;
-  while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.'))  {
-    if (i<(int)sizeof(T)-1)  T[i++] = *p;
-    p++;
-  }
-  T[i] = char(0);
-
-  if (*p!='.')  {    // category name missing
-    strcpy ( L,T );  // item name
-    T[0] = char(1);  // special
-    T[1] = char(0);  //   category name
-  }
-
-  //  look for category
-  i = AddCategory ( T );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Struct = new CMMCIFStruct ( T );
-    Category[nCategories-1] = Struct;
-  } else  {
-    Struct = PCMMCIFStruct(Category[i]);
-    if (Struct->GetCategoryID()!=MMCIF_Struct)  {
-      strcpy ( _err_string,S );
-      _err_line = lcount;
-      Warning |= CIFW_NotAStructure;
-      if (flags & CIFFL_PrintWarnings)
-        printf ( "\n **** mmCIF READ WARNING "
-                 "<<line %i: %s was a loop -- replaced>>\n%s\n",
-                 lcount,T,S );
-      delete Category[i];
-      Struct = new CMMCIFStruct ( T );
-      Category[i] = Struct;
-    }
-  }
-
-  if (*p=='.')  {  // get item name
-    i = 0;
-    p++;  // skip period
-    while ((*p) && (*p!=' ') && (*p!=char(9)))  {
-      T[i++] = *p;
-      p++;
-    }
-    T[i] = char(0);
-  } else
-    strcpy ( T,L );
-
-  if (nWrongFields>0)  {
-    if (CheckWrongField(Struct->name,T))  {
-      GetField ( f,S,L,p,lcount,llen );
-      Struct->DeleteField ( T );
-      return;
-    }
-  }
-
-  RC = GetField ( f,S,L,p,lcount,llen );
-
-  if (RC)  {
-    strcpy ( _err_string,S );
-    _err_line = lcount;
-    Warning |= CIFW_MissingField;
-    if (flags & CIFFL_PrintWarnings)
-      printf ( "\n **** mmCIF READ WARNING "
-               "<<line %i: expected data field missing>>\n%s\n",
-               lcount,S );
-  }
-
-  while ((*p==' ') || (*p==char(9)))  p++;
-  if (*p=='#')  *p = char(0);
-
-  i = Struct->GetTagNo ( T );
-  if (i>=0)  {
-    if (flags & CIFFL_SuggestTags)  {
-      tagNo++;
-      ParamStr ( T,pstr("\1"),tagNo );
-    } else  {
-      strcpy ( _err_string,S );
-      _err_line = lcount;
-      Warning |= CIFW_DuplicateTag;
-      if (flags & CIFFL_PrintWarnings)
-        printf ( "\n **** mmCIF READ WARNING "
-                 "<<line %i: duplicated tag>>\n%s\n",lcount,S );
-    }
-  }
-  Struct->AddField ( L,T );
-
-}
-
-void CMMCIFData::GetLoop ( RCFile f, pstr S, pstr & L,
-                           pstr & p, int & lcount, int & llen )  {
-PCMMCIFLoop Loop;
-pstr        p1;
-char        T[100];
-Boolean     Repeat,WrongField;
-int         RC,i,nC;
-
-  RC = 0;
-
-  p += 5;  // skip 'loop_' tag
-
-  loopNo++;
-  Loop = NULL;
-  nC   = -1; // undefined category number
-  do {
-
-    while ((*p==' ') || (*p==char(9)))  p++;
-    p1 = p;
-
-    if (*p=='_')  {
-
-      // get category name
-      i = 0;
-      while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.'))  {
-        if (i<(int)sizeof(T)-1)  T[i++] = *p;
-        p++;
-      }
-      T[i] = char(0);
-
-      if (*p!='.')  {    // category name missing
-        strcpy ( L,T );  // item name
-        if (flags & CIFFL_SuggestCategories)
-             sprintf ( T,"X%i",loopNo );
-        else strcpy  ( T,"X" );
-        T[0] = char(1);  // special category name
-      }
-
-      if (Loop)  {
-        if (strcmp(Loop->GetCategoryName(),T))  {
-          // loop ended, empty
-          p    = p1;   // play back to last category
-          Loop = NULL;
-        }
-      } else  {
-        //  look for category
-        i = AddCategory ( T );
-        if ((i!=nC) && (nC>=0))  {  // empty loop; most probably
-                                    // a corrupted file
-          p = p1;   // play back to last category
-          strcpy ( _err_string,S );
-          _err_line = lcount;
-          Warning |= CIFW_EmptyLoop;
-          if (flags & CIFFL_PrintWarnings)
-            printf ( "\n **** mmCIF READ WARNING "
-                     "<<line %i: empty loop>>\n%s\n",lcount,S );
-          // AddCategory(..) has added a NULL-Category on the top of
-          // category list; remove it now
-          DeleteCategory ( nCategories-1 );
-          Loop = NULL;
-//          return;
-        }
-        if (i<0)  {
-          // negative value means that the category was not in the list,
-          // but a place for it has been provided and index updated
-          Loop = new CMMCIFLoop ( T );
-          Category[nCategories-1] = Loop;
-          nC = nCategories-1;
-        }
-      }
-/*
- else if (Loop)  {
-        if (!strcmp(Loop->GetCategoryName(),
-                    Category[i]->GetCategoryName()))  {
-          if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-            Warning |= CIFW_NotALoop;
-            if (flags & CIFFL_PrintWarnings)
-              printf ( "\n **** mmCIF READ WARNING "
-                       "<<line %i: %s was a structure --"
-                       " replaced>>\n%s\n",lcount,T,S );
-            delete Category[i];
-            Loop = new CMMCIFLoop ( T );
-            Category[i] = Loop;
-          }
-        } else
-          Loop = NULL;
-      }
-*/
-      if (Loop)  {
-
-        if (*p=='.')  {  // get item name
-          i = 0;
-          p++;  // skip period
-          while ((*p) && (*p!=' ') && (*p!=char(9)))  {
-            T[i++] = *p;
-            p++;
-          }
-          T[i] = char(0);
-        } else
-          strcpy ( T,L );
-
-        if (nWrongFields>0)
-              WrongField = CheckWrongField ( Loop->name,T );
-        else  WrongField = False;
-
-        if (!WrongField)  {
-          if (Loop->AddTag(T)>=0)  {
-            if (flags & CIFFL_SuggestTags)  {
-              tagNo++;
-              ParamStr ( T,pstr("\1"),tagNo );
-              Loop->AddTag(T);
-            } else  {
-              strcpy ( _err_string,S );
-              _err_line = lcount;
-              Warning |= CIFW_DuplicateTag;
-              if (flags & CIFFL_PrintWarnings)
-                printf ( "\n **** mmCIF READ WARNING "
-                         "<<line %i: duplicate tag>>\n%s\n",lcount,S );
-            }
-          }
-        }
-        Repeat = True;
-
-      } else  {
-
-        p = p1;
-        Repeat = False;
-
-      }
-
-    } else if (!(*p) || (*p=='#'))  {
-      Repeat = !f.FileEnd();
-      if (Repeat)  {
-        f.ReadLine ( S,_max_buf_len );
-        lcount++;
-        p = &(S[0]);
-      } else  {
-        strcpy ( _err_string,S );
-        _err_line = lcount;
-        Warning |= CIFW_UnexpectedEOF;
-        if (flags & CIFFL_PrintWarnings)
-          printf ( "\n **** mmCIF READ WARNING "
-                   "<<line %i: unexpected end of file>>\n%s\n",
-                   lcount,S );
-      }
-    } else
-      Repeat = False;
-
-  } while (Repeat);
-
-  if (Loop)  {
-    do  {
-      while ((*p==' ') || (*p==char(9)))  p++;
-      if (!(*p) || (*p=='#'))  {
-        Repeat = !f.FileEnd();
-        if (Repeat)  {
-          f.ReadLine ( S,_max_buf_len );
-          lcount++;
-          p = &(S[0]);
-        }
-      } else if (*p=='_')  Repeat = False;
-      else if (!strncmp(p,"loop_",5))  Repeat = False;
-      else if (!strncmp(p,"data_",5))  Repeat = False;
-      else if (!strncmp(p,"stop_",5))  {
-        p += 5;
-        Repeat = False;
-      } else  {
-        RC = GetField ( f,S,L,p,lcount,llen );
-        if (!RC)  {
-          Loop->AddString ( L );
-          Repeat = True;
-        } else
-          Repeat = False;
-      }
-    } while (Repeat);
-    if ((Loop->iColumn!=0) || (RC))  {
-      strcpy ( _err_string,S );
-      _err_line = lcount;
-      Warning |= CIFW_LoopFieldMissing;
-      if (flags & CIFFL_PrintWarnings)
-        printf ( "\n **** mmCIF READ WARNING "
-                 "<<line %i: expected loop field missing>>\n%s\n",
-                 lcount,S );
-    }
-  }
-
-}
-
-int  CMMCIFData::GetField ( RCFile f, pstr S, pstr & L,
-                            pstr & p, int & lcount, int & llen )  {
-Boolean Repeat;
-pstr    L1;
-int     i,flen;
-char    c;
-
-  flen    = 0;
-  L[flen] = char(0);
-
-  do {
-
-    // skip all spaces before the field
-    while ((*p==' ') || (*p==char(9)))  p++;
-
-    if ((*p=='#') || (!(*p)))  {
-      // comment or end of line met;  the field should be
-      // found on the next line
-      Repeat = !f.FileEnd();
-      if (Repeat)  {
-        // take the next line
-        f.ReadLine ( S,_max_buf_len );
-        lcount++;
-        p = &(S[0]);
-        Repeat = (*p!=';');
-      } else  {
-        // end of file and the field is not taken
-        L[0] = char(0);
-        return 1;
-      }
-    } else
-      // first symbol of a field is found
-      Repeat = False;
-
-  } while (Repeat);
-
-
-  if (*p==';')  {      // this is a multiline field
-    p++;
-    strcpy ( L,p );    // take first line of the field
-    flen = strlen(L);
-    while (!f.FileEnd())  {
-      f.ReadLine ( S,_max_buf_len );
-      lcount++;
-      p = &(S[0]);
-      if (*p==';')  {  // multiline field terminated
-        p++;
-        while ((*p==' ') || (*p==char(9)))  p++;
-        return 0;
-      } else  {        // multiline field continues -- take next line
-        flen += strlen(S)+2;
-        if (flen>=llen)  {
-          llen = flen + IMin(2000,llen);
-          L1   = new char[llen];
-          strcpy ( L1,L );
-          delete[] L;
-          L = L1;
-        }
-        strcat ( L,"\n" );
-        strcat ( L,S );
-      }
-    }
-
-    // end of file -- take the last line of the multiline field
-    p = &(S[strlen(S)]);
-
-  } else  {
-
-    i = 0;
-    if (*p!='_')  {
-      if ((*p=='\'') || (*p=='"'))  {
-        c = *p;
-        // field in quotation marks
-        do  {
-          p++;
-          // stop taking characters either on end of line
-          // or the quotation mark
-          while ((*p) && (*p!=c))  {
-            L[i++] = *p;
-            p++;
-          }
-          while (*p==c)  {
-            // it was a quotation mark -- check that it is followed
-            // by end of line or space
-            p++;
-            if ((*p) && (*p!=' ') && (*p!=char(9)))  {
-              // the quotation mark is not a field terminator and
-              // belongs to the field.
-              L[i++] = c;    // take the quotation mark
-              if (*p!=c)     // take the non-space character
-                L[i++] = *p; // but check for field terminator
-            }
-          }
-          // terminate the loop only on space or end of line
-        } while ((*p) && (*p!=' ') && (*p!=char(9)));
-        if (*p)  p++;
-        L[i] = char(0);
-      } else  {
-        // a simplest field without spaces
-        while ((*p) && (*p!=' ') && (*p!=char(9)))  {
-          L[i++] = *p;
-          p++;
-        }
-        L[i] = char(0);
-        if (((L[0]=='.') || (L[0]=='?')) && (!L[1]))  {
-          //  "no data" tokens
-          L[1] = L[0];
-          L[0] = char(2);
-          L[2] = char(0);
-        }
-      }
-    }
-
-  }
-
-  return 0;
-
-}
-
-void  CMMCIFData::Sort()  {
-int      i,k;
-psvector cnames;
-
-  k = 0;
-  for (i=0;i<nCategories;i++)
-    if (Category[i])  {
-      if (k<i)  Category[k] = Category[i];
-      k++;
-    }
-  for (i=k;i<nCategories;i++)
-    Category[i] = NULL;
-  nCategories = k;
-
-  FreeVectorMemory ( index ,0 );
-  GetVectorMemory  ( cnames,nCategories,0 );
-  GetVectorMemory  ( index ,nCategories,0 );
-
-  for (i=0;i<nCategories;i++)  {
-    Category[i]->Sort();
-    cnames[i] = NULL;
-    CreateCopy ( cnames[i],Category[i]->name );
-  }
-
-  SortTags ( cnames,nCategories,index );
-
-  for (i=0;i<nCategories;i++)
-    if (cnames[i])  delete[] cnames[i];
-
-  if (cnames) delete[] cnames;
-
-}
-
-int  CMMCIFData::GetCategoryNo ( cpstr cname )  {
-//   Binary search for index of category cname in Category[].
-// Return:
-//    >=0 : position of the category found
-//     <0 : the category was not found, it could be inserted before
-//          (-RC-1)th element, where RC is the return value
-int l1,l2,l,k;
-
-  if (!Category) return -1;
-
-  if (!index)    Sort();
-
-  if (cname[0])  {
-    l  = 0;
-    l1 = 0;
-    l2 = nCategories-1;
-    k  = 1;
-    while (l1<l2-1)  {
-      l = (l1+l2)/2;
-      k = strcasecmp ( cname,Category[index[l]]->name );
-      if (k<0)      l2 = l;
-      else if (k>0) l1 = l;
-      else  {
-        l1 = l;
-        break;
-      }
-    }
-    if (k==0)  return index[l];    // is at RCth position
-    k = strcasecmp(cname,Category[index[l1]]->name);
-    if (k==0)  return index[l1];   // is at RCth position
-    if (k<0)   return -1;          // would be at (-RC-1)th position
-    if (l2!=l1)  {
-      k = strcasecmp(cname,Category[index[l2]]->name);
-      if (k==0)  return index[l2]; // is at RCth position
-      if (k>0)   return -2-l2;   // would be at l2+1=(-RC-1)th position
-    }
-    return -2-l1;                // would be at l1+1=(-RC-1)th position
-  } else
-    // 'root' category should be always on top
-    if (Category[index[0]]->name[0]==char(1))  return index[0];
-
-  return -1;
-
-}
-
-int  CMMCIFData::AddCategory ( cpstr cname )  {
-//  return -1: a place for category has been added on the top of array;
-//             index is added and sorted automatically
-//        >=0: the category is already in the array -- its position
-//             is returned
-int              l1,l;
-PPCMMCIFCategory Category1;
-ivector          index1;
-
-
-  if (!Category)  {
-    Category     = new PCMMCIFCategory[1];
-    Category[0]  = NULL;
-    GetVectorMemory ( index,1,0 );
-    index[0]     = 0;
-    nCategories  = 1;
-    return -nCategories;  // the category has been added on the top of array
-  }
-  l1 = GetCategoryNo ( cname );
-  if (l1>=0)  return l1;  // non-negative returns mean that
-                          // the category is already in the array
-  l1 = -l1-1;  // otherwise the category has to be added and indexed at here
-  // put new NULL-category on the top of array and update the index
-  Category1 = new PCMMCIFCategory[nCategories+1];
-  GetVectorMemory ( index1,nCategories+1,0 );
-  for (l=0;l<nCategories;l++)
-    Category1[l] = Category[l];
-  Category1[nCategories] = NULL;
-  for (l=0;l<l1;l++)
-    index1[l] = index[l];
-  index1[l1] = nCategories;
-  for (l=l1+1;l<=nCategories;l++)
-    index1[l] = index[l-1];
-  delete[] Category;
-  FreeVectorMemory ( index,0 );
-  Category = Category1;
-  index    = index1;
-  nCategories++;
-  return -nCategories; // the category has been added on
-                       // the top of array
-}
-
-Boolean CMMCIFData::WriteMMCIFData ( cpstr FName, byte gzipMode )  {
-CFile f;
-  f.assign ( FName,True,False,gzipMode );
-  if (f.rewrite())  {
-    WriteMMCIF ( f );
-    f.shut();
-    return True;
-  } else
-    return False;
-}
-
-void CMMCIFData::WriteMMCIF ( RCFile f )  {
-int  i;
-
-  if (name)  {
-    f.Write     ( pstr("\ndata_") );
-    f.WriteLine ( name            );
-  } else
-    f.WriteLine ( pstr("\ndata_") );
-
-  for (i=0;i<nCategories;i++)
-    if (Category[i])
-      Category[i]->WriteMMCIF ( f );
-
-}
-
-
-// ---------------  Retrieving data
-
-int  CMMCIFData::DeleteCategory ( cpstr CName )  {
-int k;
-  k = GetCategoryNo ( CName );
-  if (k<0)  return CIFRC_NoCategory;
-  return DeleteCategory ( k );
-}
-
-int  CMMCIFData::DeleteCategory ( int CatNo ) {
-int i;
-  if (Category[CatNo])  delete Category[CatNo];
-  for (i=CatNo+1;i<nCategories;i++)
-    Category[i-1] = Category[i];
-  i = 0;
-  while ((i<nCategories) && (index[i]!=CatNo))  {
-    if (index[i]>CatNo) index[i]--;
-    i++;
-  }
-  i++;
-  while (i<nCategories)  {
-    if (index[i]>CatNo) index[i]--;
-    index[i-1] = index[i];
-    i++;
-  }
-  nCategories--;
-  index   [nCategories] = 0;
-  Category[nCategories] = NULL;
-  return 0;
-}
-
-int  CMMCIFData::DeleteStructure ( cpstr CName )  {
-int k;
-  k = GetCategoryNo ( CName );
-  if (k<0)  return CIFRC_NoCategory;
-  if (Category[k]->GetCategoryID()==MMCIF_Struct)
-        return DeleteCategory ( k );
-  else  return CIFRC_NotAStructure;
-}
-
-int  CMMCIFData::DeleteLoop ( cpstr CName )  {
-int k;
-  k = GetCategoryNo ( CName );
-  if (k<0)  return CIFRC_NoCategory;
-  if (Category[k]->GetCategoryID()==MMCIF_Loop)
-        return DeleteCategory ( k );
-  else  return CIFRC_NotALoop;
-}
-
-PCMMCIFCategory CMMCIFData::GetCategory ( int categoryNo )  {
-  if ((categoryNo>=0) && (categoryNo<nCategories))
-    return Category[categoryNo];
-  return NULL;
-}
-
-PCMMCIFStruct CMMCIFData::GetStructure ( cpstr CName )  {
-int i;
-  i = GetCategoryNo ( CName );
-  if (i<0)  return NULL;
-  if (Category[i]->GetCategoryID()==MMCIF_Struct)
-        return PCMMCIFStruct(Category[i]);
-  else  return NULL;
-}
-
-PCMMCIFLoop CMMCIFData::GetLoop ( cpstr CName )  {
-int i;
-  i = GetCategoryNo ( CName );
-  if (i<0)  return NULL;
-  if (Category[i]->GetCategoryID()==MMCIF_Loop)
-        return PCMMCIFLoop(Category[i]);
-  else  return NULL;
-}
-
-PCMMCIFLoop CMMCIFData::FindLoop ( cpstr * tagList )  {
-int i;
-  for (i=0;i<nCategories;i++)
-    if (Category[i])  {
-      if (Category[i]->GetCategoryID()==MMCIF_Loop)  {
-        if (Category[i]->CheckTags(tagList))
-          return PCMMCIFLoop(Category[i]);
-      }
-    }
-  return NULL;
-}
-
-void CMMCIFData::GetDataName ( pstr & dname, Boolean Remove )  {
-  if (Remove)  {
-    if (dname)  delete[] dname;
-    dname = name;
-    name  = NULL;
-  } else
-    CreateCopy ( dname,name );
-}
-
-int  CMMCIFData::CheckData ( cpstr CName, cpstr TName )  {
-//   CheckData(..) returns positive value if the field is in the
-// file:
-//   CIFRC_Structure  category CName is a structure
-//   CIFRC_Loop       category CName is a loop
-// Negative returns mean:
-//   CIFRC_StructureNoTag  category CName is present,
-//                        it is a structure, but it does not
-//                        have tag TName
-//   CIFRC_LoopNoTag       category CName is present,
-//                        it is a loop, but it does not have
-//                        tag TName
-//   CIFRC_NoCategory      category CName is not present.
-// If TName is set to NULL then only the CName is checked and
-// possible returns are CIFRC_Structure, CIFRC_Loop and
-// CIFRC_NoCategory.
-int i,k;
-  i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()==MMCIF_Struct)
-        k = CIFRC_Structure;
-  else  k = CIFRC_Loop;
-  if (TName)  {
-    if (Category[i]->GetTagNo(TName)<0)  {
-      if (k==CIFRC_Structure)
-            k = CIFRC_StructureNoTag;
-      else  k = CIFRC_LoopNoTag;
-    }
-  }
-  return k;
-}
-
-void CMMCIFData::Optimize()  {
-int              i,k;
-PPCMMCIFCategory C1;
-  k = 0;
-  for (i=0;i<nCategories;i++)
-    if (Category[i])  {
-      Category[i]->Optimize();
-      if (Category[i]->nTags<=0)  {
-        delete Category[i];
-        Category[i] = NULL;
-      } else
-        k++;
-    }
-  if (k>0)  {
-    if (k!=nCategories)  {
-      C1 = new PCMMCIFCategory[k];
-      k  = 0;
-      for (i=0;i<nCategories;i++)
-        if (Category[i])
-          C1[k++] = Category[i];
-      if (Category) delete[] Category;
-      Category    = C1;
-      nCategories = k;
-      FreeVectorMemory ( index,0 );
-      Sort();
-    }
-  } else  {
-    if (Category)  delete[] Category;
-    Category    = NULL;
-    nCategories = 0;
-  }
-}
-
-int  CMMCIFData::GetString  ( pstr & Dest, cpstr CName,
-                              cpstr TName, Boolean Remove )  {
-//   GetString(..), GetReal(..) and GetInteger(..) return 0 if the
-// requested field was found and successfully converted. Negative
-// returns mean:
-//    CIFRC_WrongFormat    the field was found but failed to convert
-//                        due to improper numeric format
-//    CIFRC_NoTag          category CName was found, but it does not
-//                        have tag TName
-//    CIFRC_NoCategory     category CName was not found
-//    CIFRC_NotAStructure  category CName was found, but it is a loop
-//                        rather than a structure.
-//   GetString(..) will try to dispose Dest unless it is assugned
-// NULL value before the call. The string will be then dynamically
-// allocated and copied.
-int i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Struct)
-            return CIFRC_NotAStructure;
-  return PCMMCIFStruct(Category[i])->GetString ( Dest,TName,Remove );
-}
-
-pstr CMMCIFData::GetString ( cpstr CName, cpstr TName, int & RC )  {
-int i = GetCategoryNo ( CName );
-  if (i<0)  {
-    RC = CIFRC_NoCategory;
-    return NULL;
-  }
-  if (Category[i]->GetCategoryID()!=MMCIF_Struct)  {
-    RC = CIFRC_NotAStructure;
-    return NULL;
-  }
-  return PCMMCIFStruct(Category[i])->GetString ( TName,RC );
-}
-
-int  CMMCIFData::DeleteField ( cpstr CName, cpstr TName )  {
-int i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Struct)
-            return CIFRC_NotAStructure;
-  return PCMMCIFStruct(Category[i])->DeleteField ( TName );
-}
-
-int  CMMCIFData::GetReal ( realtype & R, cpstr CName,
-                           cpstr TName, Boolean Remove )  {
-int i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Struct)
-            return CIFRC_NotAStructure;
-  return PCMMCIFStruct(Category[i])->GetReal ( R,TName,Remove );
-}
-
-int  CMMCIFData::GetInteger ( int & I, cpstr CName,
-                              cpstr TName, Boolean Remove )  {
-int j = GetCategoryNo ( CName );
-  if (j<0)  return CIFRC_NoCategory;
-  if (Category[j]->GetCategoryID()!=MMCIF_Struct)
-            return CIFRC_NotAStructure;
-  return PCMMCIFStruct(Category[j])->GetInteger ( I,TName,Remove );
-}
-
-int  CMMCIFData::GetLoopLength ( cpstr CName )  {
-//   GetLoopLength(..) returns CIFRC_NotALoop if the category CName
-// is not a loop, CIFRC_NoCategory if the category CName is not
-// found. Non-negative returns give the length of the loop (may be
-// 0 if the loop is empty).
-int i;
-  i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)
-            return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[i])->nRows;
-}
-
-int  CMMCIFData::GetLoopString  ( pstr & Dest, cpstr CName,
-                                  cpstr TName, int nrow,
-                                  Boolean Remove )  {
-//   GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act
-// like GetString(..), GetReal(..) and GetInteger(..) above for
-// nrow-th element of the 'loop_' (indexed like 0..N-1 where N
-// is obtained through GetLoopLength(..)). They will return
-// CIFRC_WrongIndex if nrow is out of range.
-int i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)
-            return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[i])->GetString ( Dest,TName,nrow,Remove );
-}
-
-pstr CMMCIFData::GetLoopString  ( cpstr CName, cpstr TName,
-                                  int nrow, int & RC )  {
-int i = GetCategoryNo ( CName );
-  if (i<0)  {
-    RC = CIFRC_NoCategory;
-    return NULL;
-  }
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)  {
-    RC = CIFRC_NotALoop;
-    return NULL;
-  }
-  return  PCMMCIFLoop(Category[i])->GetString ( TName,nrow,RC );
-}
-
-int CMMCIFData::DeleteLoopField ( cpstr CName, cpstr TName,
-                                  int nrow )  {
-int i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)
-            return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[i])->DeleteField ( TName,nrow );
-}
-
-int  CMMCIFData::GetLoopReal ( realtype & R, cpstr CName,
-                               cpstr TName, int nrow,
-                               Boolean Remove )  {
-int i = GetCategoryNo ( CName );
-  if (i<0)  return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)
-            return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[i])->GetReal ( R,TName,nrow,Remove );
-}
-
-int  CMMCIFData::GetLoopInteger ( int & I, cpstr CName,
-                                  cpstr TName, int nrow,
-                                  Boolean Remove )  {
-int j = GetCategoryNo ( CName );
-  if (j<0)  return CIFRC_NoCategory;
-  if (Category[j]->GetCategoryID()!=MMCIF_Loop)
-            return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[j])->GetInteger ( I,TName,nrow,Remove );
-}
-
-
-int  CMMCIFData::GetLoopSVector ( psvector & S, cpstr CName,
-                                  cpstr TName, int i1, int i2,
-                                  Boolean Remove )  {
-//   GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..)
-// read CIF 'loop_' data into allocated vectors of strings, reals and
-// integers, correspondingly. The vectors may be deallocated prior
-// to call and assigned NULL, in which case they will be allocated
-// with offsets of i1, which is also the lower index of the 'loop_'
-// data transferred into it. The upper vector index is given by i2 or
-// by the loop's length whichever is less. If vectors are not assigned
-// NULL prior the call, it is assumed that they are properly (i1-offset,
-// i2-i1+1 length) allocated.
-//   The return codes are same as those of GetLoopString(..),
-// GetLoopReal(..) and GetLoopInteger(..).
-int i;
-  i = GetCategoryNo ( CName );
-  if (i<0)    return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)
-              return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[i])->GetSVector ( S,TName,i1,i2,Remove );
-}
-
-int  CMMCIFData::GetLoopRVector ( rvector & R, cpstr CName,
-                                  cpstr TName, int i1, int i2,
-                                  Boolean Remove )  {
-int i;
-  i = GetCategoryNo ( CName );
-  if (i<0)    return CIFRC_NoCategory;
-  if (Category[i]->GetCategoryID()!=MMCIF_Loop)
-              return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[i])->GetRVector ( R,TName,i1,i2,Remove );
-}
-
-int  CMMCIFData::GetLoopIVector ( ivector & I, cpstr CName,
-                                  cpstr TName, int i1, int i2,
-                                  Boolean Remove )  {
-int j;
-  j = GetCategoryNo ( CName );
-  if (j<0)    return CIFRC_NoCategory;
-  if (Category[j]->GetCategoryID()!=MMCIF_Loop)
-              return CIFRC_NotALoop;
-  return PCMMCIFLoop(Category[j])->GetIVector ( I,TName,i1,i2,Remove );
-}
-
-
-// ---------------  Storing data
-
-void  CMMCIFData::PutDataName ( cpstr dname )  {
-// stores name for 'data_' record
-  CreateCopy ( name,dname );
-}
-
-int  CMMCIFData::PutNoData ( int NoDataType, cpstr CName,
-                             cpstr TName )  {
-PCMMCIFStruct Struct;
-int           i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Struct = new CMMCIFStruct ( CName );
-    Category[nCategories-1] = Struct;
-  } else  {
-    Struct = PCMMCIFStruct(Category[i]);
-    if (Struct->GetCategoryID()!=MMCIF_Struct)  {
-      RC = CIFRC_NotAStructure;
-      delete Category[i];
-      Struct = new CMMCIFStruct ( CName );
-      Category[i] = Struct;
-    }
-  }
-
-  Struct->PutNoData ( NoDataType,TName );
-
-  return RC;
-
-}
-
-int  CMMCIFData::PutString ( cpstr S, cpstr CName,
-                             cpstr TName, Boolean Concatenate )  {
-//   PutString(..), PutReal(..) and PutInteger(..) will put the
-// values given into the specified category (CName) under the
-// specified tag (TName). The category, tag and field are created
-// automatically; the field will be replaced silently if identical
-// CName.TName is specified in two calls. Calls of these functions
-// may follow in random order; however CIF file will have all tags
-// grouped by categories and catgories will follow in the order
-// of first appearance in PutString(..), PutReal(..) or
-// PutInteger(..).
-//   Return code - one of CIFRC_Ok or CIFRC_NotAStruct
-PCMMCIFStruct Struct;
-int           i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Struct = new CMMCIFStruct ( CName );
-    Category[nCategories-1] = Struct;
-  } else  {
-    Struct = PCMMCIFStruct(Category[i]);
-    if (Struct->GetCategoryID()!=MMCIF_Struct)  {
-      RC = CIFRC_NotAStructure;
-      delete Category[i];
-      Struct = new CMMCIFStruct ( CName );
-      Category[i] = Struct;
-    }
-  }
-
-  Struct->AddField ( S,TName,Concatenate );
-
-  return RC;
-
-}
-
-int   CMMCIFData::PutDate ( cpstr CName, cpstr TName )  {
-PCMMCIFStruct Struct;
-int           i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Struct = new CMMCIFStruct ( CName );
-    Category[nCategories-1] = Struct;
-  } else  {
-    Struct = PCMMCIFStruct(Category[i]);
-    if (Struct->GetCategoryID()!=MMCIF_Struct)  {
-      RC = CIFRC_NotAStructure;
-      delete Category[i];
-      Struct = new CMMCIFStruct ( CName );
-      Category[i] = Struct;
-    }
-  }
-
-  Struct->PutDate ( TName );
-
-  return RC;
-
-}
-
-int  CMMCIFData::PutReal ( realtype R, cpstr CName,
-                           cpstr TName, int prec )  {
-char rS[100];
-  sprintf ( rS,"%.*g",prec,R );
-  return PutString ( rS,CName,TName,False );
-}
-
-int  CMMCIFData::PutInteger ( int I, cpstr CName,
-                                     cpstr TName )  {
-char iS[100];
-  if (I>MinInt4)  sprintf ( iS,"%i",I );
-  else  {
-    iS[0] = char(2);
-    iS[1] = '.';
-    iS[2] = char(0);
-  }
-  return PutString ( iS,CName,TName,False );
-}
-
-
-int  CMMCIFData::AddLoop ( cpstr CName, PCMMCIFLoop & Loop )  {
-int  i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Loop = new CMMCIFLoop ( CName );
-    Category[nCategories-1] = Loop;
-    RC = CIFRC_Created;
-  } else  {
-    Loop = PCMMCIFLoop(Category[i]);
-    if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-      RC = CIFRC_NotALoop;
-      delete Category[i];
-      Loop = new CMMCIFLoop ( CName );
-      Category[i] = Loop;
-    }
-  }
-
-  return RC;
-
-}
-
-int  CMMCIFData::AddStructure ( cpstr CName,
-                                PCMMCIFStruct & Struct )  {
-int  i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Struct = new CMMCIFStruct ( CName );
-    Category[nCategories-1] = Struct;
-    RC = CIFRC_Created;
-  } else  {
-    Struct = PCMMCIFStruct(Category[i]);
-    if (Struct->GetCategoryID()!=MMCIF_Struct)  {
-      RC = CIFRC_NotAStructure;
-      delete Category[i];
-      Struct = new CMMCIFStruct ( CName );
-      Category[i] = Struct;
-    }
-  }
-
-  return RC;
-
-}
-
-
-int  CMMCIFData::PutLoopNoData ( int NoDataType, cpstr CName,
-                                 cpstr TName, int nrow )  {
-PCMMCIFLoop Loop;
-int         i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Loop = new CMMCIFLoop ( CName );
-    Category[nCategories-1] = Loop;
-  } else  {
-    Loop = PCMMCIFLoop(Category[i]);
-    if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-      RC = CIFRC_NotALoop;
-      delete Category[i];
-      Loop = new CMMCIFLoop ( CName );
-      Category[i] = Loop;
-    }
-  }
-
-  Loop->PutNoData ( NoDataType,TName,nrow );
-
-  return RC;
-
-}
-
-
-int  CMMCIFData::PutLoopString ( cpstr S, cpstr CName,
-                                 cpstr TName, int nrow )  {
-//   PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act
-// like PutString(..), PutReal(..) and PutInteger(..) above for
-// nrow-th element of the 'loop_' CName (indexed begining from 0).
-// In consequitive calls, given values of nrow does not have to be
-// ordered; the most efficient way is to start with HIGHEST value
-// for nrow in the loop and move down to 0. The least efficient way
-// is to start with nrow=0 and move up.
-PCMMCIFLoop Loop;
-int         i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Loop = new CMMCIFLoop ( CName );
-    Category[nCategories-1] = Loop;
-  } else  {
-    Loop = PCMMCIFLoop(Category[i]);
-    if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-      RC = CIFRC_NotALoop;
-      delete Category[i];
-      Loop = new CMMCIFLoop ( CName );
-      Category[i] = Loop;
-    }
-  }
-
-  Loop->PutString ( S,TName,nrow );
-
-  return RC;
-
-}
-
-int  CMMCIFData::PutLoopReal ( realtype R, cpstr CName,
-                               cpstr TName, int nrow, int prec )  {
-char rS[100];
-  sprintf ( rS,"%.*g",prec,R );
-  return PutLoopString ( rS,CName,TName,nrow );
-}
-
-int  CMMCIFData::PutLoopInteger ( int I, cpstr CName,
-                                  cpstr TName, int nrow )  {
-char iS[100];
-  sprintf ( iS,"%i",I );
-  return PutLoopString ( iS,CName,TName,nrow );
-}
-
-
-int  CMMCIFData::PutLoopSVector ( psvector S, cpstr CName,
-                                  cpstr TName, int i1, int i2 )  {
-//   PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..)
-// put vectors of values into specified loop fields. Parameters i1
-// and i2 give the range of indices of values which are to be
-// transfered. To transfer an entire vector allocated as [0..N-1]
-// i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is
-// always indexed as starting form 0 on, therefore negative i1 and
-// i2 are not allowed, and specifying i1>0 will leave first i1
-// elements of the CIF loop for the corresponding tag undefined
-// (will be output like '?').
-PCMMCIFLoop Loop;
-int         i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Loop = new CMMCIFLoop ( CName );
-    Category[nCategories-1] = Loop;
-  } else  {
-    Loop = PCMMCIFLoop(Category[i]);
-    if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-      RC = CIFRC_NotALoop;
-      delete Category[i];
-      Loop = new CMMCIFLoop ( CName );
-      Category[i] = Loop;
-    }
-  }
-
-  Loop->PutSVector ( S,TName,i1,i2 );
-
-  return RC;
-
-}
-
-int  CMMCIFData::PutLoopRVector ( rvector R, cpstr CName,
-                                  cpstr TName,
-                                  int i1, int i2, int prec )  {
-PCMMCIFLoop Loop;
-int         i,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  i = AddCategory ( CName );
-  if (i<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Loop = new CMMCIFLoop ( CName );
-    Category[nCategories-1] = Loop;
-  } else  {
-    Loop = PCMMCIFLoop(Category[i]);
-    if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-      RC = CIFRC_NotALoop;
-      delete Category[i];
-      Loop = new CMMCIFLoop ( CName );
-      Category[i] = Loop;
-    }
-  }
-
-  Loop->PutRVector ( R,TName,i1,i2,prec );
-
-  return RC;
-
-}
-
-int  CMMCIFData::PutLoopIVector ( ivector I, cpstr CName,
-                                  cpstr TName,
-                                  int i1, int i2 )  {
-PCMMCIFLoop Loop;
-int         j,RC;
-
-  RC = CIFRC_Ok;
-
-  //  look for category
-  j = AddCategory ( CName );
-  if (j<0)  {
-    // negative value means that the category was not in the list,
-    // but a place for it has been provided and index updated
-    Loop = new CMMCIFLoop ( CName );
-    Category[nCategories-1] = Loop;
-  } else  {
-    Loop = PCMMCIFLoop(Category[j]);
-    if (Loop->GetCategoryID()!=MMCIF_Loop)  {
-      RC = CIFRC_NotALoop;
-      delete Category[j];
-      Loop = new CMMCIFLoop ( CName );
-      Category[j] = Loop;
-    }
-  }
-
-  Loop->PutIVector ( I,TName,i1,i2 );
-
-  return RC;
-
-}
-
-
-int CMMCIFData::RenameCategory ( cpstr CName,
-                                 cpstr newCName )  {
-int i,RC;
-  i = GetCategoryNo ( CName );
-  if (i>=0)  {
-    Category[i]->PutCategoryName ( newCName );
-    Sort();
-    RC = CIFRC_Ok;
-  } else
-    RC = CIFRC_NoCategory;
-  return RC;
-}
-
-
-void CMMCIFData::Copy ( PCMMCIFData Data )  {
-int i;
-  FreeMemory(0);
-  CreateCopy ( name,Data->name );
-  nCategories = Data->nCategories;
-  if (nCategories>0)  {
-    Category = new PCMMCIFCategory[nCategories];
-    GetVectorMemory ( index,nCategories,0 );
-    for (i=0;i<nCategories;i++)  {
-      if (Data->Category[i])  {
-        if (Data->Category[i]->GetCategoryID()==MMCIF_Struct)
-              Category[i] = new CMMCIFStruct();
-        else  Category[i] = new CMMCIFLoop();
-        Category[i]->Copy ( Data->Category[i] );
-      } else
-        Category[i] = NULL;
-      index[i] = Data->index[i];
-    }
-  }
-  flags   = Data->flags;
-  Warning = Data->Warning;
-}
-
-
-int  CMMCIFData::CopyCategory ( PCMMCIFData Data, cpstr CName,
-                                cpstr newCName )  {
-PCMMCIFCategory Cat;
-int             i,di,dc,RC;
-
-  di = Data->GetCategoryNo ( CName );
-
-  if (di>=0)  {
-
-    RC = CIFRC_Ok;
-    dc = Data->Category[di]->GetCategoryID();
-
-    //  look for category
-    i = AddCategory ( CName );
-    if (i<0)  {
-      // negative value means that the category was not in the list,
-      // but a place for it has been provided and index updated
-      if (dc==MMCIF_Loop)  Cat = new CMMCIFLoop   ( CName );
-                     else  Cat = new CMMCIFStruct ( CName );
-      Category[nCategories-1] = Cat;
-    } else  {
-      Cat = Category[i];
-      if (Cat->GetCategoryID()!=dc)  {
-        RC = CIFRC_NotAStructure;
-        delete Category[i];
-        if (dc==MMCIF_Loop)  Cat = new CMMCIFLoop   ( CName );
-                       else  Cat = new CMMCIFStruct ( CName );
-        Category[i] = Cat;
-      }
-    }
-
-    Cat->Copy ( Data->Category[di] );
-    if (newCName)  {
-      Cat->PutCategoryName ( newCName );
-      Sort();
-    }
-
-  } else
-    RC = CIFRC_NoCategory;
-
-  return RC;
-
-}
-
-void CMMCIFData::PrintCategories()  {
-// for debuging only
-int i;
-  printf ( " Total %i categories:\n",nCategories );
-  for (i=0;i<nCategories;i++)
-    if (Category[i])  {
-      printf ( " %5i. ",i+1 );
-      if (Category[i]->GetCategoryID()==MMCIF_Loop)
-            printf ( "Loop      %s\n",Category[i]->name );
-      else  printf ( "Structure %s\n",Category[i]->name );
-    }
-}
-
-
-void CMMCIFData::write ( RCFile f )  {
-int i,k;
-  if (!index)  Sort();
-  f.CreateWrite ( name );
-  f.WriteInt    ( &nCategories );
-  for (i=0;i<nCategories;i++)  {
-    if (Category[i])  {
-      k = Category[i]->GetCategoryID();
-      f.WriteInt ( &k );
-      Category[i]->write ( f );
-    } else  {
-      k = -1;
-      f.WriteInt ( &k );
-    }
-    f.WriteInt ( &(index[i]) );
-  }
-  f.WriteInt ( &flags   );
-  f.WriteInt ( &Warning );
-}
-
-
-void CMMCIFData::read ( RCFile f )  {
-int i,k;
-  FreeMemory(0);
-  f.CreateRead ( name );
-  f.ReadInt    ( &nCategories );
-  if (nCategories>0)  {
-    Category = new PCMMCIFCategory[nCategories];
-    GetVectorMemory ( index,nCategories,0 );
-    for (i=0;i<nCategories;i++)  {
-      f.ReadInt ( &k );
-      if (k>=0)  {
-        if (k==MMCIF_Struct)  Category[i] = new CMMCIFStruct();
-                        else  Category[i] = new CMMCIFLoop();
-        Category[i]->read ( f );
-      } else
-        Category[i] = NULL;
-      f.ReadInt ( &(index[i]) );
-    }
-  }
-  f.ReadInt ( &flags   );
-  f.ReadInt ( &Warning );
-}
-
-
-MakeStreamFunctions(CMMCIFData)
-
-
-
-//  ======================  CMMCIFFile  =============================
-
-
-CMMCIFFile::CMMCIFFile() : CStream()  {
-  InitMMCIFFile();
-}
-
-CMMCIFFile::CMMCIFFile ( cpstr FName, byte gzipMode )  : CStream()  {
-  InitMMCIFFile ();
-  ReadMMCIFFile ( FName,gzipMode );
-}
-
-CMMCIFFile::CMMCIFFile ( RPCStream Object ) : CStream(Object)  {
-  InitMMCIFFile();
-}
-
-CMMCIFFile::~CMMCIFFile()  {
-  FreeMemory();
-}
-
-void CMMCIFFile::InitMMCIFFile()  {
-  nData         = 0;
-  nAllocData    = 0;
-  data          = NULL;
-  index         = NULL;
-  PrintWarnings = False;
-  StopOnWarning = False;
-}
-
-void CMMCIFFile::FreeMemory()  {
-int i;
-  for (i=0;i<nData;i++)
-    if (data[i])  delete data[i];
-  if (data)  delete[] data;
-  data       = NULL;
-  FreeVectorMemory ( index,0 );
-  nData      = 0;
-  nAllocData = 0;
-}
-
-
-pstr GetMMCIFInputBuffer ( int & LineNo )  {
-  LineNo = _err_line;
-  _err_string[sizeof(_err_string)-1] = char(0);
-  return _err_string;
-}
-
-int  CMMCIFFile::ReadMMCIFFile ( cpstr FName, byte gzipMode )  {
-CFile       f;
-PCMMCIFData CIF;
-char        S[500];
-int         RC,lcount;
-
-  FreeMemory();
-
-  CIF = NULL;
-  f.assign ( FName,True,False,gzipMode );
-  if (f.reset(True))  {
-    S[0]   = char(0);
-    lcount = 0;
-    RC     = 0;
-    while ((!RC) && (!f.FileEnd()))  {
-      if (!CIF)  CIF = new CMMCIFData();
-      CIF->SetPrintWarnings ( PrintWarnings );
-      CIF->SetStopOnWarning ( StopOnWarning );
-      RC = CIF->ReadMMCIFData ( f,S,lcount );
-      if (!RC)  {
-        ExpandData ( nData+1 );
-        data[nData] = CIF;
-        nData++;
-        CIF = NULL;
-      }
-    }
-    if (CIF)  delete CIF;
-    f.shut();
-    if (RC==CIFRC_NoDataLine)  {
-      if (nData>0)  RC = 0;
-    }
-    Sort();
-    return RC;
-  } else
-    return CIFRC_CantOpenFile;
-
-}
-
-int CMMCIFFile::WriteMMCIFFile ( cpstr FName, byte gzipMode )  {
-CFile f;
-  f.assign ( FName,True,False,gzipMode );
-  if (f.rewrite())  {
-    WriteMMCIF ( f );
-    f.shut();
-    return 0;
-  } else
-    return CIFRC_CantOpenFile;
-}
-
-void CMMCIFFile::WriteMMCIF ( RCFile f )  {
-int i;
-  for (i=0;i<nData;i++)
-    if (data[i])
-      data[i]->WriteMMCIF ( f );
-}
-
-
-void CMMCIFFile::Sort()  {
-psvector tag;
-int      i;
-  if (nData>0)  {
-    FreeVectorMemory ( index,0 );
-    GetVectorMemory  ( index,nData,0 );
-    GetVectorMemory  ( tag  ,nData,0 );
-    for (i=0;i<nData;i++)  {
-      tag[i] = NULL;
-      CreateCopy ( tag[i],data[i]->name );
-    }
-    SortTags ( tag,nData,index );
-    for (i=0;i<nData;i++)
-      if (tag[i])  {
-        delete[] tag[i];
-        tag[i] = NULL;
-      }
-    FreeVectorMemory ( tag,0 );
-  }
-}
-
-int  CMMCIFFile::GetCIFDataNo ( cpstr DName )  {
-//   Binary search for index of DName ttag in data[].
-// Return:
-//    >=0 : position of the DName found
-//     <0 : the DName was not found, it could be inserted before
-//          (-RC-1)th element, where RC is the return value
-int l1,l2,l,k;
-
-  if (!data)   return -1;
-  if (!index)  Sort();
-
-  l  = 0;
-  l1 = 0;
-  l2 = nData-1;
-  k  = 1;
-  while (l1<l2-1)  {
-    l = (l1+l2)/2;
-    k = strcasecmp ( DName,data[index[l]]->name );
-    if (k<0)      l2 = l;
-    else if (k>0) l1 = l;
-    else  {
-      l1 = l;
-      break;
-    }
-  }
-
-  if (k==0)  return index[l];    // is at RCth position
-  k = strcasecmp ( DName,data[index[l1]]->name );
-  if (k==0)  return index[l1];   // is at RCth position
-  if (k<0)   return -1;          // would be at (-RC-1)th position
-  if (l2!=l1)  {
-    k = strcasecmp ( DName,data[index[l2]]->name );
-    if (k==0)  return index[l2]; // is at RCth position
-    if (k>0)   return -2-l2;     // would be at l2+1=(-RC-1)th position
-  }
-
-  return -2-l1;                  // would be at l1+1=(-RC-1)th position
-
-}
-
-PCMMCIFData  CMMCIFFile::GetCIFData ( int dataNo )  {
-  if ((dataNo>=0) && (dataNo<nData))  return data[dataNo];
-                                else  return NULL;
-}
-
-PCMMCIFData  CMMCIFFile::GetCIFData ( cpstr DName )  {
-int l;
-  l = GetCIFDataNo ( DName );
-  if (l>=0)  return data[l];
-       else  return NULL;
-}
-
-void CMMCIFFile::ExpandData ( int nDataNew )  {
-int          i,nAD;
-PPCMMCIFData data1;
-ivector      index1;
-  if (nDataNew>nAllocData)  {
-    nAD   = nDataNew + IMin(nAllocData/2+1,100);
-    data1 = new PCMMCIFData[nAD];
-    GetVectorMemory ( index1,nAD,0 );
-    for (i=0;i<nAllocData;i++)  {
-      data1 [i] = data [i];
-      index1[i] = index[i];
-    }
-    for (i=nAllocData;i<nAD;i++)  {
-      data1 [i] = NULL;
-      index1[i] = i;
-    }
-    if (data)  delete[] data;
-    FreeVectorMemory ( index,0 );
-    data       = data1;
-    index      = index1;
-    nAllocData = nAD;
-  }
-}
-
-int  CMMCIFFile::AddMMCIFData ( cpstr DName )  {
-//  return -1: the CIF data structure has been added on the
-//             top of data array; the index is added and sorted
-//             automatically
-//        >=0: the CIF data structure is already in the array
-//             -- its position is returned
-int  i1,i;
-  if (!data)  {
-    ExpandData ( 3 );  // get space for first 3 CIF data structures
-    data[0] = new CMMCIFData ( DName );
-    nData   = 1;
-    return -nData;     // the CIF data structure has been added
-                       // "on the top" of array
-  }
-  i1 = GetCIFDataNo ( DName );
-  if (i1>=0)  return i1;  // non-negative returns mean that the CIF
-                          // data structure is already in the array
-  i1 = -i1-1;  // otherwise the data has to be added and indexed at here
-  // put new CIF data structure on the top of array and update index
-  ExpandData ( nData+1 );
-  data[nData] = new CMMCIFData ( DName );
-  for (i=nData;i>i1;i--)
-    index[i] = index[i-1];
-  index[i1] = nData;
-  nData++;
-  return -nData; // the tag has been added on the top of array
-}
-
-
-int CMMCIFFile::DeleteMMCIFData ( cpstr DName )  {
-int dataNo = GetCIFDataNo ( DName );
-
-  if (dataNo>=0)  return DeleteMMCIFData ( dataNo );
-  return dataNo;
-
-}
-
-int CMMCIFFile::DeleteMMCIFData ( int dataNo )  {
-int i;
-
-  if ((0<=dataNo) && (dataNo<nData))  {
-
-    if (data[dataNo])  delete data[dataNo];
-    for (i=dataNo+1;i<nData;i++)
-      data[i-1] = data[i];
-    nData--;
-
-    Sort();
-
-    return 0;
-
-  }
-
-  return -nData;
-
-}
-
-void CMMCIFFile::Copy  ( PCMMCIFFile File )  {
-int i;
-  FreeMemory();
-  nData      = File->nData;
-  nAllocData = nData;
-  if (nData>0)  {
-    data = new PCMMCIFData[nData];
-    for (i=0;i<nData;i++)  {
-      if (File->data[i])  {
-        data[i] = new CMMCIFData();
-        data[i]->Copy ( File->data[i] );
-      } else
-        data[i] = NULL;
-    }
-  }
-}
-
-
-void CMMCIFFile::write ( RCFile f )  {
-int i,k;
-  f.WriteInt ( &nData );
-  for (i=0;i<nData;i++)
-    if (data[i])  {
-      k = 1;
-      f.WriteInt ( &k );
-      data[i]->write ( f );
-    } else  {
-      k = 0;
-      f.WriteInt ( &k );
-    }
-}
-
-void CMMCIFFile::read  ( RCFile f )  {
-int i,k;
-  FreeMemory();
-  f.ReadInt ( &nData );
-  nAllocData = nData;
-  if (nData>0)  {
-    data = new PCMMCIFData[nData];
-    for (i=0;i<nData;i++)  {
-      f.ReadInt ( &k );
-      if (k)  {
-        data[i] = new CMMCIFData();
-        data[i]->read ( f );
-      } else
-        data[i] = NULL;
-    }
-  }
-}
-
-
-MakeStreamFunctions(CMMCIFFile)
-
-
-int  isCIF ( cpstr FName, byte gzipMode )  {
-CFile f;
-int   rc;
-
-  f.assign ( FName,True,False,gzipMode );
-  if (f.reset(True))  {
-    rc = isCIF ( f );
-    f.shut();
-  } else
-    rc = -1;
-
-  return rc;
-
-}
-
-int  isCIF ( RCFile f )  {
-char    S[_max_buf_len+1];
-Boolean Done;
-pstr    p;
-
-  f.ReadLine ( S,_max_buf_len );
-  S[_max_buf_len] = char(0);
-  Done = False;
-  while (!Done)  {
-    p = &(S[0]);
-    while ((*p==' ') || (*p==char(9)))  p++;
-    Done = !strncmp(p,"data_",5);
-    if (!Done)  {
-      if (f.FileEnd())  {
-        Done = True;
-        p    = NULL;
-      } else  {
-        f.ReadLine ( S,_max_buf_len );
-        S[_max_buf_len] = char(0);
-      }
-    }
-  }
-
-  if (!p)  return 1;
-  if (!strncmp(p,"data_",5))  return 0;
-                        else  return 1;
-
-}
-
-
-pstr GetCIFMessage ( pstr M, int RC )  {
-int  LineNo;
-pstr InputLine;
-
-  InputLine = GetMMCIFInputBuffer ( LineNo );
-
-  if (RC>10)  {
-    if (RC & CIFW_UnrecognizedItems)
-      sprintf ( M,"unrecognized items found on %ith line\n%s",
-                LineNo,InputLine );
-    else if (RC & CIFW_MissingField)
-      sprintf ( M,"expected data field not found; line %i reads\n%s",
-                LineNo,InputLine );
-    else if (RC & CIFW_EmptyLoop)
-      sprintf ( M,"empty loop ('loop_') on %ith line\n%s",
-                LineNo,InputLine );
-    else if (RC & CIFW_UnexpectedEOF)
-      sprintf ( M,"unexpected end of file; line %i reads\n%s",
-                LineNo,InputLine );
-    else if (RC & CIFW_LoopFieldMissing)
-      sprintf ( M,"expected data field in a loop not found; "
-                  "line %i reads\n%s", LineNo,InputLine );
-    else if (RC & CIFW_LoopFieldMissing)
-      sprintf ( M,"expected data field in a loop not found; "
-                  "line %i reads\n%s", LineNo,InputLine );
-    else if (RC & CIFW_NotAStructure)
-      sprintf ( M,"a loop is used as a structure on line %i\n%s",
-                LineNo,InputLine );
-    else if (RC & CIFW_NotALoop)
-      sprintf ( M,"a structure is used as a loop on line %i\n%s",
-                LineNo,InputLine );
-    else if (RC & CIFW_DuplicateTag)
-      sprintf ( M,"duplicate tag was found on line %i\n%s",
-                LineNo,InputLine );
-    else
-      sprintf ( M,"undocumented warning issued for line %i\n%s",
-                LineNo,InputLine );
-  } else if (RC<0)
-    switch (RC)  {
-      case CIFRC_StructureNoTag : strcpy(M,"tag of a structure not "
-                                           "found");
-                             break;
-      case CIFRC_LoopNoTag      : strcpy(M,"tag of a loop not found");
-                             break;
-      case CIFRC_NoCategory     : strcpy(M,"category not found");
-                             break;
-      case CIFRC_WrongFormat    : strcpy(M,"wrong format of a number");
-                             break;
-      case CIFRC_NoTag          : strcpy(M,"tag not found");
-                             break;
-      case CIFRC_NotAStructure  : strcpy(M,"category is not a "
-                                           "structure");
-                             break;
-      case CIFRC_NotALoop       : strcpy(M,"category is not a loop");
-                             break;
-      case CIFRC_WrongIndex     : strcpy(M,"index outside the loop's "
-                                           "limits");
-                             break;
-      case CIFRC_NoField        : strcpy(M,"data is absent");
-                             break;
-      case CIFRC_Created        : strcpy(M,"category created");
-                             break;
-      case CIFRC_CantOpenFile   : strcpy(M,"can't open CIF file");
-                             break;
-      case CIFRC_NoDataLine     : strcpy(M,"'data_' tag not found." );
-                             break;
-      default                   : strcpy(M,"undocumented return code");
-    }
-
-  return M;
-
-}
diff --git a/mmdb/mmdb_mmcif.h b/mmdb/mmdb_mmcif.h
deleted file mode 100755
index 4b04ad5..0000000
--- a/mmdb/mmdb_mmcif.h
+++ /dev/null
@@ -1,2129 +0,0 @@
-//  $Id: mmdb_mmcif.h,v 1.23 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    16.01.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_MMCIF <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMCIFCategory ( mmCIF category    )
-//       ~~~~~~~~~  CMMCIFStruct   ( mmCIF structure   )
-//                  CMMCIFLoop     ( mmCIF loop        )
-//                  CMMCIFData     ( mmCIF data block  )
-//                  CMMCIFFile     ( mmCIF file        )
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-
-#ifndef __MMDB_MMCIF__
-#define __MMDB_MMCIF__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-
-
-//  ======================  CMMCIFCategory  ==========================
-
-#define MMCIF_Category 0
-#define MMCIF_Struct   1
-#define MMCIF_Loop     2
-#define MMCIF_Data     3
-
-DefineClass(CMMCIFCategory)
-DefineStreamFunctions(CMMCIFCategory)
-
-/// \brief CMMCIFCategory is a base class for CMMCIFStruct and
-///        CMMCIFLoop, implementations of mmCIF's "structure" and
-///        "loop" categories.
-/*!
-This class is not instantiated independently in any applications,
-however, it provides a few public functions which work for
-both CMMCIFStruct and CMMCIFLoop.
-
-All data in mmCIF hierarchy is addressed using construct
-"category.tag" plus row number (>=0) for loops. Category names
-should always start from underscore, while tags normally start
-with a letter, e.g. "_barrel.id".
-
-See general principles of working with mmCIF files and mmCIF
-hierarchies in Section \"\ref mmcif_handler\".
-*/
-
-class CMMCIFCategory : public CStream  {
-
-  friend class  CMMCIFData;
-
-  public :
-
-    /// \brief Basic constructor.
-    CMMCIFCategory ();
-
-    /// \brief Constructor that assigns category name.
-    /// \param[in] N category name (must start with underscore).
-    CMMCIFCategory ( cpstr N );
-
-    /// \brief Constructor for MMDB data streaming functions.
-    CMMCIFCategory ( RPCStream Object );
-
-    /// \brief Destructor.
-    ~CMMCIFCategory();
-
-    /// \brief Returns category name.
-    /// \return NULL if name was not set
-    /// \return pointer to character string if name was set
-    pstr   GetCategoryName() { return name;           }
-
-    /// \brief Sets category name.
-    /// \param N new category name
-    void   SetCategoryName ( cpstr N );
-
-    /// \brief Returns category type.
-    /// This function may be used when retrieving categories
-    /// (structures and loops) from data blocks (CMMCIFData).
-    /// \return MMCIF_Category for CMMCIFCategory
-    /// \return MMCIF_Struct   for CMMCIFStruct
-    /// \return MMCIF_Loop     for CMMCIFLoop
-    virtual int  GetCategoryID() { return MMCIF_Category; }
-
-    /// \brief Virtual function for writing category's content
-    ///        into mmCIF file.
-    /// Default implementation does nothing.
-    virtual void WriteMMCIF ( RCFile ) {}
-
-    /// \brief Virtual function for optimizig data structures.
-    /// Optimized data structures take less RAM and their indexes
-    /// are sorted for quicker access. Sorting is done automatically
-    /// as new data is added to the category. If the
-    /// category is edited (fields/data removed), it may need
-    /// optimization and re-sorting for efficiency.\n\n
-    /// The sorting preserves the order of actual appearance of
-    /// tags in mmCIF file. If a category is created
-    /// programmatically, the order of tags in mmCIF file will be
-    /// the same as order of adding them to the category.
-    virtual void Optimize();
-
-    /// \brief Sorts category's data for quicker access.
-    /// The sorting is essentially re-indexing of data for quicker
-    /// access. It does not change the order of data in both mmCIF
-    /// hierarchy and mmCIF file. E.g., if tag "serial_no" was 2nd
-    /// one in given category before sorting, it will remain on 2nd
-    /// place after it, therefore no change in tag number passed
-    /// to functions in CMMCIFStruct, CMMCIFLoop and CMMCIFData.
-    void  Sort();
-
-    /// \brief Returns serial number of a tag in the category.
-    /// \param[in]  ttag tag (or name of a field in category)
-    /// \return \b >=0 : the tag is in given position
-    /// \return \b <0 : the tag was not found, but it could be
-    ///         inserted before tag with (-rc-1)th index, where
-    ///         'rc' is the return.
-    int   GetTagNo ( cpstr ttag );
-
-    /// \brief Adds a tag to the category.
-    /// Adding a tag in CMMCIFCategory does not reserve any
-    /// placeholder for the corresponding value. All tags get
-    /// automatically sorted (reindexed) for quicker access.
-    /// Tags will appear in mmCIF file in order of their addition
-    /// to the category.
-    /// \param[in]  ttag tag to be added.
-    /// \return \b >=0 the tag is already in the category, and return
-    ///             is its serial number. No changes to the category
-    ///             is done
-    /// \return \b <0  the tag was added to the list of tags, and
-    ///             return is minus total number of tags in the
-    ///             category.
-    int   AddTag ( cpstr ttag );
-
-    /// \brief Returns the total number of tags in the category
-    int   GetNofTags() { return nTags; }
-
-    /// \brief Returns tag with the specified serial number.
-    /// The tags are enumerated as 0..GetNofTags()-1.
-    /// \param tagNo tag's serial number
-    /// \return \b NULL: tagNo is outside the range
-    ///                  of 0..GetNofTags()-1
-    /// \return \b not \b NULL: tag in tagNo'th position
-    pstr  GetTag ( int tagNo );  // 0..nTags-1
-
-    /// \brief Prints list of tags to stdout.
-    /// Both sorted and unsorted tags are printed to standard
-    /// output. This function may be used for debugging.
-    void  PrintTags();
-
-    /// \brief Returns True if all tags from the list are found
-    ///        in the category.
-    /// The size of the list of tags may be less than the number
-    /// of tags in the category, and order of tags is disregarded.
-    /// \param[in] tagList  list of tags to be checked for presence
-    ///                 in the category. The list must end with NULL
-    ///                 pointer, or your program will crash.
-    /// \return \b True  if all tags from the list were found in the
-    ///               category
-    /// \return \b False if one or more tags from the list were not
-    ///               found in the category.
-    ///
-    /// Example:
-    /// \code
-    ///  cpstr tagList[] = {"id","type","date",NULL};
-    ///  CMMCIFStruct cifStruct;
-    ///  if (cifStruct.CheckTags(tagList))
-    ///    printf ( " all tags are found in category %s\n",
-    ///             cifStruct.GetCategoryName() );
-    /// \endcode
-    /// This function is useful for finding categories in
-    /// "dirty cifs", where category name is not given.
-    Boolean CheckTags ( cpstr * tagList );
-
-    /// \brief Deep copy of categories.
-    /// Deep copy duplicates all data and memory allocations,
-    /// producing a genuine clone of the original. Only deep copy
-    /// should be used for copying MMDB objects, a mere assignment
-    /// operator will fail you.
-    /// \param[in] Category a pointer to CMMCIFCategory, the content of
-    ///                 which is copied into 'this' category.
-    virtual void Copy ( PCMMCIFCategory Category );
-
-    /// \brief MMDB stream writer.
-    void  write ( RCFile f );
-
-    /// \brief MMDB stream reader.
-    void  read  ( RCFile f );
-
-  protected:
-    int      nTags;
-    pstr     name;
-    psvector tag;
-    ivector  index;
-    int      nAllocTags;
-
-    void          InitMMCIFCategory ();
-    virtual void  FreeMemory        ();
-    void          ExpandTags        ( int nTagsNew );
-    void          PutCategoryName   ( cpstr newName );
-
-};
-
-
-
-//  ======================  CMMCIFStruct  ============================
-
-DefineClass(CMMCIFStruct)
-DefineStreamFunctions(CMMCIFStruct)
-
-/// \brief Constants used to specify mmCIF's \"data not given\" and
-/// \"data not available\" data types.
-#define CIF_NODATA_DOT           0
-#define CIF_NODATA_QUESTION      1
-#define CIF_NODATA_DOT_FIELD      pstr("\x02" ".")
-#define CIF_NODATA_QUESTION_FIELD pstr("\x02" "?")
-
-/// \brief CMMCIFStruct represents mmCIF's \"structure\" category,
-///        where data follows directly the corresponding tag.
-/*!
-mmCIF's \"structure\" category has the following form:
-\code
-_structure_name.tag0   value0
-_structure_name.tag1   value1
-...........
-_structure_name.tagN   valueN
-\endcode
-CMMCIFStruct represents this construct by keeping category name
-(\"_structure_name\") and associated lists of tags
-(\"tag0,tag1...tagN\") and their values (\"value0,value1...valueN\").
-
-The structure is created automatically when an mmCIF file is read,
-or it may be created programatically and then pushed into file.
-
-Access to data is provided via tags. Internally, all values are kept
-as character fields, and it is only on the retrieval stage that they
-are converted to other data types (integers, floats or strings).
-If conversion is not possible, an error code is returned by the
-corresponding functions, which should be checked by the application.
-
-See general principles of working with mmCIF files and mmCIF
-hierarchies, as well as some code samples, in Section
-\"\ref mmcif_handler\".
-*/
-
-class CMMCIFStruct : public CMMCIFCategory  {
-
-  public :
-
-    /// \brief Basic constructor
-    CMMCIFStruct ();
-
-    /// \brief Constructor that assigns structure name.
-    /// \param[in] N structure name (must start with underscore).
-    CMMCIFStruct ( cpstr N );
-
-    /// \brief Constructor for MMDB data streaming functions
-    CMMCIFStruct ( RPCStream Object );
-
-    /// \brief Destructor
-    ~CMMCIFStruct();
-
-    /// \brief Adds field to the structure.
-    /// \param[in] F field value
-    /// \param[in] T tag name
-    /// \param[in] Concatenate flag to concatenate existing field
-    ///            with the value of \b F. If tag \b T is already in
-    ///            the structure and \b Concatenate=True, then
-    ///            value of \b F is appended to the existing field.
-    ///            Otherwise, the field is replaced with the value
-    ///            of \b F
-    void AddField ( cpstr F, cpstr T, Boolean Concatenate=False );
-
-    /// \brief Returns category type \b MMCIF_Struct.
-    int  GetCategoryID()  { return MMCIF_Struct; }
-
-    /// \brief Optimizes structure for RAM and data access speed.
-    /// Optimized data structures take less RAM and their indexes
-    /// are sorted for quicker access. Sorting is done automatically
-    /// as new data is added to the category. If the structure
-    /// is edited (fields/data removed), it may need
-    /// optimization and re-sorting for efficiency.\n\n
-    /// The sorting preserves the order of actual appearance of
-    /// tags in mmCIF file. If a structure is created
-    /// programmatically, the order of tags in mmCIF file will be
-    /// the same as order of adding them to the structure.
-    void Optimize();
-
-    /// \brief Returns value of field corresponding to tag in the
-    ///        specified position.
-    /// Tag positions are defined by the order of their appearance in
-    /// mmCIF file (if structure was read from a file), or by the
-    /// order of their addition to the structure (if structure was
-    /// created programmatically). Tags are numbered as
-    /// 0...GetNofTags()-1.
-    /// \param[in] tagNo tag number (position in the structure)
-    /// \return \b NULL: tag does not exist
-    /// \return \b CIF_NODATA_DOT_FIELD the field contains
-    ///            \"data not given\" value
-    /// \return \b CIF_NODATA_QUESTION_FIELD the field contains
-    ///            \"data not available\" value
-    /// \return \b not \b NULL: string value of the field
-    pstr GetField ( int tagNo );  // 0..nTags-1
-
-    /// \brief Fetches value, corresponding to the given tag, as
-    ///        a string
-    /// \param[out] S pointer to string, which will point to newly
-    ///               allocated character string, containing value
-    ///               associated with tag \b TName. If tag or value
-    ///               is not found, or if value corresponds to
-    ///               mmCIF's \"data not given\" or
-    ///               \"data not available\", \b S returns NULL.
-    /// \param[in] TName character string with tag name
-    /// \param[in] Remove flag to remove the tag and its value from
-    ///               structure after it is read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_NoField: value is not found
-    /// \return \b CIFRC_Ok: success. If \b S returns NULL, then
-    ///                the value corresponds to either
-    ///                \"data not available\" or
-    ///                \"data not given\".
-    /// \remarks If \b S!=NULL at time of call, the function will
-    ///  try to dispose the string it points on. This allows a slick
-    ///  re-use of the same pointer in consequitive calls. This also
-    ///  means that one should never pass unallocated pointer to
-    ///  this function. Safe use assumes the following patern:
-    ///  \code
-    ///  CMMCIFStruct mmCIFStruct;
-    ///  pstr S;  // this is merely "char *S"
-    ///  int  rc;
-    ///
-    ///    S  = NULL; // null pointer before first use
-    ///    rc = mmCIFStruct.GetString ( S,"id" );
-    ///    if (rc)  CreateCopy ( S,"*** data not found" );
-    ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
-    ///    printf ( " rc=%i, S='%s'\n",rc,S );
-    ///
-    ///    rc = mmCIFStruct.GetString ( S,"property" );
-    ///    if (rc)  CreateCopy ( S,"*** data not found" );
-    ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
-    ///    printf ( " rc=%i, S='%s'\n",rc,S );
-    ///
-    ///    // etc etc etc
-    ///
-    ///    delete[] S;  // application is responsible for final
-    ///                 // disposal of memory
-    ///  \endcode
-    int  GetString ( pstr & S, cpstr TName, Boolean Remove=False );
-
-    /// \brief Returns pointer to value associated with given tag.
-    /// \param[in] TName character string with tag name
-    /// \param[out] RC return code:
-    ///    \arg \b CIFRC_NoTag: tag is not found
-    ///    \arg \b CIFRC_NoField: value is not found
-    ///    \arg \b CIFRC_Ok: success. If function returns NULL, then
-    ///                the value corresponds to either
-    ///                \"data not available\" or
-    ///                \"data not given\".
-    /// \return \b NULL: either tag or value is not found, or the
-    ///    value is \"data not available\" or \"data not given\".
-    ///    Read return code \b RC in order to interpret NULL return.
-    /// \return \b not \b NULL: pointer (\c char \c *) to value
-    ///    associated with \b TName.
-    /// \remarks Never try to dispose memory pointed by the return
-    /// value, or your program will crash.
-    pstr GetString ( cpstr TName, int & RC ); // NULL if TName
-                                                     // is not there
-
-    /// \brief Deletes field associated with given tag.
-    /// \param[in] TName character string with tag name
-    /// \return \b >=0: field deleted
-    /// \return \b <0: either field or tag is not found
-    int  DeleteField ( cpstr TName );  // <0 the field was not there
-
-    /// \brief Fetches value, corresponding to the given tag, as
-    ///        a real number.
-    /// \param[out] R reference to real number to accept the value.
-    ///        In case of failure, \b R returns zero.
-    /// \param[in] TName character string with tag name
-    /// \param[in] Remove flag to remove the tag and its value from
-    ///               structure after it is read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_NoField: field is not found
-    /// \return \b CIFRC_WrongFormat: value is not a real or integer
-    ///            number.
-    /// \return \b CIFRC_NoData: value is either
-    ///            \"data not available\" or
-    ///            \"data not given\".
-    /// \return \b CIFRC_Ok: success.
-    int  GetReal ( realtype & R, cpstr TName, Boolean Remove=False );
-
-    /// \brief Fetches value, corresponding to the given tag, as
-    ///        an integer number.
-    /// \param[out] I reference to integer number to accept the
-    ///        value. In case of failure, \b I returns zero, except
-    ///        when value is \"data not available\" or
-    ///        \"data not given\", when I returns \c MinInt4.
-    /// \param[in] TName character string with tag name
-    /// \param[in] Remove flag to remove the tag and its value from
-    ///               structure after it is read.
-    /// \return \arg \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_NoField: field is not found
-    /// \return \b CIFRC_WrongFormat: value is not an integer number.
-    /// \return \b CIFRC_NoData: value is either
-    ///            \"data not available\" or
-    ///            \"data not given\".
-    /// \return \b CIFRC_Ok: success.
-    int  GetInteger ( int & I, cpstr TName, Boolean Remove=False );
-
-    /// \brief Sets string value for given tag.
-    /// \param[in] S character string with value to be set.
-    ///            If \b S==NULL, the \"data not given\" value
-    ///            will be set. If \b S==\"\" (empty string), the
-    ///            \"data not available\" value is stored.
-    /// \param[in] TName character string with tag name. If tag
-    ///            is not found, it will be added to the structure.
-    /// \param[in] NonBlankOnly flag to treat white-space-only
-    ///            strings:
-    ///   \arg \b False: set as is
-    ///   \arg \b True:  set \"data not available\" value instead.
-    void PutString   ( cpstr S, cpstr TName,
-                       Boolean NonBlankOnly=False );
-
-    /// \brief Sets current date in format YYYY-MM-DD as a value
-    ///        for given tag.
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added to the structure.
-    void PutDate     ( cpstr T );
-
-    /// \brief Sets \"data not given\" or \"data not available\"
-    ///        values for given tag.
-    /// \param[in] NoDataType can be either
-    ///   \arg \b CIF_NODATA_DOT for \"data not given\"
-    ///   \arg \b CIF_NODATA_QUESTION for \"data not available\"
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added to the structure.
-    void PutNoData   ( int NoDataType, cpstr T  );
-
-    /// \brief Sets float-point value for given tag.
-    /// \param[in] R real number with value to be set.
-    /// \param[in] TName character string with tag name. If tag
-    ///            is not found, it will be added to the structure.
-    /// \param[in] prec float-point precision; g-format with given
-    ///            precision will be used
-    void PutReal     ( realtype R, cpstr TName, int prec=8 );
-
-    /// \brief Sets float-point value for given tag.
-    /// \param[in] R real number with value to be set.
-    /// \param[in] TName character string with tag name. If tag
-    ///            is not found, it will be added to the structure.
-    /// \param[in] format format string to convert \b R.
-    void PutReal     ( realtype R, cpstr TName, cpstr format );
-
-    /// \brief Sets integer value for given tag.
-    /// \param[in] I integer number with value to be set.
-    /// \param[in] TName character string with tag name. If tag
-    ///            is not found, it will be added to the structure.
-    void PutInteger  ( int      I, cpstr TName );
-
-    /// \brief Writes structure data in mmCIF format into file.
-    /// \param[in] FName character string with file name.
-    /// \param[in] gzipMode flag to controll compression of files:
-    ///  \arg \b GZM_NONE: do not compress
-    ///  \arg \b GZM_CHECK: check file name suffix and compress
-    ///                     (or not) accordingly
-    ///  \arg \b GZM_ENFORCE_GZIP: force gzip compression despite
-    ///                     suffix
-    ///  \arg \b GZM_ENFORCE_COMPRESS: force using compress despite
-    ///                     suffix
-    ///  \return \b True: success
-    ///  \return \b False: can not open file for writing.
-    /// \remarks This function does not create a valid mmCIF file
-    /// as \"data_XXX\" record will be missing. It may be used for
-    /// debugging though.
-    Boolean WriteMMCIFStruct ( cpstr FName,
-                               byte gzipMode=GZM_CHECK );
-
-    /// \brief Writes structure into given file.
-    /// \param f reference to MMDB's file class. The file should be
-    /// opened and closed by application.
-    /// \remarks There is a very limited use of this function on
-    /// application level. It is primarily used by CMMCIFData class.
-    void    WriteMMCIF ( RCFile f   );
-
-    /// \brief Deep copy of structures.
-    /// Deep copy duplicates all data and memory allocations,
-    /// producing a genuine clone of the original. Only deep copy
-    /// should be used for copying MMDB objects, a mere assignment
-    /// operator will fail you.
-    /// \param[in] Struct a pointer to CMMCIFStruct, the content of
-    ///                 which is copied into 'this' structure.
-    void Copy ( PCMMCIFCategory Struct );
-
-    /// \brief MMDB stream writer.
-    void write ( RCFile f );
-
-    /// \brief MMDB stream reader.
-    void read  ( RCFile f );
-
-  protected:
-    psvector field;
-
-    void InitMMCIFStruct();
-    void FreeMemory();
-
-};
-
-
-
-//  ======================  CMMCIFLoop  ==============================
-
-DefineClass(CMMCIFLoop)
-DefineStreamFunctions(CMMCIFLoop)
-
-/// \brief CMMCIFLoop represents mmCIF's \"loop\" category, which keeps
-///        rows of data values associated with tags.
-/*!
-mmCIF's \"loop\" category has the following form:
-\code
-loop_
-_loop_name.tag0   value0
-_loop_name.tag1   value1
-...........
-_loop_name.tagN   valueN
-value00 value10 ... valueN0
-value01 value11 ... valueN1
-...........
-value0M value1M ... valueNM
-\endcode
-CMMCIFLoop represents this construct by keeping category name
-(\"_loop_name\") and associated lists of tags
-(\"tag0,tag1...tagN\") and data vectors
-(\"[value00...value0M],[value10...value1M]...[valueN0...valueNM]\").
-
-The loop object is created automatically when an mmCIF file is read,
-or it may be created programatically and then pushed into file.
-
-Access to data is provided via tags and data indexes. Internally,
-all values are kept as character fields, and it is only on the
-retrieval stage that they are converted to other data types
-(integers, floats or strings). If conversion is not possible, an
-error code is returned by the corresponding functions, which should
-be checked by the application.
-
-The following code gives an example of creating mmCIF loop category
-and populating it with data:
-\code
-CMMCIFLoop loop;
-char       S[100];
-int        i;
-
-  // Specify loop name:
-  loop.SetCategoryName ( "_sample_loop" );
-
-  // Create loop structure, i.e., list of tags first:
-  loop.AddLoopTag ( "id"    );
-  loop.AddLoopTag ( "name"  );
-  loop.AddLoopTag ( "value" );
-
-  // Now populate it with data. This my be done in 2 ways.
-  // Here is how you write loop data in stream fashion,
-  // value-after-value:
-  for (i=0;i<3;i++)  {
-    loop.AddInteger ( i );
-    sprintf ( S,"1st_way-%i",i );
-    loop.AddString ( S );
-    loop.AddReal ( 2.5*(i+1) );
-  }
-
-  // Here is how you populate loop data using direct-access
-  // functions:
-  for (i=3;i<6;i++)  {
-    loop.PutReal ( 2.5*(i+1),"value",i );
-    loop.PutInteger ( i,"id" );
-    sprintf ( S,"2nd way: %i",i );
-    loop.PutString ( S,"name" );
-  }
-
-  loop.WriteMMCIFLoop ( "sample_loop.cif" );
-
-\endcode
-
-The resulting file \b sample_loop.cif will contain:
-
-\code
-
-loop_
-_sample_loop.id
-_sample_loop.name
-_sample_loop.value
-0   1st_way-0     2.5
-1   1st_way-1     5.0
-2   1st_way-2     7.5
-3   "2nd way: 3"  10.0
-4   "2nd way: 4"  12.5
-5   "2nd way: 5"  15.0
-
-\endcode
-
-See general principles of working with mmCIF files and mmCIF
-hierarchies, as well as some code samples, in Section
-\"\ref mmcif_handler\".
-*/
-
-class CMMCIFLoop : public CMMCIFCategory  {
-
-  friend class CMMCIFData;
-
-  public :
-
-    /// \brief Basic constructor
-    CMMCIFLoop ();
-
-    /// \brief Constructor that assigns structure name.
-    /// \param[in] N structure name (must start with underscore).
-    CMMCIFLoop ( cpstr N );
-
-    /// \brief Constructor for MMDB data streaming functions
-    CMMCIFLoop ( RPCStream Object );
-
-    /// \brief Destructor
-    ~CMMCIFLoop();
-
-    /// \brief Adds tag to the loop.
-    /// The tag is appended to the list of existing tags. The order
-    /// of tags cannot be changed.
-    /// \param[in] T tag name
-    /// \param[in] Remove flag to remove all fields in the loop.
-    void  AddLoopTag ( cpstr T, Boolean Remove=True );
-
-    /// \brief Sets string value at current loop position.
-    /// When \b CMMCIFLoop::Add[Data] functions use internal loop
-    /// pointer. When category is created or cleared (by using
-    /// \b CMMCIFTLoop::AddLoopTag ( T,True )) the pointer is set to
-    /// 0th row and 0th column (tag). After each call to
-    /// \b CMMCIFLoop::Add[Data] function, internal pointer advances
-    /// to next column (tag), and wraps over to next row, 0th tag,
-    /// if list of tags is exhausted. Any remaining fields in last
-    /// row will be populated with \"data not given\" value.
-    /// \param[in] S character string with value to be set.
-    ///            If \b S==NULL, the \"data not given\" value
-    ///            will be set. If \b S==\"\" (empty string), the
-    ///            \"data not available\" value is stored.
-    /// \param[in] NonBlankOnly flag to treat white-space-only
-    ///            strings:
-    ///   \arg \b False: set as is
-    ///   \arg \b True:  set \"data not available\" value instead.
-    void  AddString ( cpstr S, Boolean NonBlankOnly=False );
-
-    /// \brief Sets \"data not given\" or \"data not available\" at
-    ///        current loop position.
-    /// When \b CMMCIFLoop::Add[Data] functions use internal loop
-    /// pointer. When category is created or cleared (by using
-    /// \b CMMCIFTLoop::AddLoopTag ( T,True )) the pointer is set to
-    /// 0th row and 0th column (tag). After each call to
-    /// \b CMMCIFLoop::Add[Data] function, internal pointer advances
-    /// to next column (tag), and wraps over to next row, 0th tag,
-    /// if list of tags is exhausted. Any remaining fields in last
-    /// row will be populated with \"data not given\" value.
-    /// \param[in] NoDataType integer key specifying which type of
-    ///            data absence should be set as a value:
-    ///   \arg \b CIF_NODATA_DOT for \"data not given\"
-    ///   \arg \b CIF_NODATA_QUESTION for \"data not available\"
-    void  AddNoData ( int NoDataType );
-
-    /// \brief Sets float-point value at current loop position.
-    /// When \b CMMCIFLoop::Add[Data] functions use internal loop
-    /// pointer. When category is created or cleared (by using
-    /// \b CMMCIFTLoop::AddLoopTag ( T,True )) the pointer is set to
-    /// 0th row and 0th column (tag). After each call to
-    /// \b CMMCIFLoop::Add[Data] function, internal pointer advances
-    /// to next column (tag), and wraps over to next row, 0th tag,
-    /// if list of tags is exhausted. Any remaining fields in last
-    /// row will be populated with \"data not given\" value.
-    /// \param[in] R real number with value to be set.
-    /// \param[in] prec float-point precision; g-format with given
-    ///            precision will be used
-    void  AddReal ( realtype R, int prec=8 );
-
-    /// \brief Sets float-point value at current loop position in
-    ///        given format.
-    /// When \b CMMCIFLoop::Add[Data] functions use internal loop
-    /// pointer. When category is created or cleared (by using
-    /// \b CMMCIFTLoop::AddLoopTag ( T,True )) the pointer is set to
-    /// 0th row and 0th column (tag). After each call to
-    /// \b CMMCIFLoop::Add[Data] function, internal pointer advances
-    /// to next column (tag), and wraps over to next row, 0th tag,
-    /// if list of tags is exhausted. Any remaining fields in last
-    /// row will be populated with \"data not given\" value.
-    /// \brief Sets float-point value for given tag.
-    /// \param[in] R real number with value to be set.
-    /// \param[in] format format string to convert \b R.
-    void  AddReal ( realtype R, cpstr format );
-
-    /// \brief Sets integer value at current loop position in given
-    ///        format.
-    /// When \b CMMCIFLoop::Add[Data] functions use internal loop
-    /// pointer. When category is created or cleared (by using
-    /// \b CMMCIFTLoop::AddLoopTag ( T,True )) the pointer is set to
-    /// 0th row and 0th column (tag). After each call to
-    /// \b CMMCIFLoop::Add[Data] function, internal pointer advances
-    /// to next column (tag), and wraps over to next row, 0th tag,
-    /// if list of tags is exhausted. Any remaining fields in last
-    /// row will be populated with \"data not given\" value.
-    /// \param[in] I integer number with value to be set.
-    void  AddInteger ( int I );
-
-    /// \brief Returns current length of the loop (i.e. the number
-    ///        of rows).
-    /// \return number of data rows in the loop.
-    int   GetLoopLength() { return nRows; }
-
-    /// \brief Returns string pointer on the field corresponding to
-    ///        tag in the specified position, in the specified row.
-    /// Tag positions are defined by the order of their appearance in
-    /// mmCIF file (if loop was read from a file), or by the
-    /// order of their addition to the loop (if loop was
-    /// created programmatically).
-    /// \param[in] rowNo row number (0...GetLoopLength()-1)
-    /// \param[in] tagNo tag number (0...GetNofTags()-1)
-    /// \return \b NULL: tag or row do not exist
-    /// \return \b CIF_NODATA_DOT_FIELD the field contains
-    ///            \"data not given\" value
-    /// \return \b CIF_NODATA_QUESTION_FIELD the field contains
-    ///            \"data not available\" value
-    /// \return \b not \b NULL: string value of the field
-    /// \remarks Never try to dispose memory pointed by the return
-    /// value, or your program will crash.
-    pstr  GetField ( int rowNo, int tagNo );
-
-    /// \brief Fetches value, corresponding to the given tag, in
-    ///        the given row, as a string
-    /// \param[out] S pointer to string, which will point to newly
-    ///               allocated character string, containing value
-    ///               associated with tag \b TName and row \b nrow.
-    ///               If tag, row or value
-    ///               is not found, or if value corresponds to
-    ///               mmCIF's \"data not given\" or
-    ///               \"data not available\", \b S returns NULL.
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[in] Remove flag to remove the field from
-    ///               structure after it is read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_WrongIndex: row is not found
-    /// \return \b CIFRC_NoField: value is not found
-    /// \return \b CIFRC_Ok: success. If \b S returns NULL, then
-    ///                the value corresponds to either
-    ///                \"data not available\" or
-    ///                \"data not given\".
-    /// \remarks If \b S!=NULL at time of call, the function will
-    ///  try to dispose the string it points on. This allows a slick
-    ///  re-use of the same pointer in consequitive calls. This also
-    ///  means that one should never pass unallocated pointer to
-    ///  this function. Safe use assumes the following patern:
-    ///  \code
-    ///  CMMCIFLoop mmCIFLoop;
-    ///  pstr S;  // this is merely "char *S"
-    ///  int  rc;
-    ///
-    ///    S  = NULL; // null pointer before first use
-    ///    rc = mmCIFLoop.GetString ( S,"id",1 );
-    ///    if (rc)  CreateCopy ( S,"*** data not found" );
-    ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
-    ///    printf ( " rc=%i, S='%s'\n",rc,S );
-    ///
-    ///    rc = mmCIFLoop.GetString ( S,"property",0 );
-    ///    if (rc)  CreateCopy ( S,"*** data not found" );
-    ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
-    ///    printf ( " rc=%i, S='%s'\n",rc,S );
-    ///
-    ///    // etc etc etc
-    ///
-    ///    delete[] S;  // application is responsible for final
-    ///                 // disposal of memory
-    ///  \endcode
-    int   GetString ( pstr & S, cpstr TName, int nrow,
-                                       Boolean Remove=False );
-
-    /// \brief Returns pointer to value associated with given tag,
-    ///        in the given row of the loop.
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[out] RC return code:
-    ///    \arg \b CIFRC_NoTag: tag is not found
-    ///    \arg \b CIFRC_WrongIndex: row is not found
-    ///    \arg \b CIFRC_NoField: value is not found
-    ///    \arg \b CIFRC_Ok: success. If function returns NULL, then
-    ///                the value corresponds to either
-    ///                \"data not available\" or
-    ///                \"data not given\".
-    /// \return \b NULL: either tag, row or value is not found, or the
-    ///    value is \"data not available\" or \"data not given\".
-    ///    Read return code \b RC in order to interpret NULL return.
-    /// \return \b not \b NULL: pointer (\c char \c *) to value
-    ///    associated with \b TName.
-    /// \remarks Never try to dispose memory pointed by the return
-    /// value, or your program will crash.
-    pstr  GetString    ( cpstr TName, int nrow, int & RC );
-
-    /// \brief Copies value, associated with given tag,
-    ///        in the given row, into specified buffer.
-    ///  Terminating NULL character is appended.
-    /// \param[out] buf character string to accept the value
-    /// \param[in] maxlength maximum number of bytes to copy
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[out] RC return code:
-    ///    \arg \b CIFRC_NoTag: tag is not found
-    ///    \arg \b CIFRC_WrongIndex: row is not found
-    ///    \arg \b CIFRC_NoField: value is not found
-    ///    \arg \b CIFRC_Ok: success.
-    /// \remarks Destination string \b buf is not modified if
-    /// \b RC!=CIFRC_Ok .
-    void  CopyString   ( pstr  buf,   int maxlength,
-                         cpstr TName, int nrow, int & RC );
-
-    /// \brief Deletes field associated with given tag in
-    ///          the given row.
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \return \b >=0: field deleted
-    /// \return \b <0: either field or tag is not found
-    int   DeleteField  ( cpstr TName, int nrow );
-
-    /// \brief Deletes all fields in given row.
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \return \b CIFRC_Ok: fields deleted
-    /// \return \b CIFRC_WrongIndex: row not found
-    /// \remarks Note that this function delets just the fields, but
-    /// not the row. If you wish the row to be deleted, call
-    /// CMMCIFLoop::Optimize() function after this one.
-    int   DeleteRow    ( int nrow );
-
-    /// \brief Fetches value, corresponding to the given tag,
-    ///        in the given row, as a real number.
-    /// \param[out] R reference to real number to accept the value.
-    ///        In case of failure, \b R returns zero.
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[in] Remove flag to remove the field from
-    ///               the loop after it is read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_WrongIndex: row not found
-    /// \return \b CIFRC_NoField: field is not found
-    /// \return \b CIFRC_WrongFormat: value is not a real or integer
-    ///            number.
-    /// \return \b CIFRC_NoData: value is either
-    ///            \"data not available\" or
-    ///            \"data not given\".
-    /// \return \b CIFRC_Ok: success.
-    int   GetReal ( realtype & R, cpstr TName, int nrow,
-                                       Boolean Remove=False );
-
-    /// \brief Copies value, associated with given tag,
-    ///        in the given row, into specified destination as
-    ///        a real number.
-    /// \param[out] R reference to real number to accept the value
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[out] RC return code:
-    ///    \arg \b CIFRC_NoTag: tag is not found
-    ///    \arg \b CIFRC_WrongIndex: row is not found
-    ///    \arg \b CIFRC_NoField: value is not found
-    ///    \arg \b CIFRC_Ok: success.
-    /// \remarks Destination \b R is set 0 if \b RC!=CIFRC_Ok.
-    void  CopyReal ( realtype & R, cpstr TName, int nrow, int & RC );
-
-    /// \brief Copies value, associated with given tag,
-    ///        in the given row, into specified destination as
-    ///        an integer number.
-    /// \param[out] I reference to integer number to accept the value
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[out] RC return code:
-    ///    \arg \b CIFRC_NoTag: tag is not found
-    ///    \arg \b CIFRC_WrongIndex: row is not found
-    ///    \arg \b CIFRC_NoField: value is not found
-    ///    \arg \b CIFRC_Ok: success.
-    /// \remarks Destination \b I is set 0 if \b RC!=CIFRC_Ok.
-    void  CopyInteger ( int & I, cpstr TName, int nrow, int & RC );
-
-    /// \brief Fetches value, corresponding to the given tag,
-    ///        in the given row, as an integer number.
-    /// \param[out] I reference to integer number to accept the value.
-    ///        In case of failure, \b R returns zero.
-    /// \param[in] TName character string with tag name
-    /// \param[in] nrow  row number (0...GetLoopLength()-1)
-    /// \param[in] Remove flag to remove the field from
-    ///               the loop after it is read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_WrongIndex: row not found
-    /// \return \b CIFRC_NoField: field is not found
-    /// \return \b CIFRC_WrongFormat: value is not a real or integer
-    ///            number.
-    /// \return \b CIFRC_NoData: value is either
-    ///            \"data not available\" or
-    ///            \"data not given\".
-    /// \return \b CIFRC_Ok: success.
-    int   GetInteger   ( int & I, cpstr TName, int nrow,
-                                       Boolean Remove=False );
-
-    /// \brief Fetches set of values, corresponding to the given
-    ///        tag, in the given range of rows, as a vector of
-    ///        strings.
-    /// \param[out] S reference to string vector to accept
-    ///        the values. if \b S==NULL , the vector will be
-    ///        allocated with starting index of \b i1.
-    /// \param[in] TName character string with tag name
-    /// \param[in] i1  minimum row number to fetch, the actual
-    ///            index will be calculated as \b max(0,min(i1,i2))
-    /// \param[in] i2  maximum row number to fetch, the actual
-    ///            index will be calculated as
-    ///            \b min(GetLoopLength()-1,max(i1,i2))
-    /// \param[in] Remove flag to remove fetched fields from
-    ///               the loop after they are read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_WrongIndex: invalid range of rows
-    /// \return \b CIFRC_Ok: success.
-    ///
-    /// For safe use, \b S should be pre-allocated by calling
-    /// process. Only elements \b S[i1] to \b S[i2] will contain
-    /// fetched data, others remain untouched. The calling
-    /// process is responsible for the disposal of \b S. Example:
-    /// \code
-    /// CMMCIFLoop loop;
-    /// psvector   S;  // equivalent to char **S
-    /// int        i,i1,i2,rc,n;
-    ///
-    ///    // ... get loop data
-    ///
-    ///    n  = loop.GetLoopLength();
-    ///    i1 = 5;  i2 = n - 5;  // could be wrong!
-    ///
-    ///    //  allocate vector of strings
-    ///    GetVectorMemory ( S,n,0 );  // "0" for starting index
-    ///    for (i=0;i<n;i++)
-    ///      S[i] = NULL;  // initialize NULL string pointers
-    ///
-    ///    loop.GetSVector ( S,"name",i1,i2 );
-    ///    printf ( " Fetched with return code rc=%i\n",rc );
-    ///        // you may want a more thorough treatment of
-    ///        // the return code here
-    ///    for (i=i1;i<=i2;i++)
-    ///      if (S[i])  printf ( " %4i. name='%s'\n",i,S[i] );
-    ///           else  printf ( " %4i. name is not available\n",i );
-    ///
-    ///    //  S[] may be re-used for as many fetches as necessary
-    ///    //  without cleaning or disposals
-    ///
-    ///    //  dispose of vector of strings
-    ///    for (i=0;i<n;i++)
-    ///      if (S[i])  delete[] S[i];
-    ///    FreeVectorMemory ( S,0 );  // "0" for starting index
-    ///
-    /// \endcode
-    int  GetSVector ( psvector & S, cpstr TName,
-                      int i1=0, int i2=MaxInt4,
-                      Boolean Remove=False );
-
-    /// \brief Fetches set of values, corresponding to the given
-    ///        tag, in the given range of rows, as a vector of
-    ///        float-point numbers.
-    /// \param[out] R reference to float-point vector to accept
-    ///        the values. if \b R==NULL , the vector will be
-    ///        allocated with starting index of \b i1.
-    /// \param[in] TName character string with tag name
-    /// \param[in] i1  minimum row number to fetch, the actual
-    ///            index will be calculated as \b max(0,min(i1,i2))
-    /// \param[in] i2  maximum row number to fetch, the actual
-    ///            index will be calculated as
-    ///            \b min(GetLoopLength()-1,max(i1,i2))
-    /// \param[in] Remove flag to remove fetched fields from
-    ///               the loop after they are read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_WrongIndex: invalid range of rows
-    /// \return \b CIFRC_Ok: success.
-    ///
-    /// For safe use, \b R should be pre-allocated by calling
-    /// process. Only elements \b R[i1] to \b R[i2] will contain
-    /// fetched data, others remain untouched. The calling
-    /// process is responsible for the disposal of \b R. Example:
-    /// \code
-    /// CMMCIFLoop loop;
-    /// rvector    R;  // equivalent to realtype *R
-    /// int        i,i1,i2,rc,n;
-    ///
-    ///    // ... get loop data
-    ///
-    ///    n  = loop.GetLoopLength();
-    ///    i1 = 5;  i2 = n - 5;  // could be wrong!
-    ///
-    ///    //  allocate a vector of real numbers
-    ///    GetVectorMemory ( R,n,0 );  // "0" for starting index
-    ///    // no need to initiaize unless required for the
-    ///    // application
-    ///
-    ///    rc = loop.GetRVector ( R,"value",i1,i2 );
-    ///    printf ( " Fetched with return code rc=%i\n",rc );
-    ///        // you may want a more thorough treatment of
-    ///        // the return code here
-    ///    for (i=i1;i<=i2;i++)
-    ///      printf ( " value[%4i] = %15.7g\n",i,R[i] );
-    ///
-    ///    //  R[] may be re-used for as many fetches as necessary
-    ///    //  without cleaning or disposals
-    ///
-    ///    //  dispose of the vector
-    ///    FreeVectorMemory ( R,0 );  // "0" for starting index
-    ///
-    /// \endcode
-    int  GetRVector ( rvector  & R, cpstr TName,
-                      int i1=0, int i2=MaxInt4,
-                      Boolean Remove=False );
-
-    /// \brief Fetches set of values, corresponding to the given
-    ///        tag, in the given range of rows, as a vector of
-    ///        integer numbers.
-    /// \param[out] I reference to float-point vector to accept
-    ///        the values. if \b I==NULL , the vector will be
-    ///        allocated with starting index of \b i1.
-    /// \param[in] TName character string with tag name
-    /// \param[in] i1  minimum row number to fetch, the actual
-    ///            index will be calculated as \b max(0,min(i1,i2))
-    /// \param[in] i2  maximum row number to fetch, the actual
-    ///            index will be calculated as
-    ///            \b min(GetLoopLength()-1,max(i1,i2))
-    /// \param[in] Remove flag to remove fetched fields from
-    ///               the loop after they are read.
-    /// \return \b CIFRC_NoTag: tag is not found
-    /// \return \b CIFRC_WrongIndex: invalid range of rows
-    /// \return \b CIFRC_Ok: success.
-    ///
-    /// For safe use, \b I should be pre-allocated by calling
-    /// process. Only elements \b I[i1] to \b I[i2] will contain
-    /// fetched data, others remain untouched. The calling
-    /// process is responsible for the disposal of \b I.
-    /// See example in CMMCIFLoop::GetRVector documentation
-    /// for details.
-    int  GetIVector ( ivector  & I, cpstr TName,
-                      int i1=0, int i2=MaxInt4,
-                      Boolean Remove=False );
-
-    /// \brief Sets string value for given tag and row.
-    /// \param[in] S character string with value to be set.
-    ///            If \b S==NULL, the \"data not given\" value
-    ///            will be set. If \b S==\"\" (empty string), the
-    ///            \"data not available\" value is stored.
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] nrow  row number. If the row does not exist then
-    ///            it will be created, along with all other rows
-    ///            between GetLoopLength()-1 and \b nrow as
-    ///            necessary. All newly created fields will be
-    ///            initialised with \"data not given\" value.
-    void  PutString ( cpstr S, cpstr T, int nrow );
-
-    /// \brief Sets \"data not given\" or \"data not available\"
-    ///        values for given tag and row.
-    /// \param[in] NoDataType can be either
-    ///   \arg \b CIF_NODATA_DOT for \"data not given\"
-    ///   \arg \b CIF_NODATA_QUESTION for \"data not available\"
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] nrow  row number. If the row does not exist then
-    ///            it will be created, along with all other rows
-    ///            between GetLoopLength()-1 and \b nrow as
-    ///            necessary. All newly created fields will be
-    ///            initialised with \"data not given\" value.
-    void  PutNoData ( int NoDataType, cpstr T, int nrow );
-
-    /// \brief Sets float-point value for given tag and row.
-    /// \param[in] R real number with value to be set.
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] nrow  row number. If the row does not exist then
-    ///            it will be created, along with all other rows
-    ///            between GetLoopLength()-1 and \b nrow as
-    ///            necessary. All newly created fields will be
-    ///            initialised with \"data not given\" value.
-    /// \param[in] prec float-point precision; g-format with given
-    ///            precision will be used
-    void  PutReal ( realtype R, cpstr T, int nrow, int prec=8 );
-
-    /// \brief Sets float-point value for given tag and row.
-    /// \param[in] R real number with value to be set.
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] nrow  row number. If the row does not exist then
-    ///            it will be created, along with all other rows
-    ///            between GetLoopLength()-1 and \b nrow as
-    ///            necessary. All newly created fields will be
-    ///            initialised with \"data not given\" value.
-    /// \param[in] format format string to convert \b R.
-    void  PutReal ( realtype R, cpstr T, int nrow, cpstr format );
-
-    /// \brief Sets integer value for given tag.
-    /// \param[in] I integer number with value to be set.
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] nrow  row number. If the row does not exist then
-    ///            it will be created, along with all other rows
-    ///            between GetLoopLength()-1 and \b nrow as
-    ///            necessary. All newly created fields will be
-    ///            initialised with \"data not given\" value.
-    void  PutInteger ( int I, cpstr T, int nrow );
-
-    /// \brief Sets a set of string values for the given tag and
-    ///        range of rows.
-    /// \param[in] S string vector with values to store in the loop
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] i1  minimum data index in \b S to set in the loop
-    /// \param[in] i2  maximum data index in \b S to set in the loop.
-    ///
-    /// The data will be set in rows \b i1 to \b i2 (inclusive) in
-    /// the loop. If range \b [i1,i2] is not contained in the loop,
-    /// all missing rows will be created and initialised to
-    /// \"data not given\" value. Example:
-    /// \code
-    /// CMMCIFLoop loop("_sample_loop");
-    /// pstr       S[100];
-    /// int        i;
-    ///
-    ///    //  initialize vector of strings
-    ///    for (i=0;i<100;i++)  {
-    ///      S[i] = new char[20];
-    ///      sprintf ( S[i],"value i=%i",i );
-    ///    }
-    ///
-    ///    //  put data in loop
-    ///    loop.PutSVector ( S,"made_up_string_value",0,99 );
-    ///
-    ///    //  dispose of vector of strings
-    ///    for (i=0;i<100;i++)
-    ///      if (S[i])  delete[] S[i];
-    ///
-    /// \endcode
-    void  PutSVector   ( psvector S, cpstr T, int i1, int i2 );
-
-    /// \brief Sets a set of float-point values for the given tag and
-    ///        range of rows.
-    /// \param[in] R vector of real numbers to store in the loop
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] i1  minimum data index in \b S to set in the loop
-    /// \param[in] i2  maximum data index in \b S to set in the loop
-    /// \param[in] prec float-point precision; g-format with given
-    ///            precision will be used.
-    ///
-    /// The data will be set in rows \b i1 to \b i2 (inclusive) in
-    /// the loop. If range \b [i1,i2] is not contained in the loop,
-    /// all missing rows will be created and initialised to
-    /// \"data not given\" value.
-    void  PutRVector   ( rvector  R, cpstr T, int i1, int i2,
-                                                   int prec=8 );
-
-    /// \brief Sets a set of integer values for the given tag and
-    ///        range of rows.
-    /// \param[in] I vector of integers to store in the loop
-    /// \param[in] T character string with tag name. If tag
-    ///            is not found, it will be added, and all data in
-    ///            the loop will be reindexed accordingly.
-    /// \param[in] i1  minimum data index in \b S to set in the loop
-    /// \param[in] i2  maximum data index in \b S to set in the loop.
-    ///
-    /// The data will be set in rows \b i1 to \b i2 (inclusive) in
-    /// the loop. If range \b [i1,i2] is not contained in the loop,
-    /// all missing rows will be created and initialised to
-    /// \"data not given\" value.
-    void  PutIVector   ( ivector  I, cpstr T, int i1, int i2 );
-
-    /// \brief Returns category type \b MMCIF_Loop.
-    int   GetCategoryID() { return MMCIF_Loop; }
-
-    /// \brief Optimizes loop for RAM and data access speed.
-    /// Optimized data structures take less RAM and their indexes
-    /// are sorted for quicker access. Sorting is done automatically
-    /// as new data is added to the category. If the structure
-    /// is edited (fields/data removed), it may need
-    /// optimization and re-sorting for efficiency.\n\n
-    /// The sorting preserves the order of actual appearance of
-    /// tags and rows in mmCIF file. If a loop is created
-    /// programmatically, the order of tags and rows in mmCIF file
-    /// will be the same as order of adding them to the loop.
-    void  Optimize();
-
-    /// \brief Writes loop data in mmCIF format into file.
-    /// \param[in] FName character string with file name.
-    /// \param[in] gzipMode flag to controll compression of files:
-    ///  \arg \b GZM_NONE: do not compress
-    ///  \arg \b GZM_CHECK: check file name suffix and compress
-    ///                     (or not) accordingly
-    ///  \arg \b GZM_ENFORCE_GZIP: force gzip compression despite
-    ///                     suffix
-    ///  \arg \b GZM_ENFORCE_COMPRESS: force using compress despite
-    ///                     suffix
-    /// \return \b True: success
-    /// \return \b False: can not open file for writing.
-    /// \remarks This function does not create a valid mmCIF file
-    /// as \"data_XXX\" record will be missing. It may be used for
-    /// debugging though.
-    Boolean WriteMMCIFLoop ( cpstr FName,
-                             byte gzipMode=GZM_CHECK );
-
-    /// \brief Writes loop data into given file.
-    /// \param f reference to MMDB's file class. The file should be
-    /// opened and closed by application.
-    /// \remarks There is a very limited use of this function on
-    /// application level. It is primarily used by CMMCIFData class.
-    void  WriteMMCIF ( RCFile f );
-
-    /// \brief Deep copy of loops.
-    /// Deep copy duplicates all data and memory allocations,
-    /// producing a genuine clone of the original. Only deep copy
-    /// should be used for copying MMDB objects, a mere assignment
-    /// operator will fail you.
-    /// \param[in] Loop a pointer to CMMCIFLoop, the content of
-    ///                 which is copied into 'this' loop.
-    void  Copy ( PCMMCIFCategory Loop );
-
-    /// \brief MMDB stream writer.
-    void write ( RCFile f );
-
-    /// \brief MMDB stream reader.
-    void read  ( RCFile f );
-
-  protected:
-    int      nRows;
-    psmatrix field;
-    int      iColumn,nAllocRows;
-
-    void  InitMMCIFLoop();
-    void  FreeMemory   ();
-    void  DeleteFields ();
-    void  ExpandRows   ( int nRowsNew );
-
-};
-
-
-
-//  ======================  CMMCIFData  =============================
-
-
-//    CIFW are warnings which may be issued on reading the CIF file.
-// Each of them means actually a CIF syntax error.
-#define CIFW_UnrecognizedItems 0x00000020
-#define CIFW_MissingField      0x00000040
-#define CIFW_EmptyLoop         0x00000080
-#define CIFW_UnexpectedEOF     0x00000100
-#define CIFW_LoopFieldMissing  0x00000200
-#define CIFW_NotAStructure     0x00000400
-#define CIFW_NotALoop          0x00000800
-#define CIFW_DuplicateTag      0x00001000
-
-//    CIFRC are return codes from procedures of extracting data from
-// the read CIF file. Negative returns reflect unsuccessful and
-// not accomplished operation.
-#define CIFRC_Loop              2
-#define CIFRC_Structure         1
-#define CIFRC_Ok                0
-#define CIFRC_StructureNoTag   -1
-#define CIFRC_LoopNoTag        -2
-#define CIFRC_NoCategory       -3
-#define CIFRC_WrongFormat      -4
-#define CIFRC_NoTag            -5
-#define CIFRC_NotAStructure    -6
-#define CIFRC_NotALoop         -7
-#define CIFRC_WrongIndex       -8
-#define CIFRC_NoField          -9
-#define CIFRC_Created         -12
-#define CIFRC_CantOpenFile    -13
-#define CIFRC_NoDataLine      -14
-#define CIFRC_NoData          -15
-
-
-//
-//  Functional flags:
-//  ~~~~~~~~~~~~~~~~~
-//
-//  CIFFL_PrintWarnings      when reading CIF file, all warning
-//                           messages will be printed. If the flag
-//                           is off, the warnings will be bit-encoded
-//                           in the return code
-//  CIFFL_StopOnWarnings     reading CIF file will stop at first
-//                           warning issued
-//  CIFFL_SuggestCategories  allows reading CIF file with loops having
-//                           no categories. Hidden category names
-//                           will be automatically generated for
-//                           internal consistency of the system.
-//                           These names will not appear in output.
-//                           As these names are hidden, they cannot
-//                           be used to access data. It is therefore
-//                           assumed that all tags in all loops without
-//                           categories are unique. Simply specify ""
-//                           for category when accessing such data
-//                           (it cannot be accessed through CMMCIFLoop,
-//                           but only through CMMCIFData functions
-//                           taking both Category and Tag; note that
-//                           CIFFL_SuggestCategories flag must be on
-//                           while accessing such data).
-//  CIFFL_SuggestTags        allows for identical tags in a category
-//                           (including a hidden category). Hidden
-//                           suffixes to tag names will be generated
-//                           for internal consistency. At present,
-//                           only data for first non-unique tag may be
-//                           accessed.
-//
-#define CIFFL_PrintWarnings      0x00000001
-#define CIFFL_StopOnWarnings     0x00000002
-#define CIFFL_SuggestCategories  0x00000004
-#define CIFFL_SuggestTags        0x00000008
-
-
-DefineClass(CMMCIFData)
-DefineStreamFunctions(CMMCIFData)
-
-
-/// \brief CMMCIFData represents mmCIF's \"data\" category, which keeps
-///        structures and loops and is mandatory element of mmCIF file.
-/*!
-mmCIF's \"data\" category has the following form:
-\code
-data_DataName
-
-_structure1.tag1  value1
-..........
-
-loop_
-..........
-
-\endcode
-In the above example, all structures and loops that follow \b data_
-keyword until next \b data_ or end of file are part of data category
-with name \b DataName.
-
-CMMCIFData represents this construct by keeping a list of CMMCIFStruct
-and CMMCIFLoop class instances associated with the corresponding
-categories in the data block.
-
-The data object is created automatically when an mmCIF file is read,
-or it may be created programatically and then pushed into file.
-
-Access to data is provided via category (structures and loops) names,
-tags and data indexes (in case of loops). Alternatively, pointers to
-contained structures and loops may be obtained first, an used for
-fetching data using CMMCIFStruct's and CMMCIFLoop's interface
-functions.
-
-The following code gives an example of creating mmCIF's data category
-and populating it:
-\code
-CMMCIFData data;
-
-  // Specify data name:
-  data.PutDataName ( "Sample_Data" );
-
-  // the following statement:
-  data.PutInteger ( 12345,"_category1","id" );
-  // creates structure "_category1" with tag "id" and assigns it
-  // the integer value of 12345.
-
-  data.PutString ( "a name","_category1","name" );
-
-  // Loops may be created quite similarly:
-  data.PutLoopInteger ( 12345   ,"_loop1","id"  ,2 );
-  data.PutLoopInteger ( "a name","_loop1","name",0 );
-
-  // push data into a file
-  data.WriteMMCIFData ( "sample.cif" );
-
-\endcode
-
-The resulting file \b sample.cif will contain:
-
-\code
-data_Sample_Data
-
-_category1.id   12345
-_category1.name "a name"
-
-loop_
-_loop1.id
-_loop1.name
-.      "a name"
-.      .
-12345  .
-\endcode
-
-The same result may be achieved differently:
-
-\code
-CMMCIFData    data;
-PCMMCIFStruct mmCIFStruct;  // equivalent to CMMCIFStruct *mmCIFStruct
-PCMMCIFLoop   mmCIFLoop;    // equivalent to CMMCIFLoop   *mmCIFLoop
-
-  // Specify data name:
-  data.PutDataName ( "Sample_Data" );
-
-  // create new mmCIF's structure in the data block:
-  data.AddStructure ( "_category1",mmCIFStruct );
-  if (mmCIFStruct)  {
-    mmCIFStruct->PutInteger ( 12345   ,"id"   );
-    mmCIFStruct->PutString  ( "a name","name" );
-  }
-
-  // similarly for the loop:
-  data.AddLoop ( "_loop1",mmCIFLoop );
-  if (mmCIFLoop)  {
-    mmCIFLoop->PutInteger ( 12345   ,"id"  ,2 );
-    mmCIFLoop->PutString  ( "a name","name",0 );
-  }
-
-  // push data into a file
-  data.WriteMMCIFData ( "sample.cif" );
-
-\endcode
-
-See general principles of working with mmCIF files and mmCIF
-hierarchies, as well as some code samples, in Section
-\"\ref mmcif_handler\".
-*/
-
-class CMMCIFData : public CStream  {
-
-  friend class CMMCIFFile;
-
-  public :
-
-    /// \brief Basic constructor.
-    CMMCIFData ();
-
-    /// \brief Constructor that assigns data block name.
-    /// \param[in] N data block name.
-    CMMCIFData ( cpstr N );
-
-    /// \brief Constructor for MMDB data streaming functions.
-    CMMCIFData ( RPCStream Object );
-
-    /// \brief Destructor.
-    ~CMMCIFData();
-
-
-    // -------- General I/O functions
-
-    /// \brief Sets flag to print warnings on reading mmCIF files.
-    /// \param[in] SPW flag to print warnings:
-    ///    \arg \b True : warnings will be printed to stdout
-    ///    \arg \b False : warnings will not be printed but returned
-    ///                    in return code (default)
-    void  SetPrintWarnings ( Boolean SPW );
-
-    /// \brief Sets flag to stop on warning when reading an mmCIF file.
-    /// \param[in] SOW flag to stop on warning:
-    ///    \arg \b True : reading will stop on first warning encountered
-    ///    \arg \b False : warnings will not stop reading (default)
-    void  SetStopOnWarning ( Boolean SOW );
-
-    /// \brief Sets optional flag(s) for reading mmCIF files.
-    /// By default, no flags are set.
-    /// \param[in] F flag or logical \"or\" of several flags to be set:
-    ///  \arg \b CIFFL_PrintWarnings  toggles printing warning messages
-    ///               at reading an mmCIF file, in stdout. If this
-    ///               flag is not set (default), the warnings will
-    ///               be returned in the bit-encoded return code
-    ///  \arg \b CIFFL_StopOnWarnings  if set, reading an mmCIF file
-    ///               will stop at first warning issued
-    ///  \arg \b CIFFL_SuggestCategories  allows for reading of mmCIF
-    ///               files with loops and structures having no
-    ///               category names (\"dirty CIFs\"). If this flag is
-    ///               set, then hidden category names will be
-    ///               automatically generated. These names will not
-    ///               appear in the output. As these names are hidden,
-    ///               they cannot be used to access data. In order to
-    ///               access data in such categories, consider whether
-    ///               they are structures or loops. In case of a
-    ///               unnamed structure, simply specify \"\" (empty
-    ///               string) for structure name in all access
-    ///               functions ( note that \b CIFFL_SuggestCategories
-    ///               flag must be on while accessing such data). In
-    ///               case of a loop, first use the CMMCIFData::FindLoop
-    ///               function to retrieve pointer on the hidden loop,
-    ///               and then use CMMCIFLoop's interface function to
-    ///               fetch data from the loop.
-    ///  \arg \b CIFFL_SuggestTags  allows for duplicate tags in a
-    ///               category (structure or loop, including hidden
-    ///               categories). This may help reading \"dirty CIFs\".
-    ///               At present, only data for first non-unique tag
-    ///               may be accessed.
-    void  SetFlag ( int F );
-
-    /// \brief Removes optional flag(s) for reading mmCIF files.
-    /// By default, no flags are set.
-    /// \param[in] F flag or logical \"or\" of several flags to be
-    ///              removed (unset):
-    ///  \arg \b CIFFL_PrintWarnings  no wornings will be printed in
-    ///               stdout, but rather returned in the bit-encoded
-    ///               return code
-    ///  \arg \b CIFFL_StopOnWarnings  warnings will not stop reading
-    ///  \arg \b CIFFL_SuggestCategories  loops without names will
-    ///               count as errors and stop reading
-    ///  \arg \b CIFFL_SuggestTags  duplicate tags in structures and
-    ///               loops will count as errors and stop reading.
-    ///
-    /// See more detail flag description in CMMCIFData::SetFlag().
-    void  RemoveFlag ( int F );
-
-    /// \brief Returns bit-encoded warnings issued at last file read.
-    /// \return an integer number, which is an or-superposition of
-    ///         warning flags:
-    /// \arg \b CIFW_UnrecognizedItems: unrecognized items were found
-    /// \arg \b CIFW_MissingField: expected data field not found
-    /// \arg \b CIFW_EmptyLoop: loop category was defined but has no
-    ///                         data
-    /// \arg \b CIFW_UnexpectedEOF: mmCIF construct finished prematurely
-    /// \arg \b CIFW_LoopFieldMissing: loop category has wrong number
-    ///                         of data fields
-    /// \arg \b CIFW_NotAStructure: attempt to use a category name,
-    ///                         which was once defined as a structure,
-    ///                         as a loop
-    /// \arg \b CIFW_NotALoop: attempt to use a category name, which was
-    ///                         once defined as a loop, as a structure
-    /// \arg \b CIFW_DuplicateTag: duplicate tag was found in a
-    ///                         structure or loop
-    int  GetWarnings() { return Warning; }
-
-    /// \brief Sets category names and tags that are to be ignored
-    ///        on file read.
-    /// \param[in] cats list of categories, terminated by NULL
-    /// \param[in] tags list of tags, terminated by NULL.
-    ///
-    /// This special function is to aid reading corrupt mmCIF files.
-    /// The input lists should be of equal length 'n', and specify
-    /// 'n' \"wrong fields\" that should be ignored on input. E.g.,
-    /// ith \"wrong field\" is identified as \"cats[i].taga[i]\".
-    /// If \"wrong field\" belongs to a loop, then all the corresponding
-    /// column is assumed to be absent. This corrects for mmCIF errors
-    /// when defined tags in loops or structures do not have actual data
-    /// associated with them.
-    ///
-    /// In order to remove settings, call SetWrongFields(NULL,NULL).
-    ///
-    /// Example:
-    /*!
-    \code
-    // assume data for "_category.item1" and "_category.item2"
-    // missed in a file to-be-read
-    CMMCIFData data;
-    cpstr cats[] = { "_category", "_category", NULL };
-    cpstr tags[] = { "item1"    , "item2"    , NULL };
-
-       data.SetWrongFields ( cats,tags );
-       data.ReadMMCIFData  ( "corrupt.cif" );
-    \endcode
-    */
-    void  SetWrongFields ( cpstr *cats, cpstr *tags );
-
-    /// \brief Reads mmCIF data block from file.
-    /// \param FName character null-terminated string with file name
-    /// \param gzipMode flag to read compressed files:
-    /// \arg \b GZM_NONE: do not assume any compression
-    /// \arg \b GZM_CHECK: check compression type by file extension
-    /// \arg \b GZM_ENFORCE: same as \b GZM_ENFORCE_GZIP
-    /// \arg \b GZM_ENFORCE_GZIP: assume gzip compression (*.gz files)
-    /// \arg \b GZM_ENFORCE_COMPRESS: assume compression with 'compress'
-    ///         (*.Z files).
-    /// \return \b CIFRC_Ok: no errors
-    /// \return \b negative: there were errors
-    /// \return \b positive: there were warnings.
-    ///
-    /// This function will read 1st data block from the specified file.
-    /// In case of non-zero return, use GetCIFMessage() function to
-    /// print the corresponding error message or warning:
-    /*!
-    \code
-    CMMCIFData data;
-    char       errLog[500];
-    int        rc;
-       rc = data.ReadMMCIFData  ( "myfile.cif" );
-       if (rc<0)
-         printf ( " There was an error:\n %s\n",
-                  GetCIFMessage(errLog,rc) );
-       else if (rc>0)
-         printf ( " There were warnings:\n %s\n",
-                  GetCIFMessage(errLog,rc) );
-       else
-         printf ( " mmCIF file has be read in successfully.\n" );
-    \endcode
-    */
-    int  ReadMMCIFData ( cpstr FName, byte gzipMode=GZM_CHECK );
-
-    /// \brief Reads sequential mmCIF data blocks from file.
-    /// \param RCFile reference to a CFile object opened on a file
-    /// \param S buffer string which represent a sliding read window.
-    ///          The string should be at least 500 characters long,
-    ///          initialized with empty-string value before first read,
-    ///          and passed unchanged between the reads
-    /// \param lcount line counter, should be set zero before first
-    ///          read and passed unchanged between the reads.
-    /// \return \b CIFRC_Ok: no errors
-    /// \return \b negative: there were errors
-    /// \return \b positive: there were warnings.
-    ///
-    /// This function will read 1st data block from the current position
-    /// of the file. The function is useful if a file contains more than
-    /// a single data block, which should be read sequentially.
-    ///
-    /// \note Alternatively, files with multiple data blocks can be
-    /// read using CMMCIFFile class.
-    ///
-    /// In case of non-zero return, use GetCIFMessage() function to
-    /// print the corresponding error message or warning:
-    /*!
-    \code
-  CMMCIFData    mmCIFData;
-  CFile         f;
-  char          S[1000];
-  int           rc,lcount;
-
-    // open file first
-    f.assign ( "/path/example.cif" );
-    if (!f.reset(True))  {
-      printf ( " *** cannot open file '%s' for reading.\n",
-               f.FileName() );
-      return -1;
-    }
-
-    lcount = 0;         // global line counter through the file
-    S[0]   = char(0);   // buffer string
-    while (!f.FileEnd())  {
-
-      rc = mmCIFData.ReadMMCIFData ( f,S,lcount );
-
-      if (rc!=CIFRC_Ok)  {  // error or warning
-        if ((rc<0) && (!f.FileEnd()))  { // error
-          printf ( " *** error reading file %s:\n"
-                   "     %s\n",f.FileName(),GetCIFMessage(S,rc) );
-          return rc;
-        } else if (rc>0)  { // warning
-          printf ( " ... warning on reading file %s:\n"
-                   "     %s\n",f.FileName(),GetCIFMessage(S,rc) );
-        }
-      } else  {
-        // fetch needful values from the data block
-        // ........
-      }
-
-    }
-
-    f.shut();  // close file
-
-    // NOTE: do not delete CMMCIFStruct/CMMCIFLoop
-    // classes obtained from CMMCIFData. If you do, get a crash.
-    // All these structures are containers that dispose their
-    // content automatically.
-    \endcode
-    */
-    int  ReadMMCIFData ( RCFile f, pstr S, int & lcount );
-
-    /// \brief Writes mmCIF data block into file.
-    /// \param FName character null-terminated string with file name
-    /// \param gzipMode flag to read compressed files:
-    /// \arg \b GZM_NONE: do not compress
-    /// \arg \b GZM_CHECK: compress according to file extension
-    /// \arg \b GZM_ENFORCE: same as \b GZM_ENFORCE_GZIP
-    /// \arg \b GZM_ENFORCE_GZIP: compress with gzip
-    /// \arg \b GZM_ENFORCE_COMPRESS: compression with 'compress'.
-    /// \return \b True: no errors
-    /// \return \b False: file cannot be open for writing.
-    Boolean WriteMMCIFData   ( cpstr FName,
-                               byte gzipMode=GZM_CHECK );
-
-    /// \brief Writes (next) mmCIF data block into file.
-    /// \param RCFile reference to a CFile object opened on a file.
-    ///
-    /// This function allows for sequential write of mmCIF data blocks
-    /// into a file.
-    ///
-    /// \note Alternatively, files with multiple data blocks can be
-    /// created using CMMCIFFile class.
-    ///
-    /// Example:
-    /*!
-  \code
-  CFile       f;
-  CMMCIFData  cifData;
-
-    // open file first
-    f.assign ( "/path/example.cif" );
-    if (!f.rewrite())  {
-      printf ( " *** cannot open file '%s' for writing.\n",
-               f.FileName() );
-      return -1;
-    }
-
-    cifData.PutDataName ( "name1" );
-    // fill cifData with all data needed
-    cifData.WriteMMCIF ( f ); // first data block written
-
-    cifData.FreeMemory  ( 0 );  // reset data block to empty
-    cifData.PutDataName ( "name2" );
-    // fill cifData with all data needed
-    cifData.WriteMMCIF ( f );  // second data block written
-
-    // add as many data blocks as needed
-
-    // now close the file
-    f.shut();
-
-  \endcode
-
-    */
-    void  WriteMMCIF ( RCFile f );
-
-
-    // -------- Retrieving data
-
-    /// \brief Returns the number of categories (structures and loops)
-    ///        in data block.
-    int   GetNumberOfCategories ()  { return nCategories; }
-
-    /// \brief Retrieves pointer to category (a structure or a loop) by
-    ///        category number.
-    /// \param categoryNo category number to retrieve. Categories are
-    ///        numbered from 0 to GetNumberOfCategories()-1.
-    /// \return pointer to category, if \b categoryNo is in the right
-    ///        range, or \b NULL otherwise.
-    ///
-    /// \note The category type (structure or loop) is returned by
-    /// function CMMCIFCategory::GetCategoryID().
-    /// \note The application should never attempt to deallocate
-    /// the category returned. It will be properly disposed of by
-    /// CMMCIFData's destructor.
-    PCMMCIFCategory GetCategory ( int categoryNo ); // 0..nCategories-1
-
-    /// \brief Retrieves mmCIF structure with given name.
-    /// \param CName character string with name of the structure (must
-    ///        start with underscore).
-    /// \return pointer to structure if structure with given name was
-    ///        found, and \b NULL otherwise.
-    /// \note The application should never attempt to deallocate
-    /// the structure returned. It will be properly disposed of by
-    /// CMMCIFData's destructor.
-    PCMMCIFStruct GetStructure  ( cpstr CName );
-
-    /// \brief Retrieves mmCIF loop with given name.
-    /// \param CName character string with name of the loop (must
-    ///        start with underscore).
-    /// \return pointer to loop if loop with given name was
-    ///        found, and \b NULL otherwise.
-    /// \note The application should never attempt to deallocate
-    /// the loop returned. It will be properly disposed of by
-    /// CMMCIFData's destructor.
-    PCMMCIFLoop GetLoop ( cpstr CName );
-
-    /// \brief Finds loop containing all tags from the tag list
-    ///        provided.
-    /// \param tagList list of tags to be looked for. The list should
-    ///        be terminated by empty string \"\". The order of tags
-    ///        is not significant.
-    /// \return pointer to loop if loop with given tags was found, and
-    ///         \b NULL otherwise.
-    ///
-    /// The function will look for first loop that includes all tags
-    /// from the list. The list does not have to include all tags for
-    /// that loop in order for function to succeed. This function is
-    /// useful for reading \"dirty cifs\" that may contain loops without
-    /// a name.
-    PCMMCIFLoop FindLoop ( cpstr * tagList );
-
-    /// \brief Retrieves data block name into dynamically-allocated
-    ///        string.
-    /// \param dname pointer reference to a string that accepts data
-    ///        block name. If \b dname is not \b NULL, it is treated
-    ///        as a pre-allocated string, which is disposed before
-    ///        copying. The application is responsible for deallocating
-    ///        \b dname.
-    /// \param Remove flag to remove name from the data block.
-    void GetDataName ( pstr & dname, Boolean Remove=False );
-
-    /// \brief Returns data block name.
-    pstr GetDataName()  { return name; }
-
-    //   CheckData(..) returns positive value if the field is in the
-    // file:
-    //   CIFRC_Structure  category CName is a structure
-    //   CIFRC_Loop       category CName is a loop
-    // Negative returns mean:
-    //   CIFRC_StructureNoTag  category CName is present,
-    //                        it is a structure, but it does not
-    //                        have tag TName
-    //   CIFRC_LoopNoTag       category CName is present,
-    //                        it is a loop, but it does not have
-    //                        tag TName
-    //   CIFRC_NoCategory      category CName is not present.
-    // If TName is set to NULL then only the CName is checked and
-    // possible returns are CIFRC_Structure, CIFRC_Loop and
-    // CIFRC_NoCategory.
-    int  CheckData       ( cpstr CName, cpstr TName );
-
-    int  DeleteCategory  ( cpstr CName );
-    int  DeleteStructure ( cpstr CName );
-    int  DeleteLoop      ( cpstr CName );
-
-    //   Optimize() optimizes the CIF data in memory allocation. It is
-    // a good idea to call it once after extraction of data (GetXXXXXX
-    // functions) with Remove flag set on has been completed.
-    void Optimize();
-
-    //   GetString(..), GetReal(..) and GetInteger(..) return 0 if the
-    // requested field was found and successfully converted. Negative
-    // returns mean:
-    //    CIFRC_WrongFormat   the field was found but failed to convert
-    //                        due to improper numeric format
-    //    CIFRC_NoTag         category CName was found, but it does not
-    //                        have tag TName
-    //    CIFRC_NoCategory    category CName was not found
-    //    CIFRC_NotAStructure category CName was found, but it is
-    //                        a loop rather than a structure.
-    //   GetString(..) will try to dispose Dest unless it is assigned
-    // NULL value before the call. The string will be then dynamically
-    // allocated and copied.
-    //   If Remove is set to True, the field will be removed after
-    // extraction.
-    int  GetString   ( pstr & Dest, cpstr CName, cpstr TName,
-                                    Boolean Remove=False );
-    pstr GetString   ( cpstr CName, cpstr TName, int & RC );
-    int  DeleteField ( cpstr CName, cpstr TName );
-    int  GetReal     ( realtype & R, cpstr CName,
-                       cpstr TName, Boolean Remove=False );
-    int  GetInteger  ( int & I, cpstr CName, cpstr TName,
-                                Boolean Remove=False );
-
-    //   GetLoopLength(..) returns CIFRC_NotALoop if the category CName
-    // is not a loop, CIFRC_NoCategory if the category CName is not
-    // found. Non-negative returns give the length of the loop (may be
-    // 0 if the loop is empty).
-    int  GetLoopLength ( cpstr CName );
-
-    //   GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act
-    // like GetString(..), GetReal(..) and GetInteger(..) above for
-    // nrow-th element of the 'loop_' (indexed like 0..N-1 where N
-    // is obtained through GetLoopLength(..)). They will return
-    // CIFRC_WrongIndex if nrow is out of range.
-    //   If Remove is set to True, the field will be removed after
-    // extraction.
-    int  GetLoopString   ( pstr & Dest, cpstr CName,
-                                        cpstr TName, int nrow,
-                                        Boolean Remove=False );
-    pstr GetLoopString   ( cpstr CName, cpstr TName,
-                           int nrow, int & RC );
-    int  DeleteLoopField ( cpstr CName, cpstr TName,
-                           int nrow );
-    int  GetLoopReal     ( realtype & R, cpstr CName,
-                                         cpstr TName, int nrow,
-                                         Boolean Remove=False );
-    int  GetLoopInteger  ( int & I, cpstr CName,
-                                    cpstr TName, int nrow,
-                                    Boolean Remove=False );
-
-    //   GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..)
-    // read CIF 'loop_' data into allocated vectors of strings, reals
-    // and integers, correspondingly. The vectors may be deallocated
-    // prior to call and assigned NULL, in which case they will be
-    // allocated with offsets of i1, which is also the lower index of
-    // the 'loop_' data transferred into it. The upper vector index is
-    // given by i2 or by the loop's length whichever is less. If
-    // vectors are not assigned NULL prior the call, it is assumed
-    // that they are properly (i1-offset, i2-i1+1 length) allocated.
-    //   The return codes are same as those of GetLoopString(..),
-    // GetLoopReal(..) and GetLoopInteger(..).
-    int  GetLoopSVector ( psvector & S, cpstr CName,
-                          cpstr TName, int i1=0, int i2=MaxInt4,
-                          Boolean Remove=False );
-    int  GetLoopRVector ( rvector  & R, cpstr CName,
-                          cpstr TName, int i1=0, int i2=MaxInt4,
-                          Boolean Remove=False );
-    int  GetLoopIVector ( ivector  & I, cpstr CName,
-                          cpstr TName, int i1=0, int i2=MaxInt4,
-                          Boolean Remove=False );
-
-
-    // -------- Storing data
-
-    //   Unless the data are to be added to the existing CIF structure,
-    // FreeMemory() should be called once before creating a new
-    // CIF data set.
-    void FreeMemory ( int key );
-
-    void PutDataName ( cpstr dname ); // stores name for 'data_'
-                                      // record
-
-    //   PutString(..), PutReal(..) and PutInteger(..) will put the
-    // values given into the specified category (CName) under the
-    // specified tag (TName). The category, tag and field are created
-    // automatically; the field will be replaced silently if identical
-    // CName.TName is specified in two calls. Calls of these functions
-    // may follow in random order; however CIF file will have all tags
-    // grouped by categories and catgories will follow in the order
-    // of first appearance in PutString(..), PutReal(..) or
-    // PutInteger(..).
-    //   Return code - one of CIFRC_Ok or CIFRC_NotAStruct
-    int  PutNoData   ( int NoDataType, cpstr CName,
-                       cpstr TName );
-    int  PutString   ( cpstr S, cpstr CName,
-                       cpstr TName, Boolean Concatenate=False );
-    int  PutDate     ( cpstr CName, cpstr TName );
-    int  PutReal     ( realtype R, cpstr CName, cpstr TName,
-                                   int prec=8 );
-    int  PutInteger  ( int I, cpstr CName, cpstr TName );
-
-    //   If loop category CName is not present in the CIF data
-    // structure, AddLoop(..) creates an empty one and returns
-    // its pointer in Loop. If loop category CName is already in
-    // the CIF data structure, its pointer is returned, and any
-    // data which might be contained in it, remains untouched.
-    //   To stuff the loop with data, first the data tags have to
-    // be specified by calling  Loop->AddLoopTag(..). After all
-    // tags are given, the data comes as a stream of calls
-    // Loop->AddString(..), Loop->AddReal(..) and
-    // Loop->AddInteger(..) which should provide data for every
-    // tag in sequence in strictly the same order as the tags
-    // were given. This essentially reflects reading a CIF loop
-    // from a file.
-    //   Alternatively, the loop data may be stored with PutLoopXXX()
-    // functions given below, although this way may be less
-    // efficient (but more flexible).
-    //   AddLoop(..) may return
-    //     CIFRC_Ok       category was present
-    //     CIFRC_Created  category was not present but it has
-    //                    been created; the category is empty
-    //     CIFRC_NotALoop category was present as a structure, but
-    //                    has been replaced for a loop;
-    //                    the category is empty.
-    int  AddLoop      ( cpstr CName, PCMMCIFLoop   & Loop   );
-    int  AddStructure ( cpstr CName, PCMMCIFStruct & Struct );
-
-    //   PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act
-    // like PutString(..), PutReal(..) and PutInteger(..) above for
-    // nrow-th element of the 'loop_' CName (indexed begining from 0).
-    // In consequitive calls, given values of nrow does not have to be
-    // ordered; the most efficient way is to start with HIGHEST value
-    // for nrow in the loop and move down to 0. The least efficient way
-    // is to start with nrow=0 and move up.
-    //   These functions allow to form loops in arbitrary way.
-    //   The functions may return CIFRC_Ok or CIFRC_NotALoop.
-    int  PutLoopNoData  ( int NoDataType, cpstr CName,
-                                          cpstr TName, int nrow );
-    int  PutLoopString  ( cpstr S,   cpstr CName,
-                                          cpstr TName, int nrow );
-    int  PutLoopReal    ( realtype R, cpstr CName,
-                                      cpstr TName, int nrow,
-                                      int  prec=8 );
-    int  PutLoopInteger ( int I, cpstr CName, cpstr TName,
-                                 int nrow );
-
-    //   PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..)
-    // put vectors of values into specified loop fields. Parameters i1
-    // and i2 give the range of indices of values which are to be
-    // transfered. To transfer an entire vector allocated as [0..N-1]
-    // i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is
-    // always indexed as starting form 0 on, therefore negative i1 and
-    // i2 are not allowed, and specifying i1>0 will leave first i1
-    // elements of the CIF loop for the corresponding tag undefined
-    // (will be output like '?').
-    //   These functions allow to form loops in arbitrary way.
-    int  PutLoopSVector ( psvector S, cpstr CName,
-                          cpstr TName, int i1, int i2 );
-    int  PutLoopRVector ( rvector  R, cpstr CName,
-                          cpstr TName, int i1, int i2,
-                          int prec=8 );
-    int  PutLoopIVector ( ivector  I, cpstr CName,
-                          cpstr TName, int i1, int i2 );
-
-    int  RenameCategory ( cpstr CName, cpstr newCName );
-
-    // --------
-
-    void Copy         ( PCMMCIFData Data );
-    int  CopyCategory ( PCMMCIFData Data, cpstr CName,
-                                          cpstr newCName=NULL );
-
-    void PrintCategories();  // for debuging only
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected:
-    pstr             name;
-    int              nCategories;
-    PPCMMCIFCategory Category;
-    ivector          index;
-    int              flags;
-    int              Warning;
-    int              loopNo;  // used locally for suggesting categories
-    int              tagNo;   // used locally for suggesting tags
-    psvector         WrongCat;
-    psvector         WrongTag;
-    int              nWrongFields;
-
-    void    InitMMCIFData   ();
-    void    FreeWrongFields ();
-    Boolean CheckWrongField ( cpstr C, cpstr T );
-    void    Sort            ();
-
-    //   GetCategoryNo searches for index of category cname
-    // in Category[]. Return:
-    //    >=0 : position of the category found
-    //     <0 : the category was not found, it could be inserted before
-    //          (-RC-1)th element, where RC is the return value
-    int  GetCategoryNo  ( cpstr cname );
-    int  AddCategory    ( cpstr cname );
-    int  DeleteCategory ( int  CatNo );
-
-    void GetDataItem    ( RCFile f, pstr S, pstr & L, pstr & p,
-                                    int & lcount, int & llen );
-    void GetLoop        ( RCFile f, pstr S, pstr & L, pstr & p,
-                                    int & lcount, int & llen );
-    int  GetField       ( RCFile f, pstr S, pstr & L, pstr & p,
-                                    int & lcount, int & llen );
-
-};
-
-
-
-//  ======================  CMMCIFFile  =============================
-
-DefineClass(CMMCIFFile)
-DefineStreamFunctions(CMMCIFFile)
-
-class CMMCIFFile : public CStream  {
-
-  public :
-    int          nData;
-    ivector      index;
-    PPCMMCIFData data;
-
-    CMMCIFFile ();
-    CMMCIFFile ( cpstr FName, byte gzipMode=GZM_CHECK );
-    CMMCIFFile ( RPCStream Object );
-    ~CMMCIFFile();
-
-    void  SetPrintWarnings ( Boolean SPW ) { PrintWarnings = SPW; }
-    void  SetStopOnWarning ( Boolean SOW ) { StopOnWarning = SOW; }
-
-    int   ReadMMCIFFile    ( cpstr FName,byte gzipMode=GZM_CHECK);
-    int   WriteMMCIFFile   ( cpstr FName,byte gzipMode=GZM_CHECK);
-
-    int   GetNofData()  { return nData; }
-    PCMMCIFData GetCIFData ( int   dataNo );  // 0..nData-1
-    PCMMCIFData GetCIFData ( cpstr DName  );
-    int   AddMMCIFData     ( cpstr DName  );
-    int   DeleteMMCIFData  ( cpstr DName  );
-    int   DeleteMMCIFData  ( int   dataNo );
-    int   GetCIFDataNo     ( cpstr DName  );
-
-    void  WriteMMCIF       ( RCFile f    );
-
-    void  Copy  ( PCMMCIFFile File );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected:
-    int     nAllocData;
-    Boolean PrintWarnings;
-    Boolean StopOnWarning;
-
-    void  InitMMCIFFile();
-    void  FreeMemory   ();
-    void  Sort         ();
-    void  ExpandData   ( int nDataNew );
-
-};
-
-extern pstr GetMMCIFInputBuffer ( int & LineNo );
-
-//  isCIF will return
-//    -1   if file FName does not exist
-//     0   if file FName is likely a CIF file ( 'data_' is present )
-//     1   if file FName is not a CIF file ( 'data_' is absent )
-extern int isCIF ( cpstr FName, byte gzipMode=GZM_CHECK );
-extern int isCIF ( RCFile f );
-
-pstr GetCIFMessage ( pstr M, int RC );
-
-
-#endif
-
-
diff --git a/mmdb/mmdb_model.cpp b/mmdb/mmdb_model.cpp
deleted file mode 100755
index e20ec40..0000000
--- a/mmdb/mmdb_model.cpp
+++ /dev/null
@@ -1,5313 +0,0 @@
-//  $Id: mmdb_model.cpp,v 1.27 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    30.04.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Model  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CHetCompound  ( description of het compounds    )
-//       ~~~~~~~~~  CHetCompounds ( HETNAM, HETSYN, FORMULA records )
-//                  CSSContainer  ( container for helixes and turns )
-//                  CHelix        ( helix info                      )
-//                  CStrand       ( strand info                     )
-//                  CSheet        ( sheet info                      )
-//                  CSheets       ( container for sheets            )
-//                  CTurn         ( turn info                       )
-//                  CLinkContainer   ( container for link data      )
-//                  CLink            ( link data                    )
-//                  CLinkRContainer  ( container for refmac link    )
-//                  CLinkR           ( link data                    )
-//                  CCisPepContainer ( container for CisPep data    )
-//                  CCisPep          ( CisPep data                  )
-//                  CModel        ( PDB model                       )
-//
-//  Copyright (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MMDB_Model__
-#include "mmdb_model.h"
-#endif
-
-#ifndef  __MMDB_Manager__
-#include "mmdb_manager.h"
-#endif
-
-#ifndef  __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-
-
-//  ===================  CHetCompound  =========================
-
-
-CHetCompound::CHetCompound ( cpstr HetName ) : CStream()  {
-  InitHetCompound ( HetName );
-}
-
-CHetCompound::CHetCompound ( RPCStream Object ) : CStream(Object)  {
-  InitHetCompound ( pstr("---") );
-}
-
-CHetCompound::~CHetCompound() {
-  FreeMemory();
-}
-
-void  CHetCompound::InitHetCompound ( cpstr HetName )  {
-  strcpy_n0 ( hetID,HetName,sizeof(ResName) );
-  comment    = NULL;
-  nSynonyms  = 0;
-  hetSynonym = NULL;
-  compNum    = MinInt4;
-  wc         = ' ';
-  Formula    = NULL;
-}
-
-void  CHetCompound::FreeMemory()  {
-int i;
-  if (comment)  {
-    delete[] comment;
-    comment = NULL;
-  }
-  if (hetSynonym)  {
-    for (i=0;i<nSynonyms;i++)
-      if (hetSynonym[i])  delete[] hetSynonym[i];
-    delete[] hetSynonym;
-    hetSynonym = NULL;
-  }
-  nSynonyms = 0;
-  if (Formula)  {
-    delete[] Formula;
-    Formula = NULL;
-  }
-}
-
-void  CHetCompound::AddKeyWord ( cpstr W, Boolean Closed )  {
-psvector HS1;
-int      i;
-  if (Closed || (!hetSynonym))  {
-    // first synonym orthe previous synonym was closed by semicolon
-    // -- add a new one
-    HS1 = new pstr[nSynonyms+1];
-    for (i=0;i<nSynonyms;i++)
-      HS1[i] = hetSynonym[i];
-    if (hetSynonym)  delete[] hetSynonym;
-    hetSynonym = HS1;
-    hetSynonym[nSynonyms] = NULL;
-    CreateCopy ( hetSynonym[nSynonyms],W );
-    nSynonyms++;
-  } else  {
-    // just add W to the last synonym
-    CreateConcat ( hetSynonym[nSynonyms-1],pstr(" "),W );
-  }
-}
-
-
-void CHetCompound::HETNAM_PDBDump ( RCFile f )  {
-char S[100];
-pstr p1,p2;
-char c;
-int  N,i;
-
-  if (!comment)  return;
-
-  c = ' ';
-  N  = 0;
-  p1 = comment;
-  do  {
-    N++;
-    if (N==1)  sprintf ( S,"HETNAM     %3s " ,hetID   );
-         else  sprintf ( S,"HETNAM  %2i %3s ",N,hetID );
-    while (*p1==' ')  p1++;
-    p2 = strchr(p1,'\n');
-    if (p2)  {
-      c   = *p2;
-      *p2 = char(0);
-    } else if (strlen(p1)>53)  {
-      i = 0;
-      while (p1[i] && (i<53) && (p1[i]!=' '))  i++;
-      p2  = &(p1[i]);
-      c   = *p2;
-      *p2 = char(0);
-    }
-    if (*p1)  {
-      strcat      ( S,p1 );
-      PadSpaces   ( S,80 );
-      f.WriteLine ( S );
-    } else
-      N--;
-    if (p2)  {
-      *p2 = c;
-      if (c)  p1 = p2+1;
-        else  p2 = NULL;
-    }
-  } while (p2);
-
-}
-
-
-void CHetCompound::HETSYN_PDBDump ( RCFile f )  {
-char S[100];
-pstr p;
-char c;
-int  N,k,i,l;
-  if (!hetSynonym)  return;
-  N = 0;
-  k = 0;
-  p = &(hetSynonym[0][0]);
-  do  {
-    N++;
-    if (N==1)  sprintf ( S,"HETSYN     %3s " ,hetID   );
-         else  sprintf ( S,"HETSYN  %2i %3s ",N,hetID );
-    i = 0;
-    do  {
-      l = strlen(p)+2;
-      if (i+l<54)  {
-        strcat ( S,p );
-        if (k<nSynonyms-1) strcat ( S,"; " );
-        k++;
-        i += l;
-        if (k<nSynonyms)  p = &(hetSynonym[k][0]);
-                    else  i = 60;  // break loop
-      } else  {
-        if (i==0)  {
-          // too long synonym, has to be split over several lines
-          i = l-3;
-          while (i>51)  {
-            i--;
-            while ((i>0) && (p[i]!=' '))  i--;
-          }
-          if (i<2)  i = 51;  // no spaces!
-          c    = p[i];
-          p[i] = char(0);
-          strcat ( S,p );
-          p[i] = c;
-          p    = &(p[i]);
-          while (*p==' ')  p++;
-        }
-        i = 60;  // break loop
-      }
-    } while (i<54);
-    PadSpaces ( S,80 );
-    f.WriteLine ( S );
-  } while (k<nSynonyms);
-}
-
-
-void CHetCompound::FORMUL_PDBDump ( RCFile f )  {
-char S[100];
-pstr p1,p2;
-char c;
-int  N,i;
-  if (!Formula)  return;
-  N  = 0;
-  p1 = Formula;
-  do  {
-    N++;
-    if (compNum>MinInt4)  {
-      if (N==1)  sprintf ( S,"FORMUL  %2i  %3s    " ,compNum,hetID   );
-           else  sprintf ( S,"FORMUL  %2i  %3s %2i ",compNum,hetID,N );
-    } else  {
-      if (N==1)  sprintf ( S,"FORMUL      %3s    " ,hetID   );
-           else  sprintf ( S,"FORMUL      %3s %2i ",hetID,N );
-    }
-    S[18] = wc;
-    p2 = strchr(p1,'\n');
-    if (p2)  {
-      c   = *p2;
-      *p2 = char(0);
-    } else if (strlen(p1)>50)  {
-      while (*p1==' ')  p1++;
-      i = 0;
-      while (p1[i] && (i<50) && (p1[i]!=' '))  i++;
-      p2  = &(p1[i]);
-      c   = *p2;
-      *p2 = char(0);
-    }
-    strcat ( S,p1 );
-    if (p2)  {
-      *p2 = c;
-      p1  = p2+1;
-    }
-    PadSpaces ( S,80 );
-    f.WriteLine ( S );
-  } while (p2);
-}
-
-
-void  CHetCompound::FormComString ( pstr & F )  {
-pstr p;
-int  i;
-  if (F)  {
-    delete[] F;
-    F = NULL;
-  }
-  if (comment)  {
-    CreateCopy ( F,comment );
-    i = 0;
-    p = comment;
-    while (*p)  {
-      p++;
-      if (*p=='\n')  i = 0;
-               else  i++;
-      if (i>68)  {
-        F[i] = char(0);
-        CreateConcat ( F,pstr("\n"),p );
-        i = 0;
-      }
-    }
-  }
-}
-
-
-void  CHetCompound::FormSynString ( pstr & F )  {
-pstr p;
-char c;
-int  i,k,l;
-  if (F)  {
-    delete[] F;
-    F = NULL;
-  }
-  if (hetSynonym)  {
-    CreateCopy ( F,pstr("  ") );
-    k = 0;
-    p = &(hetSynonym[0][0]);
-    do  {
-      l = strlen(p)+2;
-      if (l<=60)  {
-        if (k<nSynonyms-1)  CreateConcat ( F,p,pstr(";\n  ") );
-                      else  CreateConcat ( F,p );
-        k++;
-        if (k<nSynonyms)  p = &(hetSynonym[k][0]);
-      } else  {
-        // too long synonym, has to be split over several lines
-        i = l-3;
-        while (i>60)  {
-          i--;
-          while ((i>0) && (p[i]!=' '))  i--;
-        }
-        if (i<2)  i = 60;  // no spaces!
-        c    = p[i];
-        p[i] = char(0);
-        CreateConcat ( F,p,pstr("\n  ") );
-        p[i] = c;
-        p    = &(p[i]);
-        while (*p==' ')  p++;
-      }
-    } while (k<nSynonyms);
-  }
-}
-
-void  CHetCompound::FormForString ( pstr & F )  {
-pstr p;
-int  i;
-  if (F)  {
-    delete[] F;
-    F = NULL;
-  }
-  if (Formula)  {
-    CreateCopy ( F,Formula );
-    i = 0;
-    p = &(Formula[0]);
-    while (*p)  {
-      p++;
-      if (*p=='\n')  i = 0;
-               else  i++;
-      if (i>68)  {
-        F[i] = char(0);
-        CreateConcat ( F,pstr("\n"),p );
-        i = 0;
-      }
-    }
-  }
-}
-
-
-void  CHetCompound::Copy ( PCHetCompound HetCompound )  {
-int i;
-  FreeMemory ();
-  strcpy     ( hetID  ,HetCompound->hetID   );
-  CreateCopy ( comment,HetCompound->comment );
-  nSynonyms = HetCompound->nSynonyms;
-  if (nSynonyms>0) {
-    hetSynonym = new pstr[nSynonyms];
-    for (i=0;i<nSynonyms;i++)  {
-      hetSynonym[i] = NULL;
-      CreateCopy ( hetSynonym[i],HetCompound->hetSynonym[i] );
-    }
-  }
-  compNum = HetCompound->compNum;
-  wc      = HetCompound->wc;
-  CreateCopy ( Formula,HetCompound->Formula );
-}
-
-void  CHetCompound::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte    ( &Version    );
-  f.WriteTerLine ( hetID,False );
-  f.CreateWrite  ( comment     );
-  f.WriteInt     ( &nSynonyms  );
-  for (i=0;i<nSynonyms;i++)
-    f.CreateWrite ( hetSynonym[i] );
-  f.WriteInt    ( &compNum       );
-  f.WriteFile   ( &wc,sizeof(wc) );
-  f.CreateWrite ( Formula        );
-}
-
-void  CHetCompound::read ( RCFile f )  {
-int  i;
-byte Version;
-  FreeMemory();
-  f.ReadByte    ( &Version    );
-  f.ReadTerLine ( hetID,False );
-  f.CreateRead  ( comment     );
-  f.ReadInt     ( &nSynonyms  );
-  if (nSynonyms>0) {
-    hetSynonym = new pstr[nSynonyms];
-    for (i=0;i<nSynonyms;i++)  {
-      hetSynonym[i] = NULL;
-      f.CreateRead ( hetSynonym[i] );
-    }
-  }
-  f.ReadInt    ( &compNum       );
-  f.ReadFile   ( &wc,sizeof(wc) );
-  f.CreateRead ( Formula        );
-}
-
-MakeStreamFunctions(CHetCompound)
-
-
-//  ====================  CHetCompounds  =======================
-
-
-CHetCompounds::CHetCompounds() : CStream()  {
-  InitHetCompounds();
-}
-
-CHetCompounds::CHetCompounds ( RPCStream Object ) : CStream(Object)  {
-  InitHetCompounds();
-}
-
-CHetCompounds::~CHetCompounds() {
-  FreeMemory();
-}
-
-void  CHetCompounds::InitHetCompounds()  {
-  nHets       = 0;
-  hetCompound = NULL;
-  Closed      = False;
-}
-
-void  CHetCompounds::FreeMemory()  {
-int i;
-  if (hetCompound)  {
-    for (i=0;i<nHets;i++)
-      if (hetCompound[i])  delete hetCompound[i];
-    delete[] hetCompound;
-    hetCompound = NULL;
-  }
-  nHets = 0;
-}
-
-void  CHetCompounds::ConvertHETNAM ( cpstr S )  {
-ResName hetID;
-char    L[100];
-int     l,i;
-  l = strlen(S);
-  if (l>12)  {
-    strcpy_n0 ( hetID,&(S[11]),3 );
-    i = AddHetName ( hetID );
-    if (l>15)  {
-      if (hetCompound[i]->comment)  strcpy ( L,"\n" );
-                              else  L[0] = char(0);
-      strcat       ( L,&(S[15])    );
-      CutSpaces    ( L,SCUTKEY_END );
-      CreateConcat ( hetCompound[i]->comment,L );
-    }
-  }
-}
-
-void  CHetCompounds::ConvertHETSYN ( cpstr S )  {
-ResName hetID;
-char    L[100];
-int     l,i,j,k;
-  l = strlen(S);
-  if (l>12)  {
-    strcpy_n0 ( hetID,&(S[11]),3 );
-    i = AddHetName ( hetID );
-    if (l>15)  {
-      j = 15;
-      do {
-        while (S[j]==' ')  j++;
-        k = 0;
-        if (S[j])  {
-          while (S[j] && (S[j]!=';'))
-            L[k++] = S[j++];
-          L[k--] = char(0);
-          while ((k>0) && (L[k]==' '))  L[k--] = char(0);
-          if (L[0])  {
-            hetCompound[i]->AddKeyWord ( L,Closed );
-            Closed = (S[j]==';');
-          }
-          if (S[j])  j++;
-        }
-      } while (S[j]);
-      /*
-      p1 = &(S[15]);
-      do  {
-        p2 = strchr ( p1,';' );
-        if (p2)  {
-          c   = *p2;
-          *p2 = char(0);
-        }
-        strcpy_css ( L,p1 );
-        if (L[0])
-          hetCompound[i]->AddKeyWord ( L,Closed );
-        if (p2) {
-          if (L[0]) Closed = True;
-          *p2 = c;
-          p1 = p2+1;
-        } else if (L[0])
-          Closed = False;
-      } while (p2);
-      */
-    }
-  }
-}
-
-void  CHetCompounds::ConvertFORMUL ( cpstr S )  {
-ResName hetID;
-char    L[100];
-int     l,i;
-  l = strlen(S);
-  if (l>13)  {
-    strcpy_n0 ( hetID,&(S[12]),3 );
-    i = AddHetName ( hetID );
-    if (l>18) {
-      GetInteger ( hetCompound[i]->compNum,&(S[9]),2 );
-      hetCompound[i]->wc = S[18];
-      if (strlen(S)>19)  {
-        if (hetCompound[i]->Formula)  strcpy ( L,"\n" );
-                                else  L[0] = char(0);
-        strcat       ( L,&(S[19])    );
-        CutSpaces    ( L,SCUTKEY_END );
-        CreateConcat ( hetCompound[i]->Formula,L );
-      }
-    }
-  }
-}
-int  CHetCompounds::AddHetName ( cpstr H )  {
-PPCHetCompound HC1;
-int            i;
-  i = 0;
-  while (i<nHets)  {
-    if (hetCompound[i])  {
-      if (!strcmp(hetCompound[i]->hetID,H))  break;
-    }
-    i++;
-  }
-  if (i>=nHets)  {
-    HC1 = new PCHetCompound[nHets+1];
-    for (i=0;i<nHets;i++)
-      HC1[i] = hetCompound[i];
-    if (hetCompound)  delete[] hetCompound;
-    hetCompound = HC1;
-    hetCompound[nHets] = new CHetCompound ( H );
-    i = nHets;
-    nHets++;
-  }
-  return i;
-}
-
-void CHetCompounds::PDBASCIIDump ( RCFile f )  {
-int  i;
-
-  for (i=0;i<nHets;i++)
-    if (hetCompound[i])
-      hetCompound[i]->HETNAM_PDBDump ( f );
-
-  for (i=0;i<nHets;i++)
-    if (hetCompound[i])
-      hetCompound[i]->HETSYN_PDBDump ( f );
-
-  for (i=0;i<nHets;i++)
-    if (hetCompound[i])
-      hetCompound[i]->FORMUL_PDBDump ( f );
-
-}
-
-
-void  CHetCompounds::MakeCIF ( PCMMCIFData CIF )  {
-PCMMCIFLoop Loop;
-pstr        F;
-int         RC;
-int         i;
-
-  if (!hetCompound)  return;
-
-  RC = CIF->AddLoop ( CIFCAT_CHEM_COMP,Loop );
-  if (RC!=CIFRC_Ok)  {
-    Loop->AddLoopTag ( CIFTAG_ID               );
-    Loop->AddLoopTag ( CIFTAG_NAME             );
-    Loop->AddLoopTag ( CIFTAG_NDB_SYNONYMS     );
-    Loop->AddLoopTag ( CIFTAG_NDB_COMPONENT_NO );
-    Loop->AddLoopTag ( CIFTAG_FORMULA          );
-  }
-
-  F = NULL;
-  for (i=0;i<nHets;i++)
-    if (hetCompound[i])  {
-      Loop->AddString ( hetCompound[i]->hetID );
-      hetCompound[i]->FormComString ( F );
-      Loop->AddString ( F );
-      hetCompound[i]->FormSynString ( F );
-      Loop->AddString ( F );
-      if (hetCompound[i]->compNum>MinInt4)
-            Loop->AddInteger ( hetCompound[i]->compNum );
-      else  Loop->AddNoData  ( CIF_NODATA_QUESTION     );
-      hetCompound[i]->FormForString ( F );
-      Loop->AddString ( F );
-    }
-
-  if (F)  delete[] F;
-
-}
-
-void  CHetCompounds::GetCIF ( PCMMCIFData CIF )  {
-PCMMCIFLoop Loop;
-char        L[100];
-ResName     hetID;
-pstr        F,p1,p2;
-char        c;
-int         i,l,k,RC;
-
-  FreeMemory();
-
-  Loop = CIF->GetLoop ( CIFCAT_CHEM_COMP );
-  if (!Loop)  return;
-
-  l = Loop->GetLoopLength();
-  F = NULL;
-
-  for (i=0;i<l;i++)  {
-    CIFGetString    ( hetID,Loop,CIFTAG_ID,i,sizeof(hetID),
-                      pstr("---") );
-    k = AddHetName  ( hetID );
-    Loop->GetString ( hetCompound[k]->comment,CIFTAG_NAME,i,True );
-    RC = Loop->GetInteger ( hetCompound[k]->compNum,
-                                     CIFTAG_NDB_COMPONENT_NO,i,True );
-    if (RC)  hetCompound[i]->compNum = MinInt4;
-    Loop->GetString ( hetCompound[k]->Formula,CIFTAG_FORMULA,i,True );
-    RC = Loop->GetString ( F,CIFTAG_NDB_SYNONYMS,i,True );
-    if ((!RC) && F )  {
-      p1 = &(F[0]);
-      while (*p1)  {
-        if (*p1=='\n')  *p1 = ' ';
-        p1++;
-      }
-      p1 = &(F[0]);
-      do  {
-        p2 = strchr ( p1,';' );
-        if (p2)  {
-          c   = *p2;
-          *p2 = char(0);
-        }
-        strcpy_css ( L,p1 );
-        hetCompound[i]->AddKeyWord ( L,True );
-        if (p2) {
-          *p2 = c;
-          p1 = p2+1;
-        }
-      } while (p2);
-    }
-    hetCompound[i]->wc = ' ';
-  }
-
-//  CIF->DeleteLoop ( CIFCAT_CHEM_COMP );
-
-  if (F)  delete[] F;
-
-}
-
-void  CHetCompounds::Copy ( PCHetCompounds HetCompounds )  {
-int i;
-  FreeMemory();
-  nHets = HetCompounds->nHets;
-  if (nHets>0)  {
-    hetCompound = new PCHetCompound[nHets];
-    for (i=0;i<nHets;i++)  {
-      hetCompound[i] = new CHetCompound ( "" );
-      hetCompound[i]->Copy ( HetCompounds->hetCompound[i] );
-    }
-  }
-}
-
-void  CHetCompounds::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte ( &Version );
-  f.WriteInt  ( &nHets   );
-  for (i=0;i<nHets;i++)
-    hetCompound[i]->write ( f );
-}
-
-void  CHetCompounds::read ( RCFile f )  {
-int  i;
-byte Version;
-  FreeMemory();
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &nHets   );
-  if (nHets>0)  {
-    hetCompound = new PCHetCompound[nHets];
-    for (i=0;i<nHets;i++)  {
-      hetCompound[i] = new CHetCompound ( "---" );
-      hetCompound[i]->read ( f );
-    }
-  }
-}
-
-MakeStreamFunctions(CHetCompounds)
-
-
-
-//  ====================  CSSContainer  =========================
-
-PCContainerClass CSSContainer::MakeContainerClass ( int ClassID )  {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template : return
-                        CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_Helix    : return new CHelix();
-    case ClassID_Turn     : return new CTurn ();
-  }
-}
-
-MakeStreamFunctions(CSSContainer)
-
-
-
-//  ================  CHelix  ===================
-
-CHelix::CHelix() : CContainerClass()  {
-  InitHelix();
-}
-
-CHelix::CHelix ( cpstr S ) : CContainerClass()  {
-  InitHelix();
-  ConvertPDBASCII ( S );
-}
-
-CHelix::CHelix ( RPCStream Object ) : CContainerClass(Object)  {
-  InitHelix();
-}
-
-CHelix::~CHelix() {
-  if (comment)  delete[] comment;
-}
-
-void  CHelix::InitHelix()  {
-
-  serNum = 0;                   // serial number
-  strcpy ( helixID    ,"---" ); // helix ID
-  strcpy ( initResName,"---" ); // name of the helix's initial residue
-  strcpy ( initChainID,""    ); // chain ID for the chain
-                                // containing the helix
-  initSeqNum = 0;               // sequence number of the initial
-                                //    residue
-  strcpy ( initICode  ,""    ); // insertion code of the initial
-                                //    residue
-  strcpy ( endResName ,"---" ); // name of the helix's terminal residue
-  strcpy ( endChainID ,""    ); // chain ID for the chain
-                                // containing the helix
-  endSeqNum  = 0;               // sequence number of the terminal
-                                //    residue
-  strcpy ( endICode   ,""    ); // insertion code of the terminal
-                                //    residue
-  helixClass = 0;               // helix class
-  comment    = NULL;            // comment about the helix
-  length     = 0;               // length of the helix
-
-}
-
-void  CHelix::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB OBSLTE line number N
-//  from the class' data
-  strcpy     ( S,"HELIX" );
-  PadSpaces  ( S,80 );
-  PutInteger ( &(S[7]) ,serNum     ,3  );
-  strcpy_n1  ( &(S[11]),helixID    ,3  );
-  strcpy_n1  ( &(S[15]),initResName,3  );
-  if (initChainID[0])  S[19] = initChainID[0];
-  PutIntIns  ( &(S[21]),initSeqNum ,4,initICode );
-  strcpy_n1  ( &(S[27]),endResName ,3  );
-  if (endChainID[0])   S[31] = endChainID[0];
-  PutIntIns  ( &(S[33]),endSeqNum  ,4,endICode  );
-  PutInteger ( &(S[38]),helixClass ,2  );
-  if (comment)
-    strcpy_n ( &(S[40]),comment    ,30 );
-  PutInteger ( &(S[71]),length     ,5  );
-}
-
-void AddStructConfTags ( PCMMCIFLoop Loop )  {
-  Loop->AddLoopTag ( CIFTAG_CONF_TYPE_ID               );
-  Loop->AddLoopTag ( CIFTAG_ID                         );
-  Loop->AddLoopTag ( CIFTAG_PDB_ID                     );
-  Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID          );
-  Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID          );
-  Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID           );
-  Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
-  Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID          );
-  Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID          );
-  Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID           );
-  Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
-  Loop->AddLoopTag ( CIFTAG_NDB_HELIX_CLASS_PDB        );
-  Loop->AddLoopTag ( CIFTAG_DETAILS                    );
-  Loop->AddLoopTag ( CIFTAG_NDB_LENGTH                 );
-}
-
-#define  HelixTypeID  "HELX_P"
-
-void  CHelix::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop;
-int         RC;
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
-  if (RC!=CIFRC_Ok)
-    // the category was (re)created, provide tags
-    AddStructConfTags ( Loop );
-  Loop->AddString  ( pstr(HelixTypeID) );
-  Loop->AddInteger ( serNum      );
-  Loop->AddString  ( helixID     );
-  Loop->AddString  ( initResName );
-  Loop->AddString  ( initChainID );
-  Loop->AddInteger ( initSeqNum  );
-  Loop->AddString  ( initICode,True );
-  Loop->AddString  ( endResName  );
-  Loop->AddString  ( endChainID  );
-  Loop->AddInteger ( endSeqNum   );
-  Loop->AddString  ( endICode ,True );
-  Loop->AddInteger ( helixClass  );
-  Loop->AddString  ( comment     );
-  Loop->AddInteger ( length      );
-}
-
-int CHelix::ConvertPDBASCII ( cpstr S )  {
-char L[100];
-  GetInteger  ( serNum     ,&(S[7]) ,3  );
-  strcpy_ncss ( helixID    ,&(S[11]),3  );
-  strcpy_ncss ( initResName,&(S[15]),3  );
-  strcpy_ncss ( initChainID,&(S[19]),1  );
-  GetIntIns   ( initSeqNum,initICode,&(S[21]),4  );
-  strcpy_ncss ( endResName ,&(S[27]),3  );
-  strcpy_ncss ( endChainID ,&(S[31]),1  );
-  GetIntIns   ( endSeqNum ,endICode ,&(S[33]),4  );
-  GetInteger  ( helixClass ,&(S[38]),2  );
-  strcpy_ncss ( L          ,&(S[40]),30 );
-  CreateCopy  ( comment    ,L           );
-  GetInteger  ( length     ,&(S[71]),5  );
-  return 0;
-}
-
-void  CHelix::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-int         RC,l;
-pstr        F;
-Boolean     Done;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-
-  l    = Loop->GetLoopLength();
-  Done = Signal>=l;
-  while (!Done) {
-    F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,Signal,RC );
-    if ((!RC) && F)  Done = (strcmp(F,HelixTypeID)==0);
-               else  Done = False;
-    if (!Done)  {
-      Signal++;
-      Done = Signal>=l;
-    }
-  }
-
-  if (Signal>=l)  {
-    Signal = -1;  // finish processing of Helix
-    return;
-  }
-
-  Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,Signal );
-
-  if (CIFGetInteger(serNum,Loop,CIFTAG_ID,Signal)) return;
-
-
-  CIFGetString ( helixID    ,Loop,CIFTAG_PDB_ID,
-                             Signal,sizeof(helixID),pstr("   ") );
-
-  CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
-                             Signal,sizeof(initResName),pstr("   ") );
-  CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
-                             Signal,sizeof(initChainID),pstr("") );
-  CIFGetString ( initICode  ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
-                             Signal,sizeof(initICode),pstr("") );
-  if (CIFGetInteger(initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,Signal))
-    return;
-
-  CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
-                            Signal,sizeof(endResName),pstr("   ") );
-  CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
-                            Signal,sizeof(endChainID),pstr("") );
-  CIFGetString ( endICode  ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
-                            Signal,sizeof(endICode),pstr("") );
-  if (CIFGetInteger(endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,Signal))
-    return;
-
-  if (CIFGetInteger(helixClass,Loop,
-                    CIFTAG_NDB_HELIX_CLASS_PDB,Signal)) return;
-  CreateCopy     ( comment,Loop->GetString(CIFTAG_DETAILS,Signal,RC));
-  Loop->DeleteField ( CIFTAG_DETAILS,Signal );
-  if (CIFGetInteger(length,Loop,CIFTAG_NDB_LENGTH,Signal)) return;
-
-  Signal++;
-
-}
-
-void  CHelix::Copy ( PCContainerClass Helix )  {
-  serNum     = PCHelix(Helix)->serNum;
-  initSeqNum = PCHelix(Helix)->initSeqNum;
-  endSeqNum  = PCHelix(Helix)->endSeqNum;
-  helixClass = PCHelix(Helix)->helixClass;
-  length     = PCHelix(Helix)->length;
-  strcpy ( helixID    ,PCHelix(Helix)->helixID     );
-  strcpy ( initResName,PCHelix(Helix)->initResName );
-  strcpy ( initChainID,PCHelix(Helix)->initChainID );
-  strcpy ( initICode  ,PCHelix(Helix)->initICode   );
-  strcpy ( endResName ,PCHelix(Helix)->endResName  );
-  strcpy ( endChainID ,PCHelix(Helix)->endChainID  );
-  strcpy ( endICode   ,PCHelix(Helix)->endICode    );
-  CreateCopy ( comment,PCHelix(Helix)->comment );
-}
-
-void  CHelix::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version    );
-  f.WriteInt  ( &serNum     );
-  f.WriteInt  ( &initSeqNum );
-  f.WriteInt  ( &endSeqNum  );
-  f.WriteInt  ( &helixClass );
-  f.WriteInt  ( &length     );
-  f.WriteTerLine ( helixID    ,False );
-  f.WriteTerLine ( initResName,False );
-  f.WriteTerLine ( initChainID,False );
-  f.WriteTerLine ( initICode  ,False );
-  f.WriteTerLine ( endResName ,False );
-  f.WriteTerLine ( endChainID ,False );
-  f.WriteTerLine ( endICode   ,False );
-  f.CreateWrite ( comment );
-}
-
-void  CHelix::read  ( RCFile f ) {
-byte Version;
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &serNum     );
-  f.ReadInt  ( &initSeqNum );
-  f.ReadInt  ( &endSeqNum  );
-  f.ReadInt  ( &helixClass );
-  f.ReadInt  ( &length     );
-  f.ReadTerLine ( helixID    ,False );
-  f.ReadTerLine ( initResName,False );
-  f.ReadTerLine ( initChainID,False );
-  f.ReadTerLine ( initICode  ,False );
-  f.ReadTerLine ( endResName ,False );
-  f.ReadTerLine ( endChainID ,False );
-  f.ReadTerLine ( endICode   ,False );
-  f.CreateRead ( comment );
-}
-
-MakeStreamFunctions(CHelix)
-
-
-
-//  ================  CStrand  =====================
-
-CStrand::CStrand () : CStream()  {
-  InitStrand();
-}
-
-CStrand::CStrand ( RPCStream Object ) : CStream(Object)  {
-  InitStrand();
-}
-
-CStrand::~CStrand() {
-}
-
-void  CStrand::InitStrand()  {
-  initSeqNum = MinInt4;
-  endSeqNum  = MinInt4;
-  sense      = 0;
-  curResSeq  = MinInt4;
-  prevResSeq = MinInt4;
-  strandNo   = 0;
-  strcpy ( sheetID    ,"sheet_0"  );
-  strcpy ( initResName,"   "      );
-  strcpy ( initChainID,""         );
-  strcpy ( initICode  ,""         );
-  strcpy ( endResName ,"   "      );
-  strcpy ( endChainID ,""         );
-  strcpy ( endICode   ,""         );
-  strcpy ( curAtom    ," "        );
-  strcpy ( curResName ,"   "      );
-  strcpy ( curChainID ,""         );
-  strcpy ( curICode   ,""         );
-  strcpy ( prevAtom   ," "        );
-  strcpy ( prevResName,"   "      );
-  strcpy ( prevChainID,""         );
-  strcpy ( prevICode  ,""         );
-}
-
-void  CStrand::PDBASCIIDump ( pstr S )  {
-//   Finishes making the ASCII PDB SHEET line number N
-// from the class' data. Making is initiated by CSheet.
-
-  strcpy_n1  ( &(S[17]),initResName,3 );
-  if (initChainID[0])  S[21] = initChainID[0];
-  PutIntIns  ( &(S[22]),initSeqNum ,4,initICode );
-
-  strcpy_n1  ( &(S[28]),endResName ,3 );
-  if (endChainID[0])   S[32] = endChainID[0];
-  PutIntIns  ( &(S[33]),endSeqNum  ,4,endICode  );
-
-  PutInteger ( &(S[38]),sense      ,2 );
-
-  strcpy_n1  ( &(S[41]),curAtom    ,4 );
-  strcpy_n1  ( &(S[45]),curResName ,3 );
-  if (curChainID[0])   S[49] = curChainID[0];
-  PutIntIns  ( &(S[50]),curResSeq  ,4,curICode  );
-
-  strcpy_n1  ( &(S[56]),prevAtom   ,4 );
-  strcpy_n1  ( &(S[60]),prevResName,3 );
-  if (prevChainID[0])  S[64] = prevChainID[0];
-  PutIntIns  ( &(S[65]),prevResSeq ,4,prevICode );
-
-}
-
-
-void  CStrand::MakeCIF ( PCMMCIFData CIF )  {
-PCMMCIFLoop Loop;
-int         RC;
-
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_RANGE,Loop );
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_SHEET_ID                   );
-    Loop->AddLoopTag ( CIFTAG_ID                         );
-    Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID          );
-    Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID          );
-    Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID           );
-    Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
-    Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID          );
-    Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID          );
-    Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID           );
-    Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
-  }
-  Loop->AddString  ( sheetID     );
-  Loop->AddInteger ( strandNo    );
-  Loop->AddString  ( initResName );
-  Loop->AddString  ( initChainID );
-  Loop->AddInteger ( initSeqNum  );
-  Loop->AddString  ( initICode,True );
-  Loop->AddString  ( endResName  );
-  Loop->AddString  ( endChainID  );
-  Loop->AddInteger ( endSeqNum   );
-  Loop->AddString  ( endICode ,True );
-
-}
-
-
-int CStrand::ConvertPDBASCII ( cpstr S )  {
-
-  GetInteger  ( strandNo   ,&(S[7])  ,3 );
-  strcpy_ncss ( sheetID    ,&(S[11]) ,3 );
-
-  strcpy_ncss ( initResName,&(S[17]) ,3 );
-  strcpy_ncss ( initChainID,&(S[21]) ,1 );
-  GetIntIns   ( initSeqNum ,initICode,&(S[22]),4 );
-
-  strcpy_ncss ( endResName ,&(S[28]) ,3 );
-  strcpy_ncss ( endChainID ,&(S[32]) ,1 );
-  GetIntIns   ( endSeqNum  ,endICode ,&(S[33]),4 );
-
-  GetInteger  ( sense      ,&(S[38]) ,2 );
-
-  GetString   ( curAtom    ,&(S[41]) ,4 );
-  strcpy_ncss ( curResName ,&(S[45]) ,3 );
-  strcpy_ncss ( curChainID ,&(S[49]) ,1 );
-  GetIntIns   ( curResSeq  ,curICode ,&(S[50]),4 );
-
-  GetString   ( prevAtom   ,&(S[56]) ,4 );
-  strcpy_ncss ( prevResName,&(S[60]) ,3 );
-  strcpy_ncss ( prevChainID,&(S[64]) ,1 );
-  GetIntIns   ( prevResSeq ,prevICode,&(S[65]),4 );
-
-  return 0;
-
-}
-
-int  CStrand::GetCIF ( PCMMCIFData CIF, cpstr sheet_id )  {
-PCMMCIFLoop Loop;
-int         RC,l,i,sNo;
-pstr        F;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_RANGE );
-  if (Loop)  {
-    l = Loop->GetLoopLength();
-    i = 0;
-    while (i<l)  {
-      F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
-      if (F && (!RC))  {
-        if (!strcmp(F,sheet_id))  {
-          strcpy ( sheetID,sheet_id );
-          if (CIFGetInteger(sNo,Loop,CIFTAG_ID,i))  return i;
-          if (sNo==strandNo)  {
-            CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
-                           i,sizeof(initResName),pstr("   ") );
-            CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
-                           i,sizeof(initChainID),pstr("") );
-            CIFGetString ( initICode,Loop,
-                           CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
-                           i,sizeof(initICode),pstr("") );
-            if (CIFGetInteger(initSeqNum,Loop,
-                           CIFTAG_BEG_LABEL_SEQ_ID,i))
-              return i;
-            CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
-                           i,sizeof(endResName),pstr("   ") );
-            CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
-                           i,sizeof(endChainID),pstr("") );
-            CIFGetString ( endICode  ,Loop,
-                           CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
-                           i,sizeof(endICode),pstr("") );
-            if (CIFGetInteger(endSeqNum,Loop,
-                           CIFTAG_END_LABEL_SEQ_ID,i))
-              return i;
-            Loop->DeleteRow ( i );
-            i = l+100;  // break the loop
-          }
-        }
-      }
-      i++;
-    }
-  }
-
-  return 0;
-
-}
-
-void  CStrand::Copy ( PCStrand Strand )  {
-  initSeqNum = Strand->initSeqNum;
-  endSeqNum  = Strand->endSeqNum;
-  sense      = Strand->sense;
-  curResSeq  = Strand->curResSeq;
-  prevResSeq = Strand->prevResSeq;
-  strcpy ( initResName,Strand->initResName );
-  strcpy ( initChainID,Strand->initChainID );
-  strcpy ( initICode  ,Strand->initICode   );
-  strcpy ( endResName ,Strand->endResName  );
-  strcpy ( endChainID ,Strand->endChainID  );
-  strcpy ( endICode   ,Strand->endICode    );
-  strcpy ( curAtom    ,Strand->curAtom     );
-  strcpy ( curResName ,Strand->curResName  );
-  strcpy ( curChainID ,Strand->curChainID  );
-  strcpy ( curICode   ,Strand->curICode    );
-  strcpy ( prevAtom   ,Strand->prevAtom    );
-  strcpy ( prevResName,Strand->prevResName );
-  strcpy ( prevChainID,Strand->prevChainID );
-  strcpy ( prevICode  ,Strand->prevICode   );
-}
-
-void  CStrand::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version    );
-  f.WriteInt  ( &initSeqNum );
-  f.WriteInt  ( &endSeqNum  );
-  f.WriteInt  ( &sense      );
-  f.WriteInt  ( &curResSeq  );
-  f.WriteInt  ( &prevResSeq );
-  f.WriteTerLine ( initResName,False );
-  f.WriteTerLine ( initChainID,False );
-  f.WriteTerLine ( initICode  ,False );
-  f.WriteTerLine ( endResName ,False );
-  f.WriteTerLine ( endChainID ,False );
-  f.WriteTerLine ( endICode   ,False );
-  f.WriteTerLine ( curAtom    ,False );
-  f.WriteTerLine ( curResName ,False );
-  f.WriteTerLine ( curChainID ,False );
-  f.WriteTerLine ( curICode   ,False );
-  f.WriteTerLine ( prevAtom   ,False );
-  f.WriteTerLine ( prevResName,False );
-  f.WriteTerLine ( prevChainID,False );
-  f.WriteTerLine ( prevICode  ,False );
-}
-
-void  CStrand::read  ( RCFile f ) {
-byte Version;
-  f.ReadByte ( &Version    );
-  f.ReadInt  ( &initSeqNum );
-  f.ReadInt  ( &endSeqNum  );
-  f.ReadInt  ( &sense      );
-  f.ReadInt  ( &curResSeq  );
-  f.ReadInt  ( &prevResSeq );
-  f.ReadTerLine ( initResName,False );
-  f.ReadTerLine ( initChainID,False );
-  f.ReadTerLine ( initICode  ,False );
-  f.ReadTerLine ( endResName ,False );
-  f.ReadTerLine ( endChainID ,False );
-  f.ReadTerLine ( endICode   ,False );
-  f.ReadTerLine ( curAtom    ,False );
-  f.ReadTerLine ( curResName ,False );
-  f.ReadTerLine ( curChainID ,False );
-  f.ReadTerLine ( curICode   ,False );
-  f.ReadTerLine ( prevAtom   ,False );
-  f.ReadTerLine ( prevResName,False );
-  f.ReadTerLine ( prevChainID,False );
-  f.ReadTerLine ( prevICode  ,False );
-}
-
-MakeStreamFunctions(CStrand)
-
-
-
-
-//  ================  CSheet  ===================
-
-CSheet::CSheet() : CStream()  {
-  InitSheet();
-}
-
-CSheet::CSheet ( RPCStream Object ) : CStream(Object)  {
-  InitSheet();
-}
-
-CSheet::~CSheet()  {
-  FreeMemory();
-}
-
-void  CSheet::InitSheet()  {
-  nStrands   = 0;
-  sheetID[0] = char(0);
-  Strand     = NULL;
-}
-
-void  CSheet::FreeMemory()  {
-int i;
-  if (Strand)  {
-    for (i=0;i<nStrands;i++)
-      if (Strand[i])  delete Strand[i];
-    delete[] Strand;
-    Strand = NULL;
-  }
-  nStrands   = 0;
-  sheetID[0] = char(0);
-}
-
-void  CSheet::PDBASCIIDump ( RCFile f )  {
-char  S[100];
-int   i;
-  if (Strand)
-    for (i=0;i<nStrands;i++)
-      if (Strand[i])  {
-        strcpy      ( S,"SHEET"           );
-        PadSpaces   ( S,80                );
-        PutInteger  ( &(S[7]) ,i+1     ,3 );
-        strcpy_n1   ( &(S[11]),sheetID ,3 );
-        PutInteger  ( &(S[14]),nStrands,2 );
-        Strand[i]->PDBASCIIDump ( S       );
-        f.WriteLine ( S                   );
-      }
-}
-
-void  CSheet::OrderSheet()  {
-int        i,k;
-PPCStrand  Strand1;
-  k = 0;
-  for (i=0;i<nStrands;i++)
-    if (Strand[i])  k++;
-  if (k<nStrands)  {
-    Strand1 = new PCStrand[k];
-    k = 0;
-    for (i=0;i<nStrands;i++)
-      if (Strand[i])  Strand1[k++] = Strand[i];
-    if (Strand)  delete[] Strand;
-    Strand   = Strand1;
-    nStrands = k;
-  }
-}
-
-void  CSheet::MakeCIF ( PCMMCIFData CIF )  {
-PCMMCIFLoop Loop;
-int         RC;
-int         i;
-Boolean     isSense;
-
-  OrderSheet();
-
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET,Loop );
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_SHEET_ID       );
-    Loop->AddLoopTag ( CIFTAG_NUMBER_STRANDS );
-  }
-  Loop->AddString  ( sheetID  );
-  Loop->AddInteger ( nStrands );
-
-  for (i=0;i<nStrands;i++)  {
-    Strand[i]->MakeCIF ( CIF );
-    if (Strand[i]->sense!=0)  isSense = True;
-  }
-
-  if (nStrands>1)  {
-
-    if (isSense)  {
-      RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_ORDER,Loop );
-      if (RC!=CIFRC_Ok)  {
-        // the category was (re)created, provide tags
-        Loop->AddLoopTag ( CIFTAG_SHEET_ID   );
-        Loop->AddLoopTag ( CIFTAG_RANGE_ID_1 );
-        Loop->AddLoopTag ( CIFTAG_RANGE_ID_2 );
-        Loop->AddLoopTag ( CIFTAG_SENSE      );
-      }
-      for (i=1;i<nStrands;i++)  {
-        Loop->AddString  ( sheetID               );
-        Loop->AddInteger ( Strand[i-1]->strandNo );
-        Loop->AddInteger ( Strand[i]  ->strandNo );
-        if (Strand[i]->sense>0)
-              Loop->AddString ( pstr("parallel")      );
-        else  Loop->AddString ( pstr("anti-parallel") );
-      }
-    }
-
-    RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_HBOND,Loop );
-    if (RC!=CIFRC_Ok)  {
-      // the category was (re)created, provide tags
-      Loop->AddLoopTag ( CIFTAG_SHEET_ID                       );
-      Loop->AddLoopTag ( CIFTAG_RANGE_ID_1                     );
-      Loop->AddLoopTag ( CIFTAG_RANGE_ID_2                     );
-      Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID      );
-      Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID  );
-      Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID  );
-      Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID       );
-      Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE );
-      Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_ATOM_ID      );
-      Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID  );
-      Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID  );
-      Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_SEQ_ID       );
-      Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE );
-    }
-    for (i=1;i<nStrands;i++)  {
-      Loop->AddString  ( sheetID                );
-      Loop->AddInteger ( Strand[i-1]->strandNo  );
-      Loop->AddInteger ( Strand[i]->strandNo    );
-      Loop->AddString  ( Strand[i]->curAtom     );
-      Loop->AddString  ( Strand[i]->curResName  );
-      Loop->AddString  ( Strand[i]->curChainID  );
-      Loop->AddInteger ( Strand[i]->curResSeq   );
-      Loop->AddString  ( Strand[i]->curICode ,True );
-      Loop->AddString  ( Strand[i]->prevAtom    );
-      Loop->AddString  ( Strand[i]->prevResName );
-      Loop->AddString  ( Strand[i]->prevChainID );
-      Loop->AddInteger ( Strand[i]->prevResSeq  );
-      Loop->AddString  ( Strand[i]->prevICode,True );
-    }
-  }
-
-}
-
-
-int CSheet::ConvertPDBASCII ( cpstr S )  {
-int        i,k,ns;
-SheetID    SID;
-PPCStrand  Strand1;
-
-  GetInteger  ( k  ,&(S[7]) ,3 );
-  strcpy_ncss ( SID,&(S[11]),3 );
-  GetInteger  ( ns ,&(S[14]),2 );
-
-//  if (!SID[0])  return  Error_NoSheetID;
-  if (!sheetID[0])  strcpy ( sheetID,SID );
-  else if (strcmp(sheetID,SID))
-                return  Error_WrongSheetID;
-
-  if (k<=0)     return  Error_WrongStrandNo;
-
-  ns = IMax(k,ns);
-  if (!Strand)  {
-    Strand = new PCStrand[ns];
-    for (i=0;i<ns;i++)
-      Strand[i] = NULL;
-  } else if (ns>nStrands)  {
-    Strand1 = new PCStrand[ns];
-    for (i=0;i<nStrands;i++)
-      Strand1[i] = Strand[i];
-    for (i=nStrands;i<ns;i++)
-      Strand1[i] = NULL;
-    if (Strand)  delete[] Strand;
-    Strand = Strand1;
-  }
-  nStrands = ns;
-
-  k--;
-  if (!Strand[k])  Strand[k] = new CStrand();
-
-  return  Strand[k]->ConvertPDBASCII ( S );
-
-}
-
-void  CSheet::TryStrand ( int strand_no )  {
-int       i,k;
-PPCStrand Strand1;
-  k = -1;
-  for (i=0;(i<nStrands) && (k<0);i++)
-    if (Strand[i])
-      if (Strand[i]->strandNo==strand_no)  k = i;
-  if (k<0)  {
-    Strand1 = new PCStrand[nStrands+1];
-    for (i=0;i<nStrands;i++)
-      Strand1[i] = Strand[i];
-    if (Strand) delete[] Strand;
-    Strand = Strand1;
-    Strand[nStrands] = new CStrand();
-    Strand[nStrands]->strandNo = strand_no;
-    nStrands++;
-  }
-}
-
-
-void  CSheet::CIFFindStrands ( PCMMCIFData CIF, cpstr Category ) {
-// just look for all strands mentioned for the sheet
-PCMMCIFLoop Loop;
-pstr        F;
-int         RC,i,l,sNo;
-  Loop = CIF->GetLoop ( Category );
-  if (Loop)  {
-    l = Loop->GetLoopLength();
-    for (i=0;i<l;i++)  {
-      F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
-      if (F && (!RC))  {
-        if (!strcmp(F,sheetID))  {
-          if (!Loop->GetInteger(sNo,CIFTAG_ID,i))
-            TryStrand ( sNo );
-          if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))
-            TryStrand ( sNo );
-          if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i))
-            TryStrand ( sNo );
-        }
-      }
-    }
-  }
-}
-
-int  CSheet::GetStrand ( int strand_no )  {
-int i;
-  for (i=0;i<nStrands;i++)
-    if (Strand[i])  {
-      if (Strand[i]->strandNo==strand_no)
-        return i;
-    }
-  return -1;
-}
-
-int CSheet::GetCIF ( PCMMCIFData CIF )  {
-PCMMCIFLoop Loop;
-int         i,ns,l,k,k2,RC,sNo;
-pstr        F;
-ivector     pair;
-Boolean     Ok;
-
-  pair = NULL;
-
-  //    First find all strands and create
-  // the corresponding classes. The CIF fields
-  // are not removed at this stage.
-
-  CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
-  CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
-  CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
-
-  //  Check number of strands
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET );
-  if (Loop)  {
-    l = Loop->GetLoopLength();
-    i = 0;
-    while (i<l)  {
-      F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
-      if (F && (!RC))  {
-        if (!strcmp(F,sheetID))  {
-          RC = CIFGetInteger1 ( ns,Loop,CIFTAG_NUMBER_STRANDS,i );
-          if ((!RC) && (ns!=nStrands))
-            return  Error_WrongNumberOfStrands;
-          Loop->DeleteRow ( i );
-          i = l+100;  // break loop
-        }
-      }
-      i++;
-    }
-  }
-
-  //  Read each strand
-  RC = 0;
-  for (i=0;(i<nStrands) && (!RC);i++)
-    RC = Strand[i]->GetCIF ( CIF,sheetID );
-
-  if (RC)  return RC;
-
-  if (nStrands>1)  {
-
-    GetVectorMemory ( pair,nStrands,0 );
-    for (i=0;i<nStrands;i++)
-      pair[i] = -1;
-
-    Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_ORDER );
-    if (Loop)  {
-      Ok = True;
-      l  = Loop->GetLoopLength();
-      for (i=0;(i<l) && Ok;i++)  {
-        F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
-        if (F && (!RC))  {
-          if (!strcmp(F,sheetID))  {
-            if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))  {
-              k = GetStrand ( sNo );
-              if ((k>=0) &&
-                  (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i)))  {
-                pair[k] = GetStrand ( sNo );
-                if (pair[k]>=0)  {
-                  F = Loop->GetString ( CIFTAG_SENSE,i,RC );
-                  if (F && (!RC))  {
-                    if (!strcasecmp(F,"anti-parallel"))
-                      Strand[pair[k]]->sense = -1;
-                    else if (!strcasecmp(F,"parallel"))
-                      Strand[pair[k]]->sense =  1;
-                  }
-                  Loop->DeleteRow ( i );
-                } else
-                  Ok = False;
-              } else
-                Ok = False;
-            } else
-              Ok = False;
-          }
-        }
-      }
-      if (!Ok)  {
-        FreeVectorMemory ( pair,0 );
-        return Error_WrongSheetOrder;
-      }
-    }
-
-    Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_HBOND );
-    if (Loop)  {
-      Ok = True;
-      l  = Loop->GetLoopLength();
-      for (i=0;(i<l) && Ok;i++)  {
-        F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
-        if (F && (!RC))  {
-          if (!strcmp(F,sheetID))  {
-            if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))  {
-              k = GetStrand ( sNo );
-              if ((k>=0) &&
-                  (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i)))  {
-                k2 = GetStrand ( sNo );
-                if (k2>=0)  {
-                  if (pair[k]==k2)  {
-                    CIFGetString ( Strand[k2]->curAtom,Loop,
-                              CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID,
-                              i,sizeof(Strand[k2]->curAtom),
-                              pstr("    ") );
-                    CIFGetString ( Strand[k2]->curResName,Loop,
-                              CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID,
-                              i,sizeof(Strand[k2]->curResName),
-                              pstr("   ") );
-                    CIFGetString ( Strand[k2]->curChainID,Loop,
-                              CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID,
-                              i,sizeof(Strand[k2]->curChainID),
-                              pstr(" ") );
-                    if (CIFGetInteger(Strand[k2]->curResSeq,Loop,
-                              CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID,i))  {
-                      FreeVectorMemory ( pair,0 );
-                      return i;
-                    }
-                    CIFGetString ( Strand[k2]->curICode,Loop,
-                              CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE,
-                              i,sizeof(Strand[k2]->curICode),
-                              pstr(" ") );
-                    CIFGetString ( Strand[k2]->prevAtom,Loop,
-                              CIFTAG_RANGE_1_END_LABEL_ATOM_ID,
-                              i,sizeof(Strand[k2]->prevAtom),
-                              pstr("    ") );
-                    CIFGetString ( Strand[k2]->prevResName,Loop,
-                              CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID,
-                              i,sizeof(Strand[k2]->prevResName),
-                              pstr("   ") );
-                    CIFGetString ( Strand[k2]->prevChainID,Loop,
-                              CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID,
-                              i,sizeof(Strand[k2]->prevChainID),
-                              pstr(" ") );
-                    if (CIFGetInteger(Strand[k2]->prevResSeq,Loop,
-                              CIFTAG_RANGE_1_END_LABEL_SEQ_ID,i))  {
-                      FreeVectorMemory ( pair,0 );
-                      return i;
-                    }
-                    CIFGetString ( Strand[k2]->prevICode,Loop,
-                              CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE,
-                              i,sizeof(Strand[k2]->prevICode),
-                              pstr(" ") );
-                    Loop->DeleteRow ( i );
-                  } else
-                      Ok = False;
-                } else
-                  Ok = False;
-              } else
-                Ok = False;
-            } else
-              Ok = False;
-          }
-        }
-      }
-      if (!Ok)  {
-        FreeVectorMemory ( pair,0 );
-        return Error_HBondInconsistency;
-      }
-    }
-  }
-
-  FreeVectorMemory ( pair,0 );
-
-  return 0;
-
-}
-
-
-void  CSheet::Copy ( PCSheet Sheet )  {
-int i;
-  FreeMemory();
-  nStrands = Sheet->nStrands;
-  if (nStrands>0)  {
-    Strand = new PCStrand[nStrands];
-    for (i=0;i<nStrands;i++)
-      if (Sheet->Strand[i])  {
-        Strand[i] = new CStrand();
-        Strand[i]->Copy ( Sheet->Strand[i] );
-      } else
-        Strand[i] = NULL;
-  }
-  strcpy ( sheetID,Sheet->sheetID );
-}
-
-void  CSheet::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte ( &Version  );
-  f.WriteInt  ( &nStrands );
-  for (i=0;i<nStrands;i++)
-    StreamWrite ( f,Strand[i] );
-  f.WriteTerLine ( sheetID,False );
-}
-
-void  CSheet::read  ( RCFile f ) {
-int  i;
-byte Version;
-  FreeMemory();
-  f.ReadByte ( &Version  );
-  f.ReadInt  ( &nStrands );
-  if (nStrands>0)  {
-    Strand = new PCStrand[nStrands];
-    for (i=0;i<nStrands;i++)  {
-      Strand[i] = NULL;
-      StreamRead ( f,Strand[i] );
-    }
-  }
-  f.ReadTerLine ( sheetID,False );
-}
-
-MakeStreamFunctions(CSheet)
-
-
-
-//  ====================  CSheets  ============================
-
-
-CSheets::CSheets() : CStream()  {
-  InitSheets();
-}
-
-
-CSheets::CSheets ( RPCStream Object ) : CStream ( Object )  {
-  InitSheets();
-}
-
-
-CSheets::~CSheets()  {
-  FreeMemory();
-}
-
-
-void  CSheets::InitSheets()  {
-  nSheets = 0;
-  Sheet   = NULL;
-}
-
-
-void  CSheets::FreeMemory()  {
-int i;
-  if (Sheet)  {
-    for (i=0;i<nSheets;i++)
-      if (Sheet[i])  delete Sheet[i];
-    delete[] Sheet;
-    Sheet = NULL;
-  }
-  nSheets = 0;
-}
-
-
-void  CSheets::PDBASCIIDump ( RCFile f )  {
-int i;
-  if (Sheet)
-    for (i=0;i<nSheets;i++)
-      if (Sheet[i])  Sheet[i]->PDBASCIIDump ( f );
-}
-
-
-void  CSheets::MakeCIF ( PCMMCIFData CIF )  {
-int i;
-  if (Sheet)
-    for (i=0;i<nSheets;i++)
-      if (Sheet[i])  Sheet[i]->MakeCIF ( CIF );
-}
-
-
-int   CSheets::ConvertPDBASCII ( cpstr S )  {
-SheetID  sheetID;
-int      i,k;
-PPCSheet Sheet1;
-  strcpy_ncss ( sheetID,&(S[11]),3 );
-  //  if (!sheetID[0]) return  Error_NoSheetID;
-  k = -1;
-  for (i=0;i<nSheets;i++)
-    if (Sheet[i])  {
-      if (!strcmp(sheetID,Sheet[i]->sheetID))  {
-        k = i;
-        break;
-      }
-    }
-  if (k<0)  {
-    Sheet1 = new PCSheet[nSheets+1];
-    for (i=0;i<nSheets;i++)
-      Sheet1[i] = Sheet[i];
-    if (Sheet) delete[] Sheet;
-    Sheet = Sheet1;
-    Sheet[nSheets] = new CSheet();
-    k = nSheets;
-    nSheets++;
-  }
-  return  Sheet[k]->ConvertPDBASCII ( S );
-}
-
-
-void  CSheets::CIFFindSheets ( PCMMCIFData CIF, cpstr Category ) {
-PCMMCIFLoop Loop;
-int         RC,i,j,k,l;
-pstr        F;
-PPCSheet    Sheet1;
-  Loop = CIF->GetLoop ( Category );
-  if (Loop)  {
-    l = Loop->GetLoopLength();
-    for (i=0;i<l;i++)  {
-      F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
-      if (F && (!RC))  {
-        k = -1;
-        j = 0;
-        while ((j<nSheets) && (k<0))  {
-          if (Sheet[j])  {
-            if (!strcmp(F,Sheet[j]->sheetID))  k = j;
-          }
-          j++;
-        }
-        if (k<0)  {
-          Sheet1 = new PCSheet[nSheets+1];
-          for (i=0;i<nSheets;i++)
-            Sheet1[i] = Sheet[i];
-          if (Sheet) delete[] Sheet;
-          Sheet = Sheet1;
-          Sheet[nSheets] = new CSheet();
-          strcpy ( Sheet[nSheets]->sheetID,F );
-          nSheets++;
-    }
-      }
-    }
-  }
-}
-
-int CSheets::GetCIF ( PCMMCIFData CIF )  {
-int i,RC;
-
-  FreeMemory();
-
-  //  First find all sheet names and create
-  // the corresponding classes. The CIF fields
-  // are not removed at this stage.
-
-  CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET       );
-  CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
-  CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
-  CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
-
-  //  Read each sheet
-  i  = 0;
-  RC = 0;
-  while ((i<nSheets) && (!RC))  {
-    RC = Sheet[i]->GetCIF ( CIF );
-    i++;
-  }
-
-  return RC;
-
-}
-
-
-void  CSheets::Copy ( PCSheets Sheets )  {
-int i;
-  FreeMemory();
-  if (Sheets->nSheets>0)  {
-    nSheets = Sheets->nSheets;
-    Sheet = new PCSheet[nSheets];
-    for (i=0;i<nSheets;i++)
-      if (Sheets->Sheet[i]) {
-        Sheet[i] = new CSheet();
-        Sheet[i]->Copy ( Sheets->Sheet[i] );
-      } else
-        Sheet[i] = NULL;
-  }
-}
-
-
-void  CSheets::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte ( &Version );
-  f.WriteInt  ( &nSheets );
-  for (i=0;i<nSheets;i++)
-    StreamWrite ( f,Sheet[i] );
-}
-
-
-void  CSheets::read ( RCFile f )  {
-int  i;
-byte Version;
-  FreeMemory();
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &nSheets );
-  if (nSheets>0)  {
-    Sheet = new PCSheet[nSheets];
-    for (i=0;i<nSheets;i++)  {
-      Sheet[i] = NULL;
-      StreamRead ( f,Sheet[i] );
-    }
-  }
-}
-
-
-MakeStreamFunctions(CSheets)
-
-
-
-//  ================  CTurn  ===================
-
-CTurn::CTurn() : CContainerClass()  {
-  InitTurn();
-}
-
-CTurn::CTurn ( cpstr S ) : CContainerClass()  {
-  InitTurn();
-  ConvertPDBASCII ( S );
-}
-
-CTurn::CTurn ( RPCStream Object ) : CContainerClass(Object)  {
-  InitTurn();
-}
-
-CTurn::~CTurn() {
-  if (comment)  delete[] comment;
-}
-
-void  CTurn::InitTurn()  {
-  serNum = 0;                   // serial number
-  strcpy ( turnID     ,"---" ); // turn ID
-  strcpy ( initResName,"---" ); // name of the turn's initial residue
-  strcpy ( initChainID," "   ); // chain ID for the chain
-                                // containing the turn
-  initSeqNum = 0;               // sequence number of the initial
-                                //    residue
-  strcpy ( initICode  ," "   ); // insertion code of the initial
-                                //    residue
-  strcpy ( endResName ,"---" ); // name of the turn's terminal residue
-  strcpy ( endChainID ," "   ); // chain ID for the chain
-                                // containing the turn
-  endSeqNum  = 0;               // sequence number of the terminal
-                                //    residue
-  strcpy ( endICode   ," "   ); // insertion code of the terminal
-                                //    residue
-  comment    = NULL;            // comment about the helix
-}
-
-void  CTurn::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB OBSLTE line number N
-//  from the class' data
-  strcpy     ( S,"TURN" );
-  PadSpaces  ( S,80 );
-  PutInteger ( &(S[7]) ,serNum     ,3  );
-  strcpy_n1  ( &(S[11]),turnID     ,3  );
-  strcpy_n1  ( &(S[15]),initResName,3  );
-  strcpy_n1  ( &(S[19]),initChainID,1  );
-  PutIntIns  ( &(S[20]),initSeqNum ,4,initICode );
-  strcpy_n1  ( &(S[26]),endResName ,3  );
-  strcpy_n1  ( &(S[30]),endChainID ,1  );
-  PutIntIns  ( &(S[31]),endSeqNum  ,4,endICode  );
-  if (comment)
-    strcpy_n ( &(S[40]),comment    ,30 );
-}
-
-
-#define  TurnTypeID  "TURN_P"
-
-void  CTurn::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop;
-int         RC;
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
-  if (RC!=CIFRC_Ok)
-    // the category was (re)created, provide tags
-    AddStructConfTags ( Loop );
-  Loop->AddString  ( pstr(TurnTypeID) );
-  Loop->AddInteger ( serNum      );
-  Loop->AddString  ( turnID      );
-  Loop->AddString  ( initResName );
-  Loop->AddString  ( initChainID );
-  Loop->AddInteger ( initSeqNum  );
-  Loop->AddString  ( initICode,True );
-  Loop->AddString  ( endResName  );
-  Loop->AddString  ( endChainID  );
-  Loop->AddInteger ( endSeqNum   );
-  Loop->AddString  ( endICode ,True );
-  Loop->AddNoData  ( CIF_NODATA_QUESTION );
-  Loop->AddString  ( comment     );
-  Loop->AddNoData  ( CIF_NODATA_QUESTION );
-}
-
-int CTurn::ConvertPDBASCII ( cpstr S )  {
-char L[100];
-  GetInteger   ( serNum     ,&(S[7]) ,3  );
-  strcpy_ncss  ( turnID     ,&(S[11]),3  );
-  strcpy_ncss  ( initResName,&(S[15]),3  );
-  strcpy_ncss  ( initChainID,&(S[19]),1  );
-  GetIntIns    ( initSeqNum,initICode,&(S[20]),4 );
-  strcpy_ncss  ( endResName ,&(S[26]),3  );
-  strcpy_ncss  ( endChainID ,&(S[30]),1  );
-  GetIntIns    ( endSeqNum ,endICode ,&(S[31]),4 );
-  strcpy_ncss  ( L          ,&(S[40]),30 );
-  CreateCopy   ( comment    ,L           );
-  return 0;
-}
-
-void  CTurn::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-int         RC,l;
-pstr        F;
-Boolean     Done;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-
-  l    = Loop->GetLoopLength();
-  Done = Signal>=l;
-  while (!Done) {
-    F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,Signal,RC );
-    if ((!RC) && F)  Done = (strcmp(F,TurnTypeID)==0);
-               else  Done = False;
-    if (!Done)  {
-      Signal++;
-      Done = Signal>=l;
-    }
-  }
-
-  if (Signal>=l)  {
-    Signal = -1;  // finish processing of Turn
-    return;
-  }
-
-  Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,Signal );
-
-  if (CIFGetInteger(serNum,Loop,CIFTAG_ID,Signal)) return;
-
-
-  CIFGetString ( turnID,Loop,CIFTAG_PDB_ID,Signal,
-                 sizeof(turnID),pstr("   ") );
-
-  CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
-                             Signal,sizeof(initResName),pstr("   ") );
-  CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
-                             Signal,sizeof(initChainID),pstr(" ") );
-  CIFGetString ( initICode  ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
-                             Signal,sizeof(initICode),pstr(" ") );
-  if (CIFGetInteger(initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,Signal))
-    return;
-
-  CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
-                            Signal,sizeof(endResName),pstr("   ") );
-  CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
-                            Signal,sizeof(endChainID),pstr(" ") );
-  CIFGetString ( endICode  ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
-                            Signal,sizeof(endICode),pstr(" ") );
-  if (CIFGetInteger(endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,Signal))
-    return;
-
-  CreateCopy      ( comment,Loop->GetString(CIFTAG_DETAILS,Signal,RC));
-  Loop->DeleteField ( CIFTAG_DETAILS,Signal );
-
-  Signal++;
-
-}
-
-void  CTurn::Copy ( PCContainerClass Turn )  {
-  serNum     = PCTurn(Turn)->serNum;
-  initSeqNum = PCTurn(Turn)->initSeqNum;
-  endSeqNum  = PCTurn(Turn)->endSeqNum;
-  strcpy ( turnID     ,PCTurn(Turn)->turnID      );
-  strcpy ( initResName,PCTurn(Turn)->initResName );
-  strcpy ( initChainID,PCTurn(Turn)->initChainID );
-  strcpy ( initICode  ,PCTurn(Turn)->initICode   );
-  strcpy ( endResName ,PCTurn(Turn)->endResName  );
-  strcpy ( endChainID ,PCTurn(Turn)->endChainID  );
-  strcpy ( endICode   ,PCTurn(Turn)->endICode    );
-  CreateCopy ( comment,PCTurn(Turn)->comment );
-}
-
-void  CTurn::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version    );
-  f.WriteInt  ( &serNum     );
-  f.WriteInt  ( &initSeqNum );
-  f.WriteInt  ( &endSeqNum  );
-  f.WriteTerLine ( turnID     ,False );
-  f.WriteTerLine ( initResName,False );
-  f.WriteTerLine ( initChainID,False );
-  f.WriteTerLine ( initICode  ,False );
-  f.WriteTerLine ( endResName ,False );
-  f.WriteTerLine ( endChainID ,False );
-  f.WriteTerLine ( endICode   ,False );
-  f.CreateWrite ( comment );
-}
-
-void  CTurn::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &serNum     );
-  f.ReadInt  ( &initSeqNum );
-  f.ReadInt  ( &endSeqNum  );
-  f.ReadTerLine ( turnID     ,False );
-  f.ReadTerLine ( initResName,False );
-  f.ReadTerLine ( initChainID,False );
-  f.ReadTerLine ( initICode  ,False );
-  f.ReadTerLine ( endResName ,False );
-  f.ReadTerLine ( endChainID ,False );
-  f.ReadTerLine ( endICode   ,False );
-  f.CreateRead ( comment );
-}
-
-MakeStreamFunctions(CTurn)
-
-
-//  ===================  CLinkContainer  ========================
-
-PCContainerClass CLinkContainer::MakeContainerClass ( int ClassID )  {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template : return
-                        CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_Link    : return new CLink();
-  }
-}
-
-MakeStreamFunctions(CLinkContainer)
-
-
-
-//  ========================  CLink  ===========================
-
-CLink::CLink() : CContainerClass()  {
-  InitLink();
-}
-
-CLink::CLink ( cpstr S ) : CContainerClass()  {
-  InitLink();
-  ConvertPDBASCII ( S );
-}
-
-CLink::CLink ( RPCStream Object ) : CContainerClass(Object)  {
-  InitLink();
-}
-
-CLink::~CLink() {}
-
-void  CLink::InitLink()  {
-  strcpy ( atName1 ,"----" );  // name of 1st linked atom
-  strcpy ( aloc1   ," "    );  // alternative location of 1st atom
-  strcpy ( resName1,"---"  );  // residue name of 1st linked atom
-  strcpy ( chainID1," "    );  // chain ID of 1st linked atom
-  seqNum1 = 0;                 // sequence number of 1st linked atom
-  strcpy ( insCode1," "    );  // insertion code of 1st linked atom
-  strcpy ( atName2 ,"----" );  // name of 2nd linked atom
-  strcpy ( aloc2   ," "    );  // alternative location of 2nd atom
-  strcpy ( resName2,"---"  );  // residue name of 2nd linked atom
-  strcpy ( chainID2," "    );  // chain ID of 2nd linked atom
-  seqNum2 = 0;                 // sequence number of 2nd linked atom
-  strcpy ( insCode2," "    );  // insertion code of 2nd linked atom
-  s1 = 1;  // sym id of 1st atom
-  i1 = 5;
-  j1 = 5;
-  k1 = 5;
-  s2 = 1;  // sym id of 2nd atom
-  i2 = 5;
-  j2 = 5;
-  k2 = 5;
-}
-
-
-void  CLink::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB OBSLTE line number N
-//  from the class' data
-
-  strcpy     ( S,"LINK" );
-  PadSpaces  ( S,80 );
-
-  strcpy_n1  ( &(S[12]),atName1 ,4 );
-  strcpy_n1  ( &(S[16]),aloc1   ,1 );
-  strcpy_n1  ( &(S[17]),resName1,3 );
-  strcpy_n1  ( &(S[21]),chainID1,1 );
-  PutIntIns  ( &(S[22]),seqNum1 ,4,insCode1 );
-
-  strcpy_n1  ( &(S[42]),atName2 ,4 );
-  strcpy_n1  ( &(S[46]),aloc2   ,1 );
-  strcpy_n1  ( &(S[47]),resName2,3 );
-  strcpy_n1  ( &(S[51]),chainID2,1 );
-  PutIntIns  ( &(S[52]),seqNum2 ,4,insCode2 );
-
-  PutInteger ( &(S[59]),s1,3 );
-  PutInteger ( &(S[62]),i1,1 );
-  PutInteger ( &(S[63]),j1,1 );
-  PutInteger ( &(S[64]),k1,1 );
-
-  PutInteger ( &(S[66]),s2,3 );
-  PutInteger ( &(S[69]),i2,1 );
-  PutInteger ( &(S[70]),j2,1 );
-  PutInteger ( &(S[71]),k2,1 );
-
-}
-
-
-#define  LinkTypeID  "LINK"
-
-void AddStructConnTags ( PCMMCIFLoop Loop )  {
-
-  Loop->AddLoopTag ( CIFTAG_ID                           );
-  Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID                 );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID  );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID       );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID  );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID       );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_SYMMETRY );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_SYMMETRY );
-
-}
-
-
-void  CLink::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop;
-char        S[100];
-int         RC;
-
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
-  if (RC!=CIFRC_Ok) // the category was (re)created, provide tags
-    AddStructConnTags ( Loop );
-
-  Loop->AddString  ( "1"      );  // should be a counter
-  Loop->AddString  ( pstr(LinkTypeID) );
-
-  Loop->AddString  ( atName1  );
-  Loop->AddString  ( aloc1    );
-  Loop->AddString  ( resName1 );
-  Loop->AddString  ( chainID1 );
-  Loop->AddInteger ( seqNum1  );
-  Loop->AddString  ( insCode1 );
-
-  Loop->AddString  ( atName2  );
-  Loop->AddString  ( aloc2    );
-  Loop->AddString  ( resName2 );
-  Loop->AddString  ( chainID2 );
-  Loop->AddInteger ( seqNum2  );
-  Loop->AddString  ( insCode2 );
-
-  sprintf ( S,"%i%i%i%i",s1,i1,j1,k1 );
-  Loop->AddString  ( S );
-  sprintf ( S,"%i%i%i%i",s2,i2,j2,k2 );
-  Loop->AddString  ( S );
-
-}
-
-int CLink::ConvertPDBASCII ( cpstr S )  {
-
-  GetString    ( atName1 ,&(S[12]),4 );
-  strcpy_ncss  ( aloc1   ,&(S[16]),1 );
-  strcpy_ncss  ( resName1,&(S[17]),3 );
-  strcpy_ncss  ( chainID1,&(S[21]),1 );
-  GetIntIns    ( seqNum1,insCode1,&(S[22]),4 );
-
-  GetString    ( atName2 ,&(S[42]),4 );
-  strcpy_ncss  ( aloc2   ,&(S[46]),1 );
-  strcpy_ncss  ( resName2,&(S[47]),3 );
-  strcpy_ncss  ( chainID2,&(S[51]),1 );
-  GetIntIns    ( seqNum2,insCode2,&(S[52]),4 );
-
-  GetInteger   ( s1,&(S[59]),3 );
-  GetInteger   ( i1,&(S[62]),1 );
-  GetInteger   ( j1,&(S[63]),1 );
-  GetInteger   ( k1,&(S[64]),1 );
-
-  GetInteger   ( s2,&(S[66]),3 );
-  GetInteger   ( i2,&(S[69]),1 );
-  GetInteger   ( j2,&(S[70]),1 );
-  GetInteger   ( k2,&(S[71]),1 );
-
-  return 0;
-
-}
-
-void  CLink::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-pstr        F;
-char        S[100];
-int         RC,l;
-Boolean     Done;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-
-  l    = Loop->GetLoopLength();
-  Done = (Signal>=l);
-  while (!Done) {
-    F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,Signal,RC );
-    if ((!RC) && F)  Done = (strcmp(F,LinkTypeID)==0);
-               else  Done = False;
-    if (!Done)  {
-      Signal++;
-      Done = (Signal>=l);
-    }
-  }
-
-  if (Signal>=l)  {
-    Signal = -1;  // finish processing of Turn
-    return;
-  }
-
-  Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,Signal );
-
-//  CIFGetInteger ( l,Loop,CIFTAG_ID,Signal );
-
-  CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,Signal,
-                 sizeof(atName1),pstr("    ") );
-  CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,Signal,
-                 sizeof(aloc1),pstr(" ") );
-  CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,Signal,
-                 sizeof(resName1),pstr("   ") );
-  CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,Signal,
-                 sizeof(chainID1),pstr(" ") );
-  if (CIFGetInteger(seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,Signal))
-    return;
-  CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
-                 Signal,sizeof(insCode1),pstr(" ") );
-
-  CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,Signal,
-                 sizeof(atName2),pstr("    ") );
-  CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,Signal,
-                 sizeof(aloc2),pstr(" ") );
-  CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,Signal,
-                 sizeof(resName2),pstr("   ") );
-  CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,Signal,
-                 sizeof(chainID2),pstr(" ") );
-  if (CIFGetInteger(seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,Signal))
-    return;
-  CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
-                 Signal,sizeof(insCode2),pstr(" ") );
-
-  CIFGetString ( S,Loop,CIFTAG_CONN_PTNR1_SYMMETRY,Signal,
-                 sizeof(S),pstr("") );
-  if (S[0])  {
-    l  = strlen(S)-1;
-    k1 = int(S[l--]) - int('0');
-    j1 = int(S[l--]) - int('0');
-    i1 = int(S[l--]) - int('0');
-    S[l] = char(0);
-    s1 = atoi(S);
-  }
-
-  CIFGetString ( S,Loop,CIFTAG_CONN_PTNR2_SYMMETRY,Signal,
-                 sizeof(S),pstr("") );
-  if (S[0])  {
-    l  = strlen(S)-1;
-    k2 = int(S[l--]) - int('0');
-    j2 = int(S[l--]) - int('0');
-    i2 = int(S[l--]) - int('0');
-    S[l] = char(0);
-    s2 = atoi(S);
-  }
-
-  Signal++;
-
-}
-
-void  CLink::Copy ( PCContainerClass Link )  {
-
-  strcpy ( atName1 ,PCLink(Link)->atName1  );
-  strcpy ( aloc1   ,PCLink(Link)->aloc1    );
-  strcpy ( resName1,PCLink(Link)->resName1 );
-  strcpy ( chainID1,PCLink(Link)->chainID1 );
-  seqNum1 = PCLink(Link)->seqNum1;
-  strcpy ( insCode1,PCLink(Link)->insCode1 );
-
-  strcpy ( atName2 ,PCLink(Link)->atName2  );
-  strcpy ( aloc2   ,PCLink(Link)->aloc2    );
-  strcpy ( resName2,PCLink(Link)->resName2 );
-  strcpy ( chainID2,PCLink(Link)->chainID2 );
-  seqNum2 = PCLink(Link)->seqNum2;
-  strcpy ( insCode2,PCLink(Link)->insCode2 );
-
-  s1 = PCLink(Link)->s1;
-  i1 = PCLink(Link)->i1;
-  j1 = PCLink(Link)->j1;
-  k1 = PCLink(Link)->k1;
-
-  s2 = PCLink(Link)->s2;
-  i2 = PCLink(Link)->i2;
-  j2 = PCLink(Link)->j2;
-  k2 = PCLink(Link)->k2;
-
-}
-
-void  CLink::write ( RCFile f )  {
-byte Version=1;
-
-  f.WriteByte ( &Version    );
-
-  f.WriteTerLine ( atName1 ,False );
-  f.WriteTerLine ( aloc1   ,False );
-  f.WriteTerLine ( resName1,False );
-  f.WriteTerLine ( chainID1,False );
-  f.WriteInt     ( &seqNum1 );
-  f.WriteTerLine ( insCode1,False );
-
-  f.WriteTerLine ( atName2 ,False );
-  f.WriteTerLine ( aloc2   ,False );
-  f.WriteTerLine ( resName2,False );
-  f.WriteTerLine ( chainID2,False );
-  f.WriteInt     ( &seqNum2 );
-  f.WriteTerLine ( insCode2,False );
-
-  f.WriteInt ( &s1 );
-  f.WriteInt ( &i1 );
-  f.WriteInt ( &j1 );
-  f.WriteInt ( &k1 );
-
-  f.WriteInt ( &s2 );
-  f.WriteInt ( &i2 );
-  f.WriteInt ( &j2 );
-  f.WriteInt ( &k2 );
-
-}
-
-void  CLink::read ( RCFile f )  {
-byte Version;
-
-  f.ReadByte ( &Version    );
-
-  f.ReadTerLine ( atName1 ,False );
-  f.ReadTerLine ( aloc1   ,False );
-  f.ReadTerLine ( resName1,False );
-  f.ReadTerLine ( chainID1,False );
-  f.ReadInt     ( &seqNum1 );
-  f.ReadTerLine ( insCode1,False );
-
-  f.ReadTerLine ( atName2 ,False );
-  f.ReadTerLine ( aloc2   ,False );
-  f.ReadTerLine ( resName2,False );
-  f.ReadTerLine ( chainID2,False );
-  f.ReadInt     ( &seqNum2 );
-  f.ReadTerLine ( insCode2,False );
-
-  f.ReadInt ( &s1 );
-  f.ReadInt ( &i1 );
-  f.ReadInt ( &j1 );
-  f.ReadInt ( &k1 );
-
-  f.ReadInt ( &s2 );
-  f.ReadInt ( &i2 );
-  f.ReadInt ( &j2 );
-  f.ReadInt ( &k2 );
-
-}
-
-MakeStreamFunctions(CLink)
-
-
-//  ===================  CLinkRContainer  =======================
-
-PCContainerClass CLinkRContainer::MakeContainerClass ( int ClassID )  {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template : return
-                         CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_LinkR    : return new CLinkR();
-  }
-}
-
-MakeStreamFunctions(CLinkRContainer)
-
-
-//  ========================  CLinkR  ===========================
-
-CLinkR::CLinkR() : CContainerClass()  {
-  InitLinkR();
-}
-
-CLinkR::CLinkR ( cpstr S ) : CContainerClass()  {
-  InitLinkR();
-  ConvertPDBASCII ( S );
-}
-
-CLinkR::CLinkR ( RPCStream Object ) : CContainerClass(Object)  {
-  InitLinkR();
-}
-
-CLinkR::~CLinkR() {}
-
-void  CLinkR::InitLinkR()  {
-  strcpy ( linkRID ,"----" );  // link name
-  strcpy ( atName1 ,"----" );  // name of 1st linked atom
-  strcpy ( aloc1   ," "    );  // alternative location of 1st atom
-  strcpy ( resName1,"---"  );  // residue name of 1st linked atom
-  strcpy ( chainID1," "    );  // chain ID of 1st linked atom
-  seqNum1 = 0;                 // sequence number of 1st linked atom
-  strcpy ( insCode1," "    );  // insertion code of 1st linked atom
-  strcpy ( atName2 ,"----" );  // name of 2nd linked atom
-  strcpy ( aloc2   ," "    );  // alternative location of 2nd atom
-  strcpy ( resName2,"---"  );  // residue name of 2nd linked atom
-  strcpy ( chainID2," "    );  // chain ID of 2nd linked atom
-  seqNum2 = 0;                 // sequence number of 2nd linked atom
-  strcpy ( insCode2," "    );  // insertion code of 2nd linked atom
-  dist    = 0.0;               // link distance
-}
-
-/*
-LINK             LYS A  27                     PLP A 255                PLPLYS
-LINK             MAN S   3                     MAN S   4                BETA1-4
-LINK        C6  BBEN B   1                O1  BMAF S   2                BEN-MAF
-LINK        OE2 AGLU A 320                C1  AMAF S   2                GLU-MAF
-LINK        OE2  GLU A  67        1.895   ZN   ZN  R   5                GLU-ZN
-LINK        NE2  HIS A  71        2.055   ZN   ZN  R   5                HIS-ZN
-LINK        O    ARG A  69        2.240   NA   NA  R   9                ARG-NA
-012345678901234567890123456789012345678901234567890123456789012345678901234567890
-          1         2         3         4         5         6         7
-*/
-
-void  CLinkR::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-//  makes the ASCII PDB OBSLTE line number N
-//  from the class' data
-
-  strcpy     ( S,"LINKR" );
-  PadSpaces  ( S,80 );
-
-  strcpy_n1  ( &(S[12]),atName1 ,4 );
-  strcpy_n1  ( &(S[16]),aloc1   ,1 );
-  strcpy_n1  ( &(S[17]),resName1,3 );
-  strcpy_n1  ( &(S[21]),chainID1,1 );
-  PutIntIns  ( &(S[22]),seqNum1 ,4,insCode1 );
-
-  if (dist>0.0)
-    PutRealF ( &(S[32]),dist,7,3 );
-
-  strcpy_n1  ( &(S[42]),atName2 ,4 );
-  strcpy_n1  ( &(S[46]),aloc2   ,1 );
-  strcpy_n1  ( &(S[47]),resName2,3 );
-  strcpy_n1  ( &(S[51]),chainID2,1 );
-  PutIntIns  ( &(S[52]),seqNum2 ,4,insCode2 );
-
-  strcpy_ns  ( &(S[72]),linkRID,8 );
-
-}
-
-
-#define  LinkRTypeID  "LINKR"
-
-void AddStructConnLinkRTags ( PCMMCIFLoop Loop )  {
-
-  Loop->AddLoopTag ( CIFTAG_ID                           );
-  Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID                 );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID  );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID       );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_DIST );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID  );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID      );
-  Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID       );
-  Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
-
-  Loop->AddLoopTag ( CIFTAG_CONN_NAME );
-
-}
-
-void  CLinkR::MakeCIF ( PCMMCIFData CIF, int N )  {
-UNUSED_ARGUMENT(N);
-PCMMCIFLoop Loop;
-int         RC;
-
-  RC = CIF->AddLoop ( CIFCAT_STRUCT_LINKR,Loop );
-  if (RC!=CIFRC_Ok) // the category was (re)created, provide tags
-    AddStructConnLinkRTags ( Loop );
-
-  Loop->AddString  ( "1"      );  // should be a counter
-  Loop->AddString  ( pstr(LinkTypeID) );
-
-  Loop->AddString  ( atName1  );
-  Loop->AddString  ( aloc1    );
-  Loop->AddString  ( resName1 );
-  Loop->AddString  ( chainID1 );
-  Loop->AddInteger ( seqNum1  );
-  Loop->AddString  ( insCode1 );
-
-  Loop->AddReal    ( dist     );
-
-  Loop->AddString  ( atName2  );
-  Loop->AddString  ( aloc2    );
-  Loop->AddString  ( resName2 );
-  Loop->AddString  ( chainID2 );
-  Loop->AddInteger ( seqNum2  );
-  Loop->AddString  ( insCode2 );
-
-  Loop->AddString  ( linkRID  );
-
-}
-
-int CLinkR::ConvertPDBASCII ( cpstr S )  {
-
-  GetString    ( atName1 ,&(S[12]),4 );
-  strcpy_ncss  ( aloc1   ,&(S[16]),1 );
-  strcpy_ncss  ( resName1,&(S[17]),3 );
-  strcpy_ncss  ( chainID1,&(S[21]),1 );
-  GetIntIns    ( seqNum1,insCode1,&(S[22]),4 );
-
-  if (!GetReal(dist,&(S[32]),7)) dist = 0.0;
-
-  GetString    ( atName2 ,&(S[42]),4 );
-  strcpy_ncss  ( aloc2   ,&(S[46]),1 );
-  strcpy_ncss  ( resName2,&(S[47]),3 );
-  strcpy_ncss  ( chainID2,&(S[51]),1 );
-  GetIntIns    ( seqNum2,insCode2,&(S[52]),4 );
-
-  strcpy_ncss  ( linkRID,&(S[72]),8 );
-
-  return 0;
-
-}
-
-void  CLinkR::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-pstr        F;
-int         RC,l;
-Boolean     Done;
-
-  Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-
-  l    = Loop->GetLoopLength();
-  Done = (Signal>=l);
-  while (!Done) {
-    F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,Signal,RC );
-    if ((!RC) && F)  Done = (strcmp(F,LinkTypeID)==0);
-               else  Done = False;
-    if (!Done)  {
-      Signal++;
-      Done = (Signal>=l);
-    }
-  }
-
-  if (Signal>=l)  {
-    Signal = -1;  // finish processing of Turn
-    return;
-  }
-
-  Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,Signal );
-
-  //  CIFGetInteger ( l,Loop,CIFTAG_ID,Signal );
-
-  CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,Signal,
-                 sizeof(atName1),pstr("    ") );
-  CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,Signal,
-                 sizeof(aloc1),pstr(" ") );
-  CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,Signal,
-                 sizeof(resName1),pstr("   ") );
-  CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,Signal,
-                 sizeof(chainID1),pstr(" ") );
-  if (CIFGetInteger(seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,Signal))
-    return;
-  CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
-                 Signal,sizeof(insCode1),pstr(" ") );
-
-  if (CIFGetReal(dist,Loop,CIFTAG_CONN_DIST,Signal))
-    return;
-
-  CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,Signal,
-                 sizeof(atName2),pstr("    ") );
-  CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,Signal,
-                 sizeof(aloc2),pstr(" ") );
-  CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,Signal,
-                 sizeof(resName2),pstr("   ") );
-  CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,Signal,
-                 sizeof(chainID2),pstr(" ") );
-  if (CIFGetInteger(seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,Signal))
-    return;
-  CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
-                 Signal,sizeof(insCode2),pstr(" ") );
-
-  CIFGetString ( linkRID,Loop,CIFTAG_CONN_NAME,Signal,
-                 sizeof(linkRID),pstr(" ") );
-
-  Signal++;
-
-}
-
-void  CLinkR::Copy ( PCContainerClass LinkR )  {
-
-  strcpy ( atName1 ,PCLinkR(LinkR)->atName1  );
-  strcpy ( aloc1   ,PCLinkR(LinkR)->aloc1    );
-  strcpy ( resName1,PCLinkR(LinkR)->resName1 );
-  strcpy ( chainID1,PCLinkR(LinkR)->chainID1 );
-  seqNum1 = PCLinkR(LinkR)->seqNum1;
-  strcpy ( insCode1,PCLinkR(LinkR)->insCode1 );
-
-  dist = PCLinkR(LinkR)->dist;
-
-  strcpy ( atName2 ,PCLinkR(LinkR)->atName2  );
-  strcpy ( aloc2   ,PCLinkR(LinkR)->aloc2    );
-  strcpy ( resName2,PCLinkR(LinkR)->resName2 );
-  strcpy ( chainID2,PCLinkR(LinkR)->chainID2 );
-  seqNum2 = PCLinkR(LinkR)->seqNum2;
-  strcpy ( insCode2,PCLinkR(LinkR)->insCode2 );
-
-  strcpy ( linkRID,PCLinkR(LinkR)->linkRID );
-
-}
-
-void  CLinkR::write ( RCFile f )  {
-byte Version=1;
-
-  f.WriteByte ( &Version    );
-
-  f.WriteTerLine ( atName1 ,False );
-  f.WriteTerLine ( aloc1   ,False );
-  f.WriteTerLine ( resName1,False );
-  f.WriteTerLine ( chainID1,False );
-  f.WriteInt     ( &seqNum1 );
-  f.WriteTerLine ( insCode1,False );
-
-  f.WriteReal    ( &dist );
-
-  f.WriteTerLine ( atName2 ,False );
-  f.WriteTerLine ( aloc2   ,False );
-  f.WriteTerLine ( resName2,False );
-  f.WriteTerLine ( chainID2,False );
-  f.WriteInt     ( &seqNum2 );
-  f.WriteTerLine ( insCode2,False );
-
-  f.WriteTerLine ( linkRID,False );
-
-}
-
-void  CLinkR::read ( RCFile f )  {
-byte Version;
-
-  f.ReadByte ( &Version    );
-
-  f.ReadTerLine ( atName1 ,False );
-  f.ReadTerLine ( aloc1   ,False );
-  f.ReadTerLine ( resName1,False );
-  f.ReadTerLine ( chainID1,False );
-  f.ReadInt     ( &seqNum1 );
-  f.ReadTerLine ( insCode1,False );
-
-  f.ReadReal    ( &dist );
-
-  f.ReadTerLine ( atName2 ,False );
-  f.ReadTerLine ( aloc2   ,False );
-  f.ReadTerLine ( resName2,False );
-  f.ReadTerLine ( chainID2,False );
-  f.ReadInt     ( &seqNum2 );
-  f.ReadTerLine ( insCode2,False );
-
-  f.ReadTerLine ( linkRID,False );
-
-}
-
-MakeStreamFunctions(CLinkR)
-
-
-//  ===================  CCisPepContainer  ======================
-
-PCContainerClass CCisPepContainer::MakeContainerClass ( int ClassID ) {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template : return
-                        CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_CisPep   : return new CCisPep();
-  }
-}
-
-MakeStreamFunctions(CCisPepContainer)
-
-
-//  ========================  CCisPep  ==========================
-
-CCisPep::CCisPep() : CContainerClass()  {
-  InitCisPep();
-}
-
-CCisPep::CCisPep ( cpstr S ) : CContainerClass()  {
-  InitCisPep();
-  ConvertPDBASCII ( S );
-}
-
-CCisPep::CCisPep ( RPCStream Object ) : CContainerClass(Object)  {
-  InitCisPep();
-}
-
-CCisPep::~CCisPep() {}
-
-void CCisPep::InitCisPep()  {
-  serNum  = 1;                //  record serial number
-  strcpy ( pep1    ,"---" );  //  residue name
-  strcpy ( chainID1," "   );  //  chain identifier 1
-  seqNum1 = 0;                //  residue sequence number 1
-  strcpy ( icode1  ," "   );  //  insertion code 1
-  strcpy ( pep2    ,"---" );  //  residue name 2
-  strcpy ( chainID2," "   );  //  chain identifier 2
-  seqNum2 = 0;                //  residue sequence number 2
-  strcpy ( icode2  ," "   );  //  insertion code 2
-  modNum  = 0;                //  model number
-  measure = 0.0;              //  measure of the angle in degrees.
-}
-
-void  CCisPep::PDBASCIIDump ( pstr S, int N )  {
-UNUSED_ARGUMENT(N);
-
-  strcpy     ( S,"CISPEP" );
-  PadSpaces  ( S,80 );
-
-  PutInteger ( &(S[7]),serNum,3 );
-
-  strcpy_n1  ( &(S[11]),pep1    ,3 );
-  strcpy_n1  ( &(S[15]),chainID1,1 );
-  PutIntIns  ( &(S[17]),seqNum1 ,4,icode1 );
-
-  strcpy_n1  ( &(S[25]),pep2    ,3 );
-  strcpy_n1  ( &(S[29]),chainID2,1 );
-  PutIntIns  ( &(S[31]),seqNum2 ,4,icode1 );
-
-  PutInteger ( &(S[43]),modNum,3 );
-  PutRealF   ( &(S[53]),measure,6,2 );
-
-}
-
-
-int CCisPep::ConvertPDBASCII ( cpstr S )  {
-
-  GetInteger   ( serNum  ,&(S[7]) ,3 );
-
-  strcpy_ncss  ( pep1    ,&(S[11]),3 );
-  strcpy_ncss  ( chainID1,&(S[15]),1 );
-  GetIntIns    ( seqNum1,icode1,&(S[17]),4 );
-
-  strcpy_ncss  ( pep2    ,&(S[25]),3 );
-  strcpy_ncss  ( chainID2,&(S[29]),1 );
-  GetIntIns    ( seqNum2,icode2,&(S[31]),4 );
-
-  GetInteger   ( modNum  ,&(S[43]),3 );
-  GetReal      ( measure ,&(S[53]),6 );
-
-  return 0;
-
-}
-
-
-void  CCisPep::Copy ( PCContainerClass CisPep )  {
-
-  serNum  = PCCisPep(CisPep)->serNum;
-
-  strcpy ( pep1    ,PCCisPep(CisPep)->pep1     );
-  strcpy ( chainID1,PCCisPep(CisPep)->chainID1 );
-  seqNum1 = PCCisPep(CisPep)->seqNum1;
-  strcpy ( icode1  ,PCCisPep(CisPep)->icode1   );
-
-  strcpy ( pep2    ,PCCisPep(CisPep)->pep2     );
-  strcpy ( chainID2,PCCisPep(CisPep)->chainID2 );
-  seqNum2 = PCCisPep(CisPep)->seqNum2;
-  strcpy ( icode2  ,PCCisPep(CisPep)->icode2   );
-
-  modNum  = PCCisPep(CisPep)->modNum;
-  measure = PCCisPep(CisPep)->measure;
-
-}
-
-void  CCisPep::write ( RCFile f )  {
-byte Version=1;
-
-  f.WriteByte    ( &Version   );
-
-  f.WriteInt     ( &serNum );
-
-  f.WriteTerLine ( pep1    ,False );
-  f.WriteTerLine ( chainID1,False );
-  f.WriteInt     ( &seqNum1 );
-  f.WriteTerLine ( icode1  ,False );
-
-  f.WriteTerLine ( pep2    ,False );
-  f.WriteTerLine ( chainID2,False );
-  f.WriteInt     ( &seqNum2 );
-  f.WriteTerLine ( icode2  ,False );
-
-  f.WriteInt     ( &modNum  );
-  f.WriteReal    ( &measure );
-
-}
-
-void  CCisPep::read ( RCFile f )  {
-byte Version;
-
-  f.ReadByte    ( &Version   );
-
-  f.ReadInt     ( &serNum );
-
-  f.ReadTerLine ( pep1    ,False );
-  f.ReadTerLine ( chainID1,False );
-  f.ReadInt     ( &seqNum1 );
-  f.ReadTerLine ( icode1  ,False );
-
-  f.ReadTerLine ( pep2    ,False );
-  f.ReadTerLine ( chainID2,False );
-  f.ReadInt     ( &seqNum2 );
-  f.ReadTerLine ( icode2  ,False );
-
-  f.ReadInt     ( &modNum  );
-  f.ReadReal    ( &measure );
-
-}
-
-MakeStreamFunctions(CCisPep)
-
-
-
-//  =====================   CModel   =======================
-
-CModel::CModel() : CProModel() {
-  InitModel();
-}
-
-CModel::CModel ( PCMMDBManager MMDBM, int serialNum ) : CProModel() {
-  InitModel();
-  manager = MMDBM;
-  serNum  = serialNum;
-}
-
-CModel::CModel ( RPCStream Object ) : CProModel(Object)  {
-  InitModel();
-}
-
-void  CModel::InitModel()  {
-  serNum       = 0;
-  nChains      = 0;
-  nChainsAlloc = 0;
-  Chain        = NULL;
-  manager      = NULL;
-  Exclude      = True;
-}
-
-CModel::~CModel()  {
-  FreeMemory();
-  if (manager)  manager->_ExcludeModel ( serNum );
-}
-
-void CModel::FreeMemory()  {
-
-  DeleteAllChains();
-  if (Chain)  delete[] Chain;
-  Chain        = NULL;
-  nChains      = 0;
-  nChainsAlloc = 0;
-
-  RemoveSecStructure();
-  RemoveHetInfo     ();
-  RemoveLinks       ();
-  RemoveLinkRs      ();
-  RemoveCisPeps     ();
-
-}
-
-
-void  CModel::SetMMDBManager ( PCMMDBManager MMDBM, int serialNum )  {
-  manager = MMDBM;
-  serNum  = serialNum;
-}
-
-void  CModel::CheckInAtoms()  {
-int i;
-  if (manager)
-    for (i=0;i<nChains;i++)
-      if (Chain[i])
-        Chain[i]->CheckInAtoms();
-}
-
-
-int  CModel::GetNumberOfAtoms ( Boolean countTers )  {
-// returns number of atoms in the model
-int i,na;
-  na = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  na += Chain[i]->GetNumberOfAtoms ( countTers );
-  return na;
-}
-
-int  CModel::GetNumberOfResidues()  {
-// returns number of residues in the model
-PCChain   chain;
-int       ic,ir,nr;
-  nr = 0;
-  for (ic=0;ic<nChains;ic++)  {
-    chain = Chain[ic];
-    if (chain)
-      for (ir=0;ir<chain->nResidues;ir++)
-        if (chain->Residue[ir])  nr++;
-  }
-  return nr;
-}
-
-
-//  ----------------  Extracting chains  --------------------------
-
-int  CModel::GetNumberOfChains()  {
-  return nChains;
-}
-
-PCChain CModel::GetChain ( int chainNo )  {
-  if ((0<=chainNo) && (chainNo<nChains))
-        return Chain[chainNo];
-  else  return NULL;
-}
-
-
-void CModel::ExpandChainArray ( int nOfChains )  {
-PPCChain Chain1;
-int      i;
-  if (nOfChains>=nChainsAlloc)  {
-    nChainsAlloc = nOfChains+10;
-    Chain1 = new PCChain[nChainsAlloc];
-    for (i=0;i<nChains;i++)
-      Chain1[i] = Chain[i];
-    for (i=nChains;i<nChainsAlloc;i++)
-      Chain1[i] = NULL;
-    if (Chain)  delete[] Chain;
-    Chain = Chain1;
-  }
-}
-
-PCChain CModel::GetChainCreate ( const ChainID chID,
-                                 Boolean enforceUniqueChainID )  {
-//   Returns pointer on chain, whose identifier is
-// given in chID. If such a chain is absent in the
-// model, it is created.
-PCChain chain;
-ChainID chainID;
-int     i,k;
-
-  // check if such a chain is already in the model
-  chain = NULL;
-  if (enforceUniqueChainID)  {
-    k = 0;
-    for (i=0;i<nChains;i++)
-      if (Chain[i])  {
-        // here we check only first letter as it is kept in all
-        // derived names
-        if (chID[0]==Chain[i]->chainID[0])  {
-          chain = Chain[i];
-          if (chain->GetNumberOfResidues()>0)  k++;
-        }
-      }
-    if (k)            sprintf ( chainID,"%s%i",chID,k-1 );
-    else if (!chain)  strcpy  ( chainID,chID ); // chain is absent
-                else  return chain;  // the only empty chain
-  } else  {
-    if (chID[0])  {
-      for (i=0;(i<nChains) && (!chain);i++)
-        if (Chain[i])  {
-          if (!strcmp(chID,Chain[i]->chainID))
-            chain = Chain[i]; // it is there; just return the pointer
-        }
-    } else  {
-      for (i=0;(i<nChains) && (!chain);i++)
-        if (Chain[i])  {
-          if (!Chain[i]->chainID[0])
-            chain = Chain[i]; // it is there; just return the pointer
-        }
-    }
-    if (chain)  return chain;
-    strcpy ( chainID,chID );
-  }
-
-  ExpandChainArray ( nChains );
-
-  // create new chain
-  Chain[nChains] = newCChain();
-  Chain[nChains]->SetChain ( chainID );
-  Chain[nChains]->SetModel ( this );
-  nChains++;
-
-  return Chain[nChains-1];
-
-}
-
-PCChain CModel::CreateChain ( const ChainID chID )  {
-//   CreateChain() creates a new chain with chain ID regardless
-// the presence of same-ID chains in the model. This function
-// was introduced only for compatibility with older CCP4
-// applications and using it in any new developments should be
-// strictly discouraged.
-
-  ExpandChainArray ( nChains );
-
-  // create new chain
-  Chain[nChains] = newCChain();
-  Chain[nChains]->SetChain ( chID );
-  Chain[nChains]->SetModel ( this );
-  nChains++;
-
-  return Chain[nChains-1];
-
-}
-
-
-void  CModel::GetChainTable ( PPCChain & chainTable,
-                              int & NumberOfChains )  {
-  chainTable     = Chain;
-  NumberOfChains = nChains;
-}
-
-Boolean CModel::GetNewChainID ( ChainID chID, int length )  {
-int     i,k;
-Boolean found;
-
-  memset ( chID,0,sizeof(ChainID) );
-  chID[0] = 'A';
-
-  do  {
-    found = False;
-    for (i=0;(i<nChains) && (!found);i++)
-      if (Chain[i])
-        found = (!strcmp(chID,Chain[i]->chainID));
-    if (found)  {
-      k = 0;
-      while (k<length)
-        if (!chID[k])  {
-          chID[k] = 'A';
-          break;
-        } else if (chID[k]<'Z')  {
-          chID[k]++;
-          break;
-        } else  {
-          chID[k] = 'A';
-          k++;
-        }
-    } else
-      k = 0;
-  } while (found && (k<length));
-
-  if (found)  {
-    k = strlen(chID);
-    while (k<length)
-      chID[k++] = 'A';
-  }
-
-  return (!found);
-
-}
-
-
-PCChain CModel::GetChain ( const ChainID chID )  {
-//   Returns pointer on chain, whose identifier is
-// given in chID. If such a chain is absent in the
-// model, returns NULL.
-int     i;
-Boolean isChainID;
-  if (chID)  isChainID = (chID[0]!=char(0));
-       else  isChainID = False;
-  if (isChainID)  {
-    for (i=0;i<nChains;i++)
-      if (Chain[i])  {
-        if (!strcmp(chID,Chain[i]->chainID))
-          return Chain[i]; // it is there; just return the pointer
-      }
-  } else  {
-    for (i=0;i<nChains;i++)
-      if (Chain[i])  {
-        if (!Chain[i]->chainID[0])
-          return Chain[i]; // it is there; just return the pointer
-      }
-  }
-  return NULL;
-}
-
-
-//  ------------------  Deleting chains  --------------------------
-
-int CModel::DeleteChain ( int chainNo )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])  {
-      Exclude = False;
-      delete Chain[chainNo];
-      Chain[chainNo] = NULL;
-      Exclude = True;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-int CModel::DeleteChain ( const ChainID chID )  {
-int i;
-  if (chID[0])  {
-    for (i=0;i<nChains;i++)
-      if (Chain[i])  {
-        if (!strcmp(chID,Chain[i]->chainID))  {
-          Exclude  = False;
-          delete Chain[i];
-          Chain[i] = NULL;
-          Exclude  = True;
-          return 1;
-        }
-      }
-  } else  {
-    for (i=0;i<nChains;i++)
-      if (Chain[i])  {
-        if (!Chain[i]->chainID[0])  {
-          Exclude  = False;
-          delete Chain[i];
-          Chain[i] = NULL;
-          Exclude  = True;
-          return 1;
-        }
-      }
-  }
-  return 0;
-}
-
-
-int CModel::DeleteAllChains()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  {
-      delete Chain[i];
-      Chain[i] = NULL;
-      k++;
-    }
-  nChains = 0;
-  Exclude = True;
-  return k;
-}
-
-int CModel::DeleteSolventChains()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  {
-      if (Chain[i]->isSolventChain())  {
-        delete Chain[i];
-        Chain[i] = NULL;
-        k++;
-      }
-    }
-  Exclude = True;
-  return k;
-}
-
-void CModel::TrimChainTable()  {
-int i,j;
-  Exclude = False;
-  j = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  {
-      if (Chain[i]->nResidues>0)  {
-        if (j<i)  {
-          Chain[j] = Chain[i];
-          Chain[i] = NULL;
-        }
-        j++;
-      } else  {
-        delete Chain[i];
-        Chain[i] = NULL;
-      }
-    }
-  nChains = j;
-  Exclude = True;
-}
-
-
-int  CModel::GetNumberOfResidues ( const ChainID chainID )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)  return chain->nResidues;
-  return 0;
-}
-
-int  CModel::GetNumberOfResidues ( int chainNo )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->nResidues;
-  }
-  return 0;
-}
-
-PCResidue CModel::GetResidue ( const ChainID chainID, int seqNo,
-                               const InsCode insCode )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)
-    return chain->GetResidue ( seqNo,insCode );
-  return NULL;
-}
-
-PCResidue CModel::GetResidue ( const ChainID chainID, int resNo )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)  {
-    if ((0<=resNo) && (resNo<chain->nResidues))
-      return chain->Residue[resNo];
-  }
-  return NULL;
-}
-
-PCResidue CModel::GetResidue ( int chainNo, int seqNo,
-                               const InsCode insCode )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->GetResidue ( seqNo,insCode );
-  }
-  return NULL;
-}
-
-PCResidue CModel::GetResidue ( int chainNo, int resNo )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo]) {
-      if ((0<=resNo) && (resNo<Chain[chainNo]->nResidues))
-        return Chain[chainNo]->Residue[resNo];
-    }
-  }
-  return NULL;
-}
-
-int CModel::GetResidueNo ( const ChainID chainID, int seqNo,
-                           const InsCode insCode )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)
-    return chain->GetResidueNo ( seqNo,insCode );
-  return -2;
-}
-
-int CModel::GetResidueNo ( int  chainNo, int seqNo,
-                           const InsCode insCode )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->GetResidueNo ( seqNo,insCode );
-  }
-  return -2;
-}
-
-
-void CModel::GetResidueTable ( PPCResidue & resTable,
-                               int & NumberOfResidues )  {
-// resTable has to be NULL or it will be reallocated. The application
-// is responsible for deallocating the resTable (but not of its
-// residues!). This does not apply to other GetResidueTable
-// functions.
-PPCChain   chain;
-PPCResidue res;
-int        i,j,k,nChns,nResidues;
-
-  if (resTable)  {
-    delete[] resTable;
-    resTable = NULL;
-  }
-
-  NumberOfResidues = 0;
-  GetChainTable ( chain,nChns );
-  for (i=0;i<nChns;i++)
-    if (chain[i])  {
-      chain[i]->GetResidueTable ( res,nResidues );
-      NumberOfResidues += nResidues;
-    }
-
-  if (NumberOfResidues>0)  {
-    resTable = new PCResidue[NumberOfResidues];
-    k = 0;
-    GetChainTable ( chain,nChns );
-    for (i=0;i<nChns;i++)
-      if (chain[i])  {
-        chain[i]->GetResidueTable ( res,nResidues );
-        for (j=0;j<nResidues;j++)
-          if (res[j])  resTable[k++] = res[j];
-      }
-    NumberOfResidues = k;
-  }
-
-}
-
-void CModel::GetResidueTable ( const ChainID chainID,
-                               PPCResidue & resTable,
-                               int & NumberOfResidues )  {
-PCChain chain;
-  resTable         = NULL;
-  NumberOfResidues = 0;
-  chain = GetChain ( chainID );
-  if (chain)  {
-    resTable         = chain->Residue;
-    NumberOfResidues = chain->nResidues;
-  }
-}
-
-void CModel::GetResidueTable ( int chainNo, PPCResidue & resTable,
-                               int & NumberOfResidues )  {
-  resTable         = NULL;
-  NumberOfResidues = 0;
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])  {
-      resTable         = Chain[chainNo]->Residue;
-      NumberOfResidues = Chain[chainNo]->nResidues;
-    }
-  }
-}
-
-
-int CModel::DeleteResidue ( const ChainID chainID, int seqNo,
-                            const InsCode insCode )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)  return chain->DeleteResidue ( seqNo,insCode );
-  return 0;
-}
-
-int CModel::DeleteResidue ( const ChainID chainID, int resNo )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)  return chain->DeleteResidue ( resNo );
-  return 0;
-}
-
-int CModel::DeleteResidue ( int  chainNo, int seqNo,
-                            const InsCode insCode )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->DeleteResidue ( seqNo,insCode );
-  }
-  return 0;
-}
-
-int CModel::DeleteResidue ( int chainNo, int resNo )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->DeleteResidue ( resNo );
-  }
-  return 0;
-}
-
-int CModel::DeleteAllResidues ( const ChainID chainID )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)  return chain->DeleteAllResidues();
-  return 0;
-}
-
-int CModel::DeleteAllResidues ( int chainNo )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->DeleteAllResidues();
-  }
-  return 0;
-}
-
-int CModel::DeleteAllResidues()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      k += Chain[i]->DeleteAllResidues();
-  return k;
-}
-
-
-int CModel::DeleteSolvent()  {
-int i,k;
-  Exclude = False;
-  k = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  {
-      k += Chain[i]->DeleteSolvent();
-      Chain[i]->TrimResidueTable();
-      if (Chain[i]->nResidues<=0)  {
-        delete Chain[i];
-        Chain[i] = NULL;
-      }
-    }
-  Exclude = True;
-  return k;
-}
-
-
-int CModel::AddResidue ( const ChainID chainID, PCResidue res )  {
-PCChain chain;
-  chain = GetChain ( chainID );
-  if (chain)  return chain->AddResidue ( res );
-  return 0;
-}
-
-int CModel::AddResidue ( int chainNo, PCResidue res )  {
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    if (Chain[chainNo])
-      return Chain[chainNo]->AddResidue ( res );
-  }
-  return 0;
-}
-
-
-int  CModel::_ExcludeChain ( const ChainID chainID )  {
-//   _ExcludeChain(..) excludes (but does not dispose!) a chain
-// from the model. Returns 1 if the model gets empty and 0 otherwise.
-int  i,k;
-
-  if (!Exclude)  return 0;
-
-  // find the chain
-  k = -1;
-  for (i=0;(i<nChains) && (k<0);i++)
-    if (!strcmp(chainID,Chain[i]->chainID))
-      k = i;
-
-  if (k>=0)  {
-    for (i=k+1;i<nChains;i++)
-      Chain[i-1] = Chain[i];
-    nChains--;
-    Chain[nChains] = NULL;
-  }
-
-  if (nChains<=0)  return 1;
-             else  return 0;
-
-}
-
-
-//  --------------------  Sort chains  ----------------------------
-
-DefineClass(CSortChains)
-
-class CSortChains : public CQuickSort  {
-  public :
-    CSortChains() : CQuickSort() { sKey = 0; }
-    int  Compare ( int i, int j );
-    void Swap    ( int i, int j );
-    void Sort    ( PPCChain chain, int nChains, int sortKey );
-  private :
-    int sKey;
-};
-
-int CSortChains::Compare ( int i, int j )  {
-int diff;
-
-  diff = strcmp ( (PPCChain(data))[i]->GetChainID(),
-                  (PPCChain(data))[j]->GetChainID() );
-  if (diff>0)  diff =  1;
-  if (diff<0)  diff = -1;
-
-  if (sKey==SORT_CHAIN_ChainID_Desc) return -diff;
-
-  return diff;
-
-}
-
-void CSortChains::Swap ( int i, int j )  {
-PCChain chn;
-  chn = ((PPCChain)data)[i];
-  ((PPCChain)data)[i] = ((PPCChain)data)[j];
-  ((PPCChain)data)[j] = chn;
-}
-
-void CSortChains::Sort ( PPCChain chain, int nChains, int sortKey )  {
-  sKey = sortKey;
-  CQuickSort::Sort ( &(chain[0]),nChains );
-}
-
-void CModel::SortChains ( int sortKey )  {
-CSortChains SC;
-  TrimChainTable();
-  SC.Sort ( Chain,nChains,sortKey );
-}
-
-
-// --------------------  Extracting atoms  -----------------------
-
-
-int  CModel::GetNumberOfAtoms ( const ChainID chainID, int seqNo,
-                                const InsCode insCode )  {
-PCChain   chain;
-PCResidue res;
-  chain = GetChain ( chainID );
-  if (chain)  {
-    res = chain->GetResidue ( seqNo,insCode );
-    if (res)  return res->nAtoms;
-  }
-  return 0;
-}
-
-int  CModel::GetNumberOfAtoms ( int chainNo, int seqNo,
-                                const InsCode insCode )  {
-PCChain   chain;
-PCResidue res;
-  chain = GetChain ( chainNo );
-  if (chain)  {
-    res = chain->GetResidue ( seqNo,insCode );
-    if (res)  return res->nAtoms;
-  }
-  return 0;
-}
-
-int  CModel::GetNumberOfAtoms ( const ChainID chainID, int resNo )  {
-PCChain   chain;
-PCResidue res;
-  chain = GetChain ( chainID );
-  if (chain)  {
-    if ((0<=resNo) && (resNo<chain->nResidues))  {
-      res = chain->Residue[resNo];
-      if (res)  return res->nAtoms;
-    }
-  }
-  return 0;
-}
-
-int  CModel::GetNumberOfAtoms ( int chainNo, int resNo )  {
-PCChain   chain;
-PCResidue res;
-  if ((0<=chainNo) && (chainNo<nChains))  {
-    chain = Chain[chainNo];
-    if (chain)  {
-      if ((0<=resNo) && (resNo<chain->nResidues))  {
-        res = chain->Residue[resNo];
-        if (res)  return res->nAtoms;
-      }
-    }
-  }
-  return 0;
-}
-
-PCAtom  CModel::GetAtom ( const ChainID  chID,
-                          int            seqNo,
-                          const InsCode  insCode,
-                          const AtomName aname,
-                          const Element  elmnt,
-                          const AltLoc   aloc
-                        )  {
-PCChain   chn;
-PCResidue res;
-  chn = GetChain ( chID );
-  if (chn)  {
-    res = chn->GetResidue ( seqNo,insCode );
-    if (res)
-      return res->GetAtom ( aname,elmnt,aloc );
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( const ChainID chID,    int seqNo,
-                         const InsCode insCode, int   atomNo )  {
-PCChain   chn;
-PCResidue res;
-  chn = GetChain ( chID );
-  if (chn)  {
-    res = chn->GetResidue ( seqNo,insCode );
-    if (res)  {
-      if ((0<=atomNo) && (atomNo<res->nAtoms))
-        return res->atom[atomNo];
-    }
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( const ChainID  chID,
-                         int            resNo,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-PCChain   chn;
-PCResidue res;
-  chn = GetChain ( chID );
-  if (chn)  {
-    if ((0<=resNo) && (resNo<chn->nResidues))  {
-      res = chn->Residue[resNo];
-      if (res)
-        return res->GetAtom ( aname,elmnt,aloc );
-    }
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( const ChainID chID, int resNo, int atomNo )  {
-PCChain   chn;
-PCResidue res;
-  chn = GetChain ( chID );
-  if (chn)  {
-    if ((0<=resNo) && (resNo<chn->nResidues))  {
-      res = chn->Residue[resNo];
-      if (res)  {
-        if ((0<=atomNo) && (atomNo<res->nAtoms))
-          return res->atom[atomNo];
-      }
-    }
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( int chNo, int seqNo,
-                         const InsCode  insCode,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-PCResidue res;
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])  {
-      res = Chain[chNo]->GetResidue ( seqNo,insCode );
-      if (res)
-        return res->GetAtom ( aname,elmnt,aloc );
-    }
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( int chNo, int seqNo, const InsCode insCode,
-                         int atomNo )  {
-PCResidue res;
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])  {
-      res = Chain[chNo]->GetResidue ( seqNo,insCode );
-      if (res)  {
-        if ((0<=atomNo) && (atomNo<res->nAtoms))
-          return res->atom[atomNo];
-      }
-    }
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( int chNo, int resNo,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-PCResidue res;
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])  {
-      if ((0<=resNo) && (resNo<Chain[chNo]->nResidues))  {
-        res = Chain[chNo]->Residue[resNo];
-        if (res)
-          return res->GetAtom ( aname,elmnt,aloc );
-      }
-    }
-  }
-  return NULL;
-}
-
-PCAtom CModel::GetAtom ( int chNo, int resNo, int atomNo )  {
-PCResidue res;
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])  {
-      if ((0<=resNo) && (resNo<Chain[chNo]->nResidues))  {
-        res = Chain[chNo]->Residue[resNo];
-        if (res)  {
-          if ((0<=atomNo) && (atomNo<res->nAtoms))
-            return res->atom[atomNo];
-        }
-      }
-    }
-  }
-  return NULL;
-}
-
-
-void CModel::GetAtomTable ( const ChainID chainID, int seqNo,
-                            const InsCode insCode,
-                            PPCAtom & atomTable,
-                            int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  res = GetResidue ( chainID,seqNo,insCode );
-  if (res)  {
-    atomTable     = res->atom;
-    NumberOfAtoms = res->nAtoms;
-  }
-}
-
-void CModel::GetAtomTable ( int chainNo, int seqNo,
-                            const InsCode insCode,
-                            PPCAtom & atomTable,
-                            int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  res = GetResidue ( chainNo,seqNo,insCode );
-  if (res)  {
-    atomTable     = res->atom;
-    NumberOfAtoms = res->nAtoms;
-  }
-}
-
-void CModel::GetAtomTable ( const ChainID chainID, int resNo,
-                            PPCAtom & atomTable,
-                            int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  res = GetResidue ( chainID,resNo );
-  if (res)  {
-    atomTable     = res->atom;
-    NumberOfAtoms = res->nAtoms;
-  }
-}
-
-void CModel::GetAtomTable ( int chainNo, int resNo,
-                            PPCAtom & atomTable,
-                            int & NumberOfAtoms )  {
-PCResidue res;
-  atomTable     = NULL;
-  NumberOfAtoms = 0;
-  res = GetResidue ( chainNo,resNo );
-  if (res)  {
-    atomTable     = res->atom;
-    NumberOfAtoms = res->nAtoms;
-  }
-}
-
-
-void CModel::GetAtomTable1 ( const ChainID chainID, int seqNo,
-                             const InsCode insCode,
-                             PPCAtom & atomTable,
-                             int & NumberOfAtoms )  {
-PCResidue res;
-  res = GetResidue ( chainID,seqNo,insCode );
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CModel::GetAtomTable1 ( int chainNo, int seqNo,
-                             const InsCode insCode,
-                             PPCAtom & atomTable,
-                             int & NumberOfAtoms )  {
-PCResidue res;
-  res = GetResidue ( chainNo,seqNo,insCode );
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CModel::GetAtomTable1 ( const ChainID chainID, int resNo,
-                             PPCAtom & atomTable,
-                             int & NumberOfAtoms )  {
-PCResidue res;
-  res = GetResidue ( chainID,resNo );
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-void CModel::GetAtomTable1 ( int chainNo, int resNo,
-                             PPCAtom & atomTable,
-                             int & NumberOfAtoms )  {
-PCResidue res;
-  res = GetResidue ( chainNo,resNo );
-  if (res)
-    res->GetAtomTable1 ( atomTable,NumberOfAtoms );
-  else  {
-    if (atomTable)  delete[] atomTable;
-    atomTable     = NULL;
-    NumberOfAtoms = 0;
-  }
-}
-
-
-
-int  CModel::DeleteAtom ( const ChainID  chID,
-                          int            seqNo,
-                          const InsCode  insCode,
-                          const AtomName aname,
-                          const Element  elmnt,
-                          const AltLoc   aloc
-                        )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)
-    return  chn->DeleteAtom ( seqNo,insCode,aname,elmnt,aloc );
-  return 0;
-}
-
-int  CModel::DeleteAtom ( const ChainID chID,    int seqNo,
-                          const InsCode insCode, int   atomNo )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->DeleteAtom ( seqNo,insCode,atomNo );
-  return 0;
-}
-
-int  CModel::DeleteAtom ( const ChainID  chID,
-                          int            resNo,
-                          const AtomName aname,
-                          const Element  elmnt,
-                          const AltLoc   aloc )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->DeleteAtom ( resNo,aname,elmnt,aloc );
-  return 0;
-}
-
-int  CModel::DeleteAtom ( const ChainID chID, int resNo, int atomNo ) {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->DeleteAtom ( resNo,atomNo );
-  return 0;
-}
-
-int  CModel::DeleteAtom ( int chNo, int seqNo,
-                          const InsCode  insCode,
-                          const AtomName aname,
-                          const Element  elmnt,
-                          const AltLoc   aloc )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->DeleteAtom ( seqNo,insCode,aname,
-                                       elmnt,aloc );
-  }
-  return 0;
-}
-
-int CModel::DeleteAtom ( int chNo, int seqNo, const InsCode insCode,
-                         int atomNo )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return  Chain[chNo]->DeleteAtom ( seqNo,insCode,atomNo );
-  }
-  return 0;
-}
-
-int CModel::DeleteAtom ( int chNo, int resNo,
-                         const AtomName aname,
-                         const Element  elmnt,
-                         const AltLoc   aloc )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->DeleteAtom ( resNo,aname,elmnt,aloc );
-  }
-  return 0;
-}
-
-int CModel::DeleteAtom ( int chNo, int resNo, int atomNo )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->DeleteAtom ( resNo,atomNo );
-  }
-  return 0;
-}
-
-int CModel::DeleteAllAtoms ( const ChainID chID, int seqNo,
-                             const InsCode insCode )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->DeleteAllAtoms ( seqNo,insCode );
-  return 0;
-}
-
-int CModel::DeleteAllAtoms ( const ChainID chID, int resNo )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->DeleteAllAtoms ( resNo );
-  return 0;
-}
-
-int CModel::DeleteAllAtoms ( const ChainID chID )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->DeleteAllAtoms();
-  return 0;
-}
-
-int CModel::DeleteAllAtoms ( int chNo, int seqNo,
-                             const InsCode insCode )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->DeleteAllAtoms ( seqNo,insCode );
-  }
-  return 0;
-}
-
-int CModel::DeleteAllAtoms ( int chNo, int resNo )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->DeleteAllAtoms ( resNo );
-  }
-  return 0;
-}
-
-int CModel::DeleteAllAtoms ( int chNo )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->DeleteAllAtoms();
-  }
-  return 0;
-}
-
-int CModel::DeleteAllAtoms()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  k += Chain[i]->DeleteAllAtoms();
-  return k;
-}
-
-int CModel::DeleteAltLocs()  {
-//  This function leaves only alternative location with maximal
-// occupancy, if those are equal or unspecified, the one with
-// "least" alternative location indicator.
-//  The function returns the number of deleted. All tables remain
-// untrimmed, so that explicit trimming or calling FinishStructEdit()
-// is required.
-int i,n;
-
-  n = 0;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  n += Chain[i]->DeleteAltLocs();
-
-  return n;
-
-}
-
-
-int CModel::AddAtom ( const ChainID chID, int seqNo,
-                      const InsCode insCode,
-                      PCAtom atom )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->AddAtom ( seqNo,insCode,atom );
-  return 0;
-}
-
-int CModel::AddAtom ( const ChainID chID, int resNo, PCAtom  atom )  {
-PCChain chn;
-  chn = GetChain ( chID );
-  if (chn)  return chn->AddAtom ( resNo,atom );
-  return 0;
-}
-
-int CModel::AddAtom ( int chNo, int seqNo, const InsCode insCode,
-                      PCAtom atom )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->AddAtom ( seqNo,insCode,atom );
-  }
-  return 0;
-}
-
-int CModel::AddAtom ( int chNo, int resNo, PCAtom atom )  {
-  if ((0<=chNo) && (chNo<nChains))  {
-    if (Chain[chNo])
-      return Chain[chNo]->AddAtom ( resNo,atom );
-  }
-  return 0;
-}
-
-
-
-void  CModel::GetAtomStatistics ( RSAtomStat AS )  {
-  AS.Init();
-  CalcAtomStatistics ( AS );
-  AS.Finish();
-}
-
-void  CModel::CalcAtomStatistics ( RSAtomStat AS )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->CalcAtomStatistics ( AS );
-}
-
-
-
-int  CModel::ConvertPDBString ( pstr PDBString ) {
-//   Interprets PDB records DBREF, SEQADV, SEQRES, MODRES.
-//   Returns zero if the line was converted, otherwise returns a
-// non-negative value of Error_XXXX.
-//   PDBString must be not shorter than 81 characters.
-ChainID  chainID;
-PCChain  chain;
-PCHelix  helix;
-PCTurn   turn;
-PCLink   link;
-PCLinkR  linkR;
-PCCisPep cispep;
-int      RC;
-
-  //  pad input line with spaces, if necessary
-  PadSpaces ( PDBString,80 );
-
-  chainID[0] = char(0);
-  chainID[1] = char(0);
-
-  if (!strncmp(PDBString,"DBREF ",6))  {
-
-    if (PDBString[12]!=' ')  chainID[0] = PDBString[12];
-    chain = GetChainCreate ( chainID,False );
-    return chain->ConvertDBREF ( PDBString );
-
-  } else if (!strncmp(PDBString,"SEQADV",6))  {
-
-    if (PDBString[16]!=' ')  chainID[0] = PDBString[16];
-    chain = GetChainCreate ( chainID,False );
-    return chain->ConvertSEQADV ( PDBString );
-
-  } else if (!strncmp(PDBString,"SEQRES",6))  {
-
-    if (PDBString[11]!=' ')  chainID[0] = PDBString[11];
-    chain = GetChainCreate ( chainID,False );
-    return chain->ConvertSEQRES ( PDBString );
-
-  } else if (!strncmp(PDBString,"MODRES",6))  {
-
-    if (PDBString[16]!=' ')  chainID[0] = PDBString[16];
-    chain = GetChainCreate ( chainID,False );
-    return chain->ConvertMODRES ( PDBString );
-
-  } else if (!strncmp(PDBString,"HET   ",6))  {
-
-    if (PDBString[12]!=' ')  chainID[0] = PDBString[12];
-    chain = GetChainCreate ( chainID,False );
-    return chain->ConvertHET ( PDBString );
-
-  } else if (!strncmp(PDBString,"HETNAM",6))  {
-
-    HetCompounds.ConvertHETNAM ( PDBString );
-    return 0;
-
-  } else if (!strncmp(PDBString,"HETSYN",6))  {
-
-    HetCompounds.ConvertHETSYN ( PDBString );
-    return 0;
-
-  } else if (!strncmp(PDBString,"FORMUL",6))  {
-
-    HetCompounds.ConvertFORMUL ( PDBString );
-    return 0;
-
-  } else if (!strncmp(PDBString,"HELIX ",6))  {
-
-    helix = new CHelix();
-    RC    = helix->ConvertPDBASCII(PDBString);
-    if (RC==0)  Helices.AddData ( helix );
-          else  delete helix;
-    return RC;
-
-  } else if (!strncmp(PDBString,"SHEET ",6))  {
-
-    return Sheets.ConvertPDBASCII ( PDBString );
-
-  } else if (!strncmp(PDBString,"TURN  ",6))  {
-
-    turn = new CTurn();
-    RC   = turn->ConvertPDBASCII(PDBString);
-    if (RC==0)  Turns.AddData ( turn );
-          else  delete turn;
-    return RC;
-
-  } else if (!strncmp(PDBString,"LINK  ",6))  {
-
-    link = new CLink();
-    RC   = link->ConvertPDBASCII(PDBString);
-    if (RC==0)  Links.AddData ( link );
-          else  delete link;
-    return RC;
-
-
-  } else if (!strncmp(PDBString,"LINKR ",6))  {
-
-    linkR = new CLinkR();
-    RC   = linkR->ConvertPDBASCII(PDBString);
-    if (RC==0)  LinkRs.AddData ( linkR );
-          else  delete linkR;
-    return RC;
-
-  } else if (!strncmp(PDBString,"CISPEP",6))  {
-
-    cispep = new CCisPep();
-    RC   = cispep->ConvertPDBASCII(PDBString);
-    if (RC==0)  CisPeps.AddData ( cispep );
-          else  delete cispep;
-    return RC;
-
-  } else
-    return Error_WrongSection;
-
-}
-
-
-void  CModel::PDBASCIIDumpPS ( RCFile f )  {
-int i;
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->DBReference.PDBASCIIDump ( f );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->SeqAdv.PDBASCIIDump ( f );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->SeqRes.PDBASCIIDump ( f );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->ModRes.PDBASCIIDump ( f );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->Het.PDBASCIIDump ( f );
-
-  HetCompounds.PDBASCIIDump ( f );
-  Helices     .PDBASCIIDump ( f );
-  Sheets      .PDBASCIIDump ( f );
-  Turns       .PDBASCIIDump ( f );
-  Links       .PDBASCIIDump ( f );
-  LinkRs      .PDBASCIIDump ( f );
-
-}
-
-void  CModel::PDBASCIIDumpCP ( RCFile f )  {
-  CisPeps.PDBASCIIDump ( f );
-}
-
-void  CModel::PDBASCIIDump ( RCFile f )  {
-char    S[100];
-int     i;
-Boolean singleModel = True;
-
-  if (manager)
-    singleModel = (manager->nModels<=1);
-
-  if (!singleModel)  {
-    strcpy      ( S,"MODEL " );
-    PadSpaces   ( S,80 );
-    PutInteger  ( &(S[10]),serNum,4 );
-    f.WriteLine ( S );
-  }
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->PDBASCIIAtomDump ( f );
-
-  if (!singleModel)  {
-    strcpy      ( S,"ENDMDL" );
-    PadSpaces   ( S,80 );
-    f.WriteLine ( S );
-  }
-
-}
-
-
-void  CModel::MakeAtomCIF ( PCMMCIFData CIF )  {
-int  i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->MakeAtomCIF ( CIF );
-}
-
-
-void  CModel::MakePSCIF ( PCMMCIFData CIF )  {
-int  i;
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->DBReference.MakeCIF ( CIF );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->SeqAdv.MakeCIF ( CIF );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->SeqRes.MakeCIF ( CIF );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->ModRes.MakeCIF ( CIF );
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i])
-      Chain[i]->Het.MakeCIF ( CIF );
-
-  HetCompounds.MakeCIF ( CIF );
-  Helices     .MakeCIF ( CIF );
-  Sheets      .MakeCIF ( CIF );
-  Turns       .MakeCIF ( CIF );
-  Links       .MakeCIF ( CIF );
-  LinkRs      .MakeCIF ( CIF );
-
-}
-
-int  CModel::GetCIFPSClass ( PCMMCIFData CIF, int ClassID )  {
-CChainContainer  PSClass;
-PCChainContainer Dest;
-int              RC;
-cpstr            chainID;
-PCChain          chain;
-  PSClass.SetChain ( NULL );
-  RC = PSClass.GetCIF ( CIF,ClassID );
-  if (RC)  return RC;
-  chainID = PSClass.Get1stChainID();
-  while (chainID)  {
-    chain   = GetChainCreate ( chainID,False );
-    switch (ClassID)  {
-      case ClassID_DBReference : Dest = &(chain->DBReference);  break;
-      case ClassID_SeqAdv      : Dest = &(chain->SeqAdv);       break;
-      case ClassID_ModRes      : Dest = &(chain->ModRes);       break;
-      case ClassID_Het         : Dest = &(chain->Het);          break;
-      default                  : Dest = NULL;
-    }
-    if (Dest)  {
-      PSClass.MoveByChainID ( chainID,Dest );
-      Dest->SetChain ( chain );
-    } else
-      printf ( " **** PROGRAM ERROR: wrong call to"
-               " CModel::GetCIFPSClass(..)\n" );
-    chainID = PSClass.Get1stChainID();
-  }
-  return 0;
-}
-
-int  CModel::GetCIF ( PCMMCIFData CIF ) {
-CSeqRes  SeqRes;
-int      RC;
-PCChain  chain;
-
-  RC = GetCIFPSClass ( CIF,ClassID_DBReference );
-  if (RC)  return RC;
-
-  RC = GetCIFPSClass ( CIF,ClassID_SeqAdv );
-  if (RC)  return RC;
-
-  RC = SeqRes.GetCIF ( CIF );
-  while (!RC)  {
-    chain = GetChainCreate ( SeqRes.chainID,False );
-    chain->SeqRes.Copy ( &SeqRes );
-    RC    = SeqRes.GetCIF ( CIF );
-  }
-
-  RC = GetCIFPSClass ( CIF,ClassID_ModRes );
-  if (RC)  return RC;
-
-  RC = GetCIFPSClass ( CIF,ClassID_Het );
-  if (RC)  return RC;
-
-  HetCompounds.GetCIF ( CIF );
-  Helices     .GetCIF ( CIF,ClassID_Helix );
-  Sheets      .GetCIF ( CIF );
-  Turns       .GetCIF ( CIF,ClassID_Turn  );
-  Links       .GetCIF ( CIF,ClassID_Link  );
-  LinkRs      .GetCIF ( CIF,ClassID_LinkR );
-
-  return RC;
-
-}
-
-cpstr  CModel::GetEntryID()  {
-  if (manager)  return manager->Title.idCode;
-          else  return pstr("");
-}
-
-void  CModel::SetEntryID ( const IDCode idCode )  {
-  if (manager)
-    manager->SetEntryID ( idCode );
-}
-
-int   CModel::GetNumberOfAllAtoms()  {
-  if (manager)  return manager->nAtoms;
-          else  return 0;
-}
-
-int   CModel::GetSerNum()  {
-  return serNum;
-}
-
-PCAtom * CModel::GetAllAtoms()  {
-  if (manager)  return manager->Atom;
-          else  return NULL;
-}
-
-
-cpstr  CModel::GetModelID ( pstr modelID )  {
-  modelID[0] = char(0);
-  sprintf ( modelID,"/%i",serNum );
-  return modelID;
-}
-
-int   CModel::GetNumberOfModels()  {
-  if (manager)  return manager->nModels;
-          else  return 0;
-}
-
-
-void  CModel::Copy ( PCModel Model )  {
-//  modify both CModel::_copy and CModel::Copy methods simultaneously!
-int i;
-
-  FreeMemory();
-
-  if (Model)  {
-
-    serNum       = Model->serNum;
-    nChains      = Model->nChains;
-    nChainsAlloc = nChains;
-    if (nChains>0)  {
-      Chain = new PCChain[nChainsAlloc];
-      for (i=0;i<nChains;i++)  {
-        if (Model->Chain[i])  {
-          Chain[i] = newCChain();
-          Chain[i]->SetModel ( this );
-          Chain[i]->Copy ( Model->Chain[i] );
-        } else
-          Chain[i] = NULL;
-      }
-    }
-
-    HetCompounds.Copy ( &(Model->HetCompounds) );
-    Helices     .Copy ( &(Model->Helices)      );
-    Sheets      .Copy ( &(Model->Sheets)       );
-    Turns       .Copy ( &(Model->Turns)        );
-    Links       .Copy ( &(Model->Links)        );
-    LinkRs      .Copy ( &(Model->LinkRs)       );
-    CisPeps     .Copy ( &(Model->CisPeps)      );
-
-  }
-
-}
-
-void  CModel::CopyHets ( PCModel Model )  {
-  if (Model)  HetCompounds.Copy ( &(Model->HetCompounds) );
-}
-
-void  CModel::CopySecStructure ( PCModel Model )  {
-  if (Model)  {
-    Helices.Copy ( &(Model->Helices) );
-    Sheets .Copy ( &(Model->Sheets)  );
-    Turns  .Copy ( &(Model->Turns)   );
-  }
-}
-
-void  CModel::CopyLinks ( PCModel Model )  {
-  if (Model)  Links.Copy ( &(Model->Links) );
-}
-
-void  CModel::CopyLinkRs ( PCModel Model )  {
-  if (Model)  LinkRs.Copy ( &(Model->LinkRs) );
-}
-
-void  CModel::CopyCisPeps ( PCModel Model )  {
-  if (Model)  CisPeps.Copy ( &(Model->CisPeps) );
-}
-
-void  CModel::_copy ( PCModel Model )  {
-//  modify both CModel::_copy and CModel::Copy methods simultaneously!
-int i;
-
-  FreeMemory();
-
-  if (Model)  {
-
-    serNum       = Model->serNum;
-    nChains      = Model->nChains;
-    nChainsAlloc = nChains;
-    if (nChains>0)  {
-      Chain = new PCChain[nChainsAlloc];
-      for (i=0;i<nChains;i++)  {
-        if (Model->Chain[i])  {
-          Chain[i] = newCChain();
-          Chain[i]->SetModel ( this );
-          Chain[i]->_copy ( Model->Chain[i] );
-        } else
-          Chain[i] = NULL;
-      }
-    }
-
-    HetCompounds.Copy ( &(Model->HetCompounds) );
-    Helices     .Copy ( &(Model->Helices)      );
-    Sheets      .Copy ( &(Model->Sheets)       );
-    Turns       .Copy ( &(Model->Turns)        );
-    Links       .Copy ( &(Model->Links)        );
-    LinkRs      .Copy ( &(Model->LinkRs)       );
-    CisPeps     .Copy ( &(Model->CisPeps)      );
-
-  }
-
-}
-
-
-void  CModel::_copy ( PCModel Model, PPCAtom atom, int & atom_index ) {
-//  modify both CModel::_copy and CModel::Copy methods simultaneously!
-//
-//  _copy(PCModel,PPCAtom,int&) does copy atoms into array 'atom'
-// starting from position atom_index. 'atom' should be able to
-// accept all new atoms - no checks on the length of 'atom'
-// is being made. This function should not be used in applications.
-int i;
-
-  FreeMemory();
-
-  if (Model)  {
-
-    serNum       = Model->serNum;
-    nChains      = Model->nChains;
-    nChainsAlloc = nChains;
-    if (nChains>0)  {
-      Chain = new PCChain[nChainsAlloc];
-      for (i=0;i<nChains;i++)  {
-        if (Model->Chain[i])  {
-          Chain[i] = newCChain();
-          Chain[i]->SetModel ( this );
-          Chain[i]->_copy ( Model->Chain[i],atom,atom_index );
-        } else
-          Chain[i] = NULL;
-      }
-    }
-
-    HetCompounds.Copy ( &(Model->HetCompounds) );
-    Helices     .Copy ( &(Model->Helices)      );
-    Sheets      .Copy ( &(Model->Sheets)       );
-    Turns       .Copy ( &(Model->Turns)        );
-    Links       .Copy ( &(Model->Links)        );
-    LinkRs      .Copy ( &(Model->LinkRs)       );
-
-  }
-
-}
-
-
-int  CModel::AddChain ( PCChain chain )  {
-//  modify both CModel::Copy methods simultaneously!
-//
-//  Copy(PCModel,PPCAtom,int&) copies atoms into array 'atom'
-// starting from position atom_index. 'atom' should be able to
-// accept all new atoms - no checks on the length of 'atom'
-// is being made. This function should not be used in applications.
-PCModel  model1;
-int      i;
-
-  for (i=0;i<nChains;i++)
-    if (Chain[i]==chain)  return -i;  // this chain is already there
-
-  if (chain)  {
-
-    // get space for new chain
-    ExpandChainArray ( nChains );
-
-    if (chain->GetCoordHierarchy())  {
-      // The chain is associated with a coordinate hierarchy. It should
-      // remain there, therefore we physically copy all its residues
-      // and atoms.
-      Chain[nChains] = newCChain();
-      Chain[nChains]->SetModel ( this );
-      if (manager)  {
-        // get space for new atoms
-        manager->AddAtomArray ( chain->GetNumberOfAtoms(True) );
-        Chain[nChains]->_copy ( chain,manager->Atom,manager->nAtoms );
-      } else  {
-        for (i=0;i<chain->nResidues;i++)
-          Chain[nChains]->AddResidue ( chain->Residue[i] );
-      }
-    } else  {
-      // The chain is not associated with a coordinate hierarchy. Such
-      // unregistered objects are simply taken over, i.e. moved into
-      // the new destination (model).
-      Chain[nChains] = chain;
-      // remove chain from its model:
-      model1 = chain->GetModel();
-      if (model1)
-        for (i=0;i<model1->nChains;i++)
-          if (model1->Chain[i]==chain)  {
-            model1->Chain[i] = NULL;
-            break;
-          }
-      Chain[nChains]->SetModel ( this );
-      if (manager)
-        Chain[nChains]->CheckInAtoms();
-    }
-
-    nChains++;
-
-  }
-
-  return nChains;
-
-}
-
-
-void  CModel::MoveChain ( PCChain & m_chain, PPCAtom m_atom,
-                          PPCAtom  atom, int & atom_index,
-                          int  chain_ext )  {
-//   MoveChain(..) adds chain m_chain on the top Chain array.
-// The pointer on chain is then set to NULL (m_chain=NULL).
-// If chain_ext is greater than 0, the moved chain will be
-// forcefully renamed; the new name is composed as the previous
-// one + underscore + chain_ext (e.g. A_1). If thus generated
-// name duplicates any of existing chain IDs, or if chain_ext
-// was set to 0 and there is a duplication of chain IDs, the
-// name is again modified as above, with the extension number
-// generated automatically (this may result in IDs like
-// A_1_10).
-//   m_atom must give pointer to the Atom array, from which
-// the atoms belonging to m_chain, are moved to Atom array
-// given by 'atom', starting from poisition 'atom_index'.
-// 'atom_index' is then automatically updated to the next
-// free position in 'atom'.
-//   Note1: the moved atoms will occupy a continuous range
-// in 'atom' array; no checks on whether the corresponding
-// cells are occupied or not, are performed.
-//   Note2: the 'atom_index' is numbered from 0 on, i.e.
-// it is equal to atom[atom_index]->index-1; atom[]->index
-// is assigned automatically.
-ChainID   chainID;
-int       i,j,k,Ok;
-PPCChain  Chain1;
-PCResidue crRes;
-
-  if (!m_chain)  return;
-
-  // modify chain ID with the extension given
-  if (chain_ext>0)
-        sprintf ( chainID,"%s_%i",m_chain->chainID,chain_ext );
-  else  strcpy  ( chainID,m_chain->chainID );
-
-  // Choose the chain ID. If a chain with such ID is
-  // already present in the model, it will be assigned
-  // a new ID 'ID_n', where 'ID' stands for the original
-  // chain ID and 'n' is the minimum (integer) number
-  // chosen such that 'name_n' represents a new chain ID
-  // (in the model).
-  k = 0;
-  do {
-    Ok = True;
-    for (i=0;(i<nChains) && (Ok);i++)
-      if (Chain[i])
-        if (!strcmp(chainID,Chain[i]->chainID))  Ok = False;
-    if (!Ok)  {
-      k++;
-      if (chain_ext>0)
-            sprintf ( chainID,"%s_%i_%i",m_chain->chainID,
-                                         chain_ext,k );
-      else  sprintf ( chainID,"%s_%i",m_chain->chainID,k );
-    }
-  } while (!Ok);
-
-  // add chain on the top of Chain array.
-  strcpy ( m_chain->chainID,chainID );
-  if (nChains>=nChainsAlloc)  {
-    nChainsAlloc = nChains+10;
-    Chain1 = new PCChain[nChainsAlloc];
-    k = 0;
-    for (i=0;i<nChains;i++)
-      if (Chain[i])  Chain1[k++] = Chain[i];
-    for (i=k;i<nChainsAlloc;i++)
-      Chain1[i] = NULL;
-    if (Chain)  delete[] Chain;
-    Chain = Chain1;
-  }
-  Chain[nChains] = m_chain;
-  Chain[nChains]->SetModel ( this );
-  nChains++;
-
-  // Move all atoms of the chain. While residues belong
-  // atoms belong to the chain's manager class. Therefore
-  // they should be moved from one manager to another.
-  for (i=0;i<m_chain->nResidues;i++)  {
-    crRes = m_chain->Residue[i];
-    if (crRes)
-      for (j=0;j<crRes->nAtoms;j++)
-        if (crRes->atom[j])  {
-          k = crRes->atom[j]->index-1;
-          atom[atom_index] = m_atom[k];
-          atom[atom_index]->index = atom_index+1;
-          atom_index++;
-          m_atom[k] = NULL;  // moved!
-        }
-  }
-
-  m_chain = NULL;  // moved!
-
-}
-
-void CModel::GetAIndexRange ( int & i1, int & i2 )  {
-PCChain   chain;
-PCResidue res;
-int       ic,ir,ia;
-  i1 = MaxInt4;
-  i2 = MinInt4;
-  for (ic=0;ic<nChains;ic++)  {
-    chain = Chain[ic];
-    if (chain)  {
-      for (ir=0;ir<chain->nResidues;ir++)  {
-        res = chain->Residue[ir];
-        if (res)  {
-          for (ia=0;ia<res->nAtoms;ia++)
-            if (res->atom[ia])  {
-              if (res->atom[ia]->index<i1)  i1 = res->atom[ia]->index;
-              if (res->atom[ia]->index>i2)  i2 = res->atom[ia]->index;
-            }
-        }
-      }
-    }
-  }
-
-}
-
-
-void  CModel::MaskAtoms ( PCMask Mask )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->MaskAtoms ( Mask );
-}
-
-void  CModel::MaskResidues ( PCMask Mask )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->MaskResidues ( Mask );
-}
-
-void  CModel::MaskChains ( PCMask Mask )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->SetMask ( Mask );
-}
-
-void  CModel::UnmaskAtoms ( PCMask Mask )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->UnmaskAtoms ( Mask );
-}
-
-void  CModel::UnmaskResidues ( PCMask Mask )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->UnmaskResidues ( Mask );
-}
-
-void  CModel::UnmaskChains ( PCMask Mask )  {
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->RemoveMask ( Mask );
-}
-
-
-// ------ Getting Secondary Structure Elements
-
-int  CModel::GetNumberOfHelices()  {
-  return  Helices.Length();
-}
-
-int  CModel::GetNumberOfSheets()  {
-  return  Sheets.nSheets;
-}
-
-PCHelix  CModel::GetHelix ( int serialNum )  {
-  return (PCHelix)Helices.GetContainerClass ( serialNum-1 );
-}
-
-void  CModel::GetSheetID ( int serialNum, SheetID sheetID )  {
-  if ((1<=serialNum) && (serialNum<=Sheets.nSheets))  {
-    if (Sheets.Sheet[serialNum-1])  {
-      strcpy ( sheetID,Sheets.Sheet[serialNum-1]->sheetID );
-      return;
-    }
-  }
-  sheetID[0] = char(0);
-}
-
-PCSheet CModel::GetSheet ( int serialNum )  {
-  if ((1<=serialNum) && (serialNum<=Sheets.nSheets))
-        return  Sheets.Sheet[serialNum-1];
-  else  return  NULL;
-}
-
-PCSheet CModel::GetSheet ( const SheetID sheetID )  {
-int i;
-  for (i=0;i<Sheets.nSheets;i++)
-    if (Sheets.Sheet[i])  {
-      if (!strcmp(Sheets.Sheet[i]->sheetID,sheetID))
-        return Sheets.Sheet[i];
-    }
-  return NULL;
-}
-
-int  CModel::GetNumberOfStrands ( int sheetSerNum )  {
-  if ((1<=sheetSerNum) && (sheetSerNum<=Sheets.nSheets))  {
-    if (Sheets.Sheet[sheetSerNum-1])
-      return  Sheets.Sheet[sheetSerNum-1]->nStrands;
-  }
-  return 0;
-}
-
-int  CModel::GetNumberOfStrands ( const SheetID sheetID )  {
-int i;
-  for (i=0;i<Sheets.nSheets;i++)
-    if (Sheets.Sheet[i])  {
-      if (!strcmp(Sheets.Sheet[i]->sheetID,sheetID))
-        return Sheets.Sheet[i]->nStrands;
-    }
-  return 0;
-}
-
-PCStrand CModel::GetStrand ( int sheetSerNum, int strandSerNum )  {
-PCSheet Sheet;
-  if ((1<=sheetSerNum) && (sheetSerNum<=Sheets.nSheets))  {
-    Sheet = Sheets.Sheet[sheetSerNum-1];
-    if (Sheet)  {
-      if ((1<=strandSerNum) && (strandSerNum<=Sheet->nStrands))
-      return  Sheet->Strand[strandSerNum-1];
-    }
-  }
-  return NULL;
-}
-
-PCStrand CModel::GetStrand ( const SheetID sheetID,
-                             int strandSerNum )  {
-int     i;
-PCSheet Sheet;
-  for (i=0;i<Sheets.nSheets;i++)
-    if (Sheets.Sheet[i])  {
-      if (!strcmp(Sheets.Sheet[i]->sheetID,sheetID))  {
-        Sheet = Sheets.Sheet[i];
-        if (Sheet)  {
-          if ((1<=strandSerNum) && (strandSerNum<=Sheet->nStrands))
-            return  Sheet->Strand[strandSerNum-1];
-        }
-      }
-    }
-  return NULL;
-}
-
-void  CModel::RemoveSecStructure()  {
-  Helices.FreeContainer();
-  Sheets .FreeMemory   ();
-  Turns  .FreeContainer();
-}
-
-void  CModel::RemoveHetInfo()  {
-  HetCompounds.FreeMemory();
-}
-
-
-
-int  CModel::GetNumberOfLinks()  {
-  return  Links.Length();
-}
-
-PCLink  CModel::GetLink ( int serialNum )  {
-  return (PCLink)Links.GetContainerClass ( serialNum-1 );
-}
-
-void  CModel::RemoveLinks()  {
-  Links.FreeContainer();
-}
-
-void  CModel::AddLink ( PCLink Link )  {
-  Links.AddData ( Link );
-}
-
-
-int  CModel::GetNumberOfLinkRs()  {
-  return  LinkRs.Length();
-}
-
-PCLinkR  CModel::GetLinkR ( int serialNum )  {
-  return (PCLinkR)LinkRs.GetContainerClass ( serialNum-1 );
-}
-
-void  CModel::RemoveLinkRs()  {
-  LinkRs.FreeContainer();
-}
-
-void  CModel::AddLinkR ( PCLinkR LinkR )  {
-  LinkRs.AddData ( LinkR );
-}
-
-
-
-int  CModel::GetNumberOfCisPeps()  {
-  return  CisPeps.Length();
-}
-
-PCCisPep CModel::GetCisPep ( int CisPepNum )  {
-  return (PCCisPep)CisPeps.GetContainerClass ( CisPepNum-1 );
-}
-
-void  CModel::RemoveCisPeps()  {
-  CisPeps.FreeContainer();
-}
-
-void  CModel::AddCisPep ( PCCisPep CisPep )  {
-  CisPeps.AddData ( CisPep );
-}
-
-
-void  CModel::ApplyTransform ( mat44 & TMatrix )  {
-// transforms all coordinates by multiplying with matrix TMatrix
-int i;
-  for (i=0;i<nChains;i++)
-    if (Chain[i])  Chain[i]->ApplyTransform ( TMatrix );
-}
-
-Boolean CModel::isInSelection ( int selHnd )  {
-PCMask  Mask;
-  if (manager)  {
-    Mask = PCMMDBFile(manager)->GetSelMask ( selHnd );
-    if (Mask)  return CheckMask ( Mask );
-  }
-  return False;
-}
-
-
-
-// -------  user-defined data handlers
-
-int  CModel::PutUDData ( int UDDhandle, int iudd )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::putUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CModel::PutUDData ( int UDDhandle, realtype rudd )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::putUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CModel::PutUDData ( int UDDhandle, cpstr sudd )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::putUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CModel::GetUDData ( int UDDhandle, int & iudd )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::getUDData ( UDDhandle,iudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CModel::GetUDData ( int UDDhandle, realtype & rudd )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::getUDData ( UDDhandle,rudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CModel::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::getUDData ( UDDhandle,sudd,maxLen );
-  else  return  UDDATA_WrongUDRType;
-}
-
-int  CModel::GetUDData ( int UDDhandle, pstr & sudd )  {
-  if (UDDhandle & UDRF_MODEL)
-        return  CUDData::getUDData ( UDDhandle,sudd );
-  else  return  UDDATA_WrongUDRType;
-}
-
-
-// -------  calculation of Secondary Structure
-
-
-int CModel::CalcSecStructure ( Boolean flagBulge, int aminoSelHnd )  {
-// This function is contributed by Liz Potterton, University of York
-//------------------------------------------------------------------
-// Define a secondary structure type of each amino acid residue in the
-// structure.
-// Procedure:
-// Find all amino acids
-// Find all pairs of amino acids which have inter-Ca distance  < 10.0A
-// Test for hydrogen bonds between the main chain N and O of the close
-// residues and store the information in the hbonds matrix
-// Analyse the info in hbonds matrix to assign secondary structure to
-// secstr vector
-PPCResidue Res;
-PPCAtom    Ca;
-PCChain    chain;
-PSContact  contact;
-imatrix    hbonds;
-PPCAtom *  hbond_atoms;
-int        nres, ncontacts;
-int        ir1,ir2, irdif;
-int        i,j,k,l;
-
-  // 1a. Get protein residues from selection handle
-
-  if (aminoSelHnd>=0) {
-
-    manager->GetSelIndex(aminoSelHnd,Res,nres);
-//   printf ( " nres    %3i " ,nres   );
-    if (nres<=0)  return  SSERC_noResidues;
-
-  } else {
-
-    //  1b. Get all protein residues
-
-    nres = 0;
-    for (i=0;i<nChains;i++)
-      if (Chain[i])
-        nres += Chain[i]->nResidues;
-
-    if (nres<=0)  return  SSERC_noResidues;
-
-    Res  = new PCResidue[nres];
-    nres = 0;
-    for (i=0;i<nChains;i++)  {
-      chain = Chain[i];
-      if (chain)  {
-        k = chain->nResidues;
-        for (j=0;j<k;j++)
-          Res[nres++] = chain->Residue[j];
-      }
-    }
-
-
-    if (nres<=0)  {
-      delete[]  Res;
-      return  SSERC_noResidues;
-    }
-
- }
-
-  //  2. Get C-alphas of all aminoacids
-
-  Ca = new PCAtom[nres];
-  k  = 0;
-  for (i=0;i<nres;i++)
-    if (Res[i])  {
-      if (aminoSelHnd>=0 || Res[i]->isAminoacid())  {
-        Ca[i] = Res[i]->GetAtom("CA", " C", "*");
-        k++;
-      } else
-        Ca[i] = NULL;
-      Res[i]->SSE = SSE_None;
-    } else
-      Ca[i] = NULL;
-
-  if (k<=0)  {
-    delete[] Res;
-    delete[] Ca;
-    return   SSERC_noAminoacids;
-  }
-
-
-  //  3. Find all close Calphas - i.e. find the contacts between
-  //     the two equivalent sets of Ca atoms
-
-  contact   = NULL;
-  ncontacts = 0;
-  manager->SeekContacts ( Ca,nres, Ca,nres, 2.0,10.0, 2,
-                          contact,ncontacts,0 );
-  if (ncontacts<=0)  {
-    delete[] Res;
-    delete[] Ca;
-    if (contact)  delete[] contact;
-    return  SSERC_noSSE;
-  }
-
-
-  //  4. Get and initialize memory for analysing the SSE
-
-  GetMatrixMemory ( hbonds,nres,3,0,0 );
-  hbond_atoms = new PPCAtom[nres];
-  for (i=0;i<nres;i++)  {
-    hbond_atoms[i] = new PCAtom[6];
-    for (j=0;j<6;j++) hbond_atoms[i][j] = NULL;
-    for (j=0;j<3;j++) hbonds     [i][j] = 0;
-  }
-
-
-  //  5.  Loop over all close (in space) residues - excluding those
-  //      that are close in sequence
-
-  for (i=0;i<ncontacts;i++)  {
-    ir1   = contact[i].id2;
-    ir2   = contact[i].id1;
-    irdif = ir1 - ir2;
-    if (irdif>2)  {
-      //  test if there is donor Hbond from residue ir1
-      if (Res[ir1]->isMainchainHBond(Res[ir2]))  {
-        k = 0;
-        while ((hbonds[ir1][k]!=0) && (k<2))  k++;
-        hbonds     [ir1][k]   = -irdif;
-    hbond_atoms[ir1][k]   = Res[ir1]->GetAtom ( "N" );
-    hbond_atoms[ir1][k+3] = Res[ir2]->GetAtom ( "O" );
-      }
-      //  test if there is donor Hbond from residue ir2
-      if (Res[ir2]->isMainchainHBond(Res[ir1]))  {
-    k = 0;
-        while ((hbonds[ir2][k]!=0) && (k<2))  k++;
-        hbonds     [ir2][k]   = irdif;
-    hbond_atoms[ir2][k]   = Res[ir2]->GetAtom ( "N" );
-    hbond_atoms[ir2][k+3] = Res[ir1]->GetAtom ( "O" );
-      }
-    }
-  }
-
-  //  6. Assign the turns - if there is bifurcated bond then the 4-turn
-  //     takes precedence - read the paper to make sense of this
-
-  for (i=0;i<nres;i++)  {
-    k = 0;
-    while ((k<=2) && (hbonds[i][k]!=0))  {
-      if (hbonds[i][k]==-5)  {
-    Res[i-1]->SSE = SSE_5Turn;
-    Res[i-2]->SSE = SSE_5Turn;
-    Res[i-3]->SSE = SSE_5Turn;
-    Res[i-4]->SSE = SSE_5Turn;
-      }
-      if (hbonds[i][k]==-3)  {
-    Res[i-1]->SSE = SSE_3Turn;
-    Res[i-2]->SSE = SSE_3Turn;
-      }
-      k++;
-    }
-  }
-  for (i=0;i<nres;i++)  {
-    k = 0;
-    while ((k<=2) && (hbonds[i][k]!=0))  {
-      if (hbonds[i][k]==-4)  {
-        Res[i-1]->SSE = SSE_4Turn;
-        Res[i-2]->SSE = SSE_4Turn;
-        Res[i-3]->SSE = SSE_4Turn;
-      }
-      k++;
-    }
-  }
-
-
-  //  7. Look for consecutive 4-turns which make alpha helix
-
-  for (i=1;i<nres-3;i++) {
-    if (((Res[i  ]->SSE==SSE_Helix) || (Res[i  ]->SSE==SSE_4Turn)) &&
-        ((Res[i+1]->SSE==SSE_Helix) || (Res[i+1]->SSE==SSE_4Turn)) &&
-        ((Res[i+2]->SSE==SSE_Helix) || (Res[i+2]->SSE==SSE_4Turn)) &&
-        ((Res[i+3]->SSE==SSE_Helix) || (Res[i+3]->SSE==SSE_4Turn)))
-      for (j=i;j<=i+3;j++)  Res[j]->SSE = SSE_Helix;
-  }
-
-  for (i=0;i<nres;i++)  {
-
-    k = 0;
-    while ((k<=2) && (hbonds[i][k]!=0))  {
-
-      irdif = hbonds[i][k];
-      // Test for 'close' hbond
-      j = i + irdif;
-      l = 0;
-      while ((l<=2) && (hbonds[j][l]!=0))  {
-        // Antiparallel strands
-        if (hbonds[j][l]==-irdif)  {
-          Res[i]->SSE = SSE_Strand;
-          Res[j]->SSE = SSE_Strand;
-        }
-        // Parallel strand
-        if (hbonds[j][l]==-irdif-2)  {
-          Res[i-1]->SSE = SSE_Strand;
-          Res[j  ]->SSE = SSE_Strand;
-        }
-        // Parallel beta bulge
-        if (hbonds[j][l]==-irdif-3)  {
-          if (flagBulge) {
-            if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Bulge;
-            if (Res[i-2]->SSE==SSE_None)  Res[i-2]->SSE = SSE_Bulge;
-            if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Bulge;
-          } else  {
-            if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Strand;
-            if (Res[i-2]->SSE==SSE_None)  Res[i-2]->SSE = SSE_Strand;
-            if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Strand;
-          }
-        }
-        l++;
-      }
-      // Test for 'wide' hbond
-      j = i + hbonds[i][k] + 2;
-      if (j<nres)  {
-        l = 0;
-        while ((l<=2) && (hbonds[j][l]!=0))  {
-          // Antiaprallel strands
-          if (hbonds[j][l]==-irdif-4)  {
-            Res[i-1]->SSE = SSE_Strand;
-            Res[j-1]->SSE = SSE_Strand;
-          }
-          // Parallel strands
-          if (hbonds[j][l]==-irdif-2)  {
-            Res[i  ]->SSE = SSE_Strand;
-        Res[j-1]->SSE = SSE_Strand;
-          }
-          l++;
-        }
-      }
-
-      // test for anti-parallel B-bulge between 'close' hbonds
-      j = i + hbonds[i][k] - 1;
-      if (j>=0)  {
-        l = 0;
-        while ((l<=2) && (hbonds[j][l]!=0))  {
-          if (hbonds[j][l]==-irdif+1)  {
-            if (flagBulge)  {
-          if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Bulge;
-          if (Res[j+1]->SSE==SSE_None)  Res[j+1]->SSE = SSE_Bulge;
-          if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Bulge;
-            } else  {
-              if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Strand;
-              if (Res[j+1]->SSE==SSE_None)  Res[j+1]->SSE = SSE_Strand;
-              if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Strand;
-            }
-          }
-          l++;
-        }
-      }
-
-      // test for anti-parallel B-bulge between 'wide' hbonds
-      j = i + hbonds[i][k] + 3;
-      if (j<nres)  {
-        l = 0;
-        while ((l<=2) && (hbonds[j][l]!=0))  {
-          if ((hbonds[j][l]==-irdif+5) && (i>0))  {
-            if (flagBulge)  {
-              if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Bulge;
-              if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Bulge;
-              if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Bulge;
-            } else  {
-              if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Strand;
-              if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Strand;
-              if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Strand;
-            }
-          } else if (hbonds[j][l]==-irdif-3)  {
-            // and bulge in parallel strand
-        if (flagBulge)  {
-              if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Bulge;
-              if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Bulge;
-              if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Bulge;
-            }
-            else {
-              if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Strand;
-              if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Strand;
-              if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Strand;
-            }
-          }
-          l++;
-        }
-      }
-      k++;
-
-    } // Finish looping over Hbonds for residue (k loop)
-
-  }  // Finish looping over residues ( i loop)
-
-
-  //  8. Free memory
-
-  if (hbond_atoms)  {
-    for (i=0;i<nres;i++)
-      if (hbond_atoms[i])  delete[] hbond_atoms[i];
-    delete[] hbond_atoms;
-  }
-  FreeMatrixMemory ( hbonds,nres,0,0 );
-  if (contact) delete[] contact;
-  if (Res && aminoSelHnd<0) delete[] Res;
-  if (Ca)      delete[] Ca;
-
-  return  SSERC_Ok;
-
-}
-
-
-// -------  streaming
-
-void  CModel::write ( RCFile f )  {
-int  i,k;
-byte Version=3;
-
-  f.WriteByte ( &Version );
-
-  CProModel::write ( f );
-
-  f.WriteInt ( &serNum  );
-  f.WriteInt ( &nChains );
-
-  for (i=0;i<nChains;i++)  {
-    if (Chain[i])  k = 1;
-             else  k = 0;
-    f.WriteInt ( &k );
-    if (Chain[i]) Chain[i]->write ( f );
-  }
-
-  HetCompounds.write ( f );
-  Helices     .write ( f );
-  Sheets      .write ( f );
-  Turns       .write ( f );
-  Links       .write ( f );
-  LinkRs      .write ( f );
-
-}
-
-void  CModel::read ( RCFile f )  {
-int  i,k;
-byte Version;
-
-  FreeMemory();
-
-  f.ReadByte ( &Version );
-
-  CProModel::read ( f );
-
-  f.ReadInt ( &serNum  );
-  f.ReadInt ( &nChains );
-  nChainsAlloc = nChains;
-  if (nChains>0)  {
-    Chain = new PCChain[nChainsAlloc];
-    for (i=0;i<nChains;i++)  {
-      f.ReadInt ( &k );
-      if (k)  {
-        Chain[i] = newCChain();
-        Chain[i]->SetModel ( this );
-        Chain[i]->read ( f );
-      }
-    }
-  }
-
-  HetCompounds.read ( f );
-  Helices     .read ( f );
-  Sheets      .read ( f );
-  Turns       .read ( f );
-  if (Version>1)  Links .read ( f );
-  if (Version>2)  LinkRs.read ( f );
-
-}
-
-MakeFactoryFunctions(CModel)
-
-
diff --git a/mmdb/mmdb_model.h b/mmdb/mmdb_model.h
deleted file mode 100755
index fabb1cc..0000000
--- a/mmdb/mmdb_model.h
+++ /dev/null
@@ -1,1085 +0,0 @@
-//  $Id: mmdb_model.h,v 1.25 2012/01/26 17:52:20 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    30.04.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Model <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CHetCompound  ( description of het compounds    )
-//       ~~~~~~~~~  CHetCompounds ( HETNAM, HETSYN, FORMULA records )
-//                  CSSContainer  ( container for helixes and turns )
-//                  CHelix        ( helix info                      )
-//                  CStrand       ( strand info                     )
-//                  CSheet        ( sheet info                      )
-//                  CSheets       ( container for sheets            )
-//                  CTurn         ( turn info                       )
-//                  CLinkContainer   ( container for link data      )
-//                  CLink            ( link data                    )
-//                  CLinkRContainer  ( container for refmac link    )
-//                  CLinkR           ( link data                    )
-//                  CCisPepContainer ( container for CisPep data    )
-//                  CCisPep          ( CisPep data                  )
-//                  CModel        ( PDB model                       )
-//
-//  Copyright (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Model__
-#define __MMDB_Model__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_Utils__
-#include "mmdb_utils.h"
-#endif
-
-#ifndef  __MMDB_Chain__
-#include "mmdb_chain.h"
-#endif
-
-
-
-//  ====================  CHetCompound  =======================
-
-
-DefineClass(CHetCompound);
-DefineStreamFunctions(CHetCompound);
-
-class CHetCompound : public CStream  {
-
-  public :
-
-    ResName  hetID;      // Het identifiers, right-justified
-    pstr     comment;
-    int      nSynonyms;
-    psvector hetSynonym; // synonyms
-    int      compNum;    // component number
-    char     wc;         // '*' for water, otherwise space
-    pstr     Formula;    // formulas
-
-    CHetCompound ( cpstr HetName );
-    CHetCompound ( RPCStream Object );
-    ~CHetCompound();
-
-    void  AddKeyWord     ( cpstr W, Boolean Closed );
-    void  HETNAM_PDBDump ( RCFile f );
-    void  HETSYN_PDBDump ( RCFile f );
-    void  FORMUL_PDBDump ( RCFile f );
-
-    void  FormComString  ( pstr & F );
-    void  FormSynString  ( pstr & F );
-    void  FormForString  ( pstr & F );
-
-    void  Copy  ( PCHetCompound HetCompound );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void  InitHetCompound ( cpstr HetName );
-    void  FreeMemory      ();
-
-};
-
-
-//  ====================  CSSContainer  ======================
-
-DefineClass(CSSContainer);
-DefineStreamFunctions(CSSContainer);
-
-class CSSContainer : public CClassContainer  {
-
-  public :
-
-    CSSContainer  () : CClassContainer() {}
-    CSSContainer  ( RPCStream Object )
-                     : CClassContainer ( Object ) {} 
-    ~CSSContainer () {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-};
-
-
-//  ====================  CHelix  ============================
-
-DefineClass(CHelix);
-DefineStreamFunctions(CHelix);
-
-class CHelix : public CContainerClass  {
-
-  public :
-    int     serNum;      // serial number
-    HelixID helixID;     // helix ID
-    ResName initResName; // name of the helix's initial residue
-    ChainID initChainID; // chain ID for the chain containing the helix
-    int     initSeqNum;  // sequence number of the initial residue
-    InsCode initICode;   // insertion code of the initial residue
-    ResName endResName;  // name of the helix's terminal residue
-    ChainID endChainID;  // chain ID for the chain containing the helix
-    int     endSeqNum;   // sequence number of the terminal residue
-    InsCode endICode;    // insertion code of the terminal residue
-    int     helixClass;  // helix class
-    pstr    comment;     // comment about the helix
-    int     length;      // length of the helix
-
-    CHelix ();
-    CHelix ( cpstr S );
-    CHelix ( RPCStream Object );
-    ~CHelix();
-
-    void  PDBASCIIDump    ( pstr S, int N   );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_Helix; }
-
-    void  Copy  ( PCContainerClass Helix );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitHelix();
-
-};
-
-
-
-//  ====================  CStrand  ============================
-
-DefineClass(CStrand);
-DefineStreamFunctions(CStrand);
-
-class CStrand : public CStream  {
-
-  public :
-
-    StrandID sheetID;     // sheet ID
-    int      strandNo;    // strand number
-    ResName  initResName; // name of the strand's initial residue
-    ChainID  initChainID; // chain ID of initial residue in the strand
-    int      initSeqNum;  // sequence number of the initial residue
-    InsCode  initICode;   // insertion code of the initial residue
-    ResName  endResName;  // name of the strand's terminal residue
-    ChainID  endChainID;  // chain ID of terminal residue in the strand
-    int      endSeqNum;   // sequence number of the terminal residue
-    InsCode  endICode;    // insertion code of the terminal residue
-    int      sense;       // sense of strand with respect to previous
-                          //    strand
-    AtomName curAtom;     // registration; atom name in current strand
-    ResName  curResName;  // registration; residue name in current
-                          //    strand
-    ChainID  curChainID;  // registration; chain ID in current strand
-    int      curResSeq;   // registration; res-e seq numb in current
-                          //    strand
-    InsCode  curICode;    // registration; ins code in current strand
-    AtomName prevAtom;    // registration; atom name in previous strand
-    ResName  prevResName; // registration; residue name in previous
-                          //    strand
-    ChainID  prevChainID; // registration; chain ID in previous strand
-    int      prevResSeq;  // registration; res-e seq numb in previous
-                          //    strand
-    InsCode  prevICode;   // registration; ins code in previous strand
-
-    CStrand ();
-    CStrand ( RPCStream Object );
-    ~CStrand();
-
-    void  PDBASCIIDump    ( pstr S          );
-    void  MakeCIF         ( PCMMCIFData CIF );
-    int   ConvertPDBASCII ( cpstr S    );
-    int   GetCIF          ( PCMMCIFData CIF, cpstr sheet_id );
-
-    void  Copy  ( PCStrand Strand );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitStrand();
-
-};
-
-
-//  ====================  CSheet  ============================
-
-DefineClass(CSheet);
-DefineStreamFunctions(CSheet);
-
-class CSheet : public CStream  {
-
-  public :
-    SheetID   sheetID;   // sheet ID
-    int       nStrands;  // number of strands in the sheet
-    PPCStrand Strand;    // array of strands
-
-    CSheet ();
-    CSheet ( RPCStream Object );
-    ~CSheet();
-
-    void  FreeMemory();
-    void  OrderSheet();
-
-    void  PDBASCIIDump    ( RCFile f        );
-    void  MakeCIF         ( PCMMCIFData CIF );
-    int   ConvertPDBASCII ( cpstr  S   );
-    int   GetCIF          ( PCMMCIFData CIF );
-
-    void  Copy  ( PCSheet Sheet );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    void  InitSheet      ();
-    void  CIFFindStrands ( PCMMCIFData CIF, cpstr Category );
-    void  TryStrand      ( int strand_no );
-    int   GetStrand      ( int strand_no );
-
-};
-
-
-//  ====================  CSheets  ============================
-
-DefineClass(CSheets);
-DefineStreamFunctions(CSheets);
-
-class CSheets : public CStream  {
-
-  public :
-    int      nSheets;
-    PPCSheet Sheet;
-
-    CSheets ();
-    CSheets ( RPCStream Object );
-    ~CSheets();
-
-    void  FreeMemory();
-
-    void  PDBASCIIDump    ( RCFile f );
-    void  MakeCIF         ( PCMMCIFData CIF );
-    int   ConvertPDBASCII ( cpstr  S   );
-    int   GetCIF          ( PCMMCIFData CIF );
-
-    void  Copy  ( PCSheets Sheets );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    void  InitSheets    ();
-    void  CIFFindSheets ( PCMMCIFData CIF, cpstr Category );
-
-};
-
-
-//  ====================  CTurn  ============================
-
-DefineClass(CTurn);
-DefineStreamFunctions(CTurn);
-
-class CTurn : public CContainerClass  {
-
-  public :
-    int     serNum;      // serial number
-    TurnID  turnID;      // turn ID
-    ResName initResName; // name of the turn's initial residue
-    ChainID initChainID; // chain ID for the chain containing the turn
-    int     initSeqNum;  // sequence number of the initial residue
-    InsCode initICode;   // insertion code of the initial residue
-    ResName endResName;  // name of the turn's terminal residue
-    ChainID endChainID;  // chain ID for the chain containing the turn
-    int     endSeqNum;   // sequence number of the terminal residue
-    InsCode endICode;    // insertion code of the terminal residue
-    pstr    comment;     // comment about the helix
-
-    CTurn ();
-    CTurn ( cpstr S );
-    CTurn ( RPCStream Object );
-    ~CTurn();
-
-    void  PDBASCIIDump    ( pstr S, int N   );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_Turn; }
-
-    void  Copy  ( PCContainerClass Turn );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    
-    void InitTurn();
-
-};
-
-
-
-//  ====================  CHetCompounds  =======================
-
-DefineClass(CHetCompounds);
-DefineStreamFunctions(CHetCompounds);
-
-class CHetCompounds : public CStream  {
-
-  public :
-
-    int            nHets;
-    PPCHetCompound hetCompound;
-
-    CHetCompounds ();
-    CHetCompounds ( RPCStream Object );
-    ~CHetCompounds();
-
-    void  FreeMemory    ();
-
-    void  PDBASCIIDump  ( RCFile f );
-    void  ConvertHETNAM ( cpstr S );
-    void  ConvertHETSYN ( cpstr S );
-    void  ConvertFORMUL ( cpstr S );
-
-    void  MakeCIF       ( PCMMCIFData CIF );
-    void  GetCIF        ( PCMMCIFData CIF );
-
-    void  Copy  ( PCHetCompounds HetCompounds );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    Boolean Closed;
-
-    void  InitHetCompounds();
-    int   AddHetName      ( cpstr H );
-
-};
-
-
-//  ===================  CLinkContainer  =====================
-
-DefineClass(CLinkContainer);
-DefineStreamFunctions(CLinkContainer);
-
-class CLinkContainer : public CClassContainer  {
-
-  public :
-
-    CLinkContainer  () : CClassContainer() {}
-    CLinkContainer  ( RPCStream Object )
-                     : CClassContainer ( Object ) {}
-    ~CLinkContainer () {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-};
-
-
-//  ====================  CLink  ============================
-
-DefineClass(CLink);
-DefineStreamFunctions(CLink);
-
-class CLink : public CContainerClass  {
-
-  public :
-    AtomName atName1;   // name of 1st linked atom
-    AltLoc   aloc1;     // alternative location of 1st linked atom
-    ResName  resName1;  // residue name of 1st linked atom
-    ChainID  chainID1;  // chain ID of 1st linked atom
-    int      seqNum1;   // sequence number of 1st linked atom
-    InsCode  insCode1;  // insertion code of 1st linked atom
-    AtomName atName2;   // name of 2nd linked atom
-    AltLoc   aloc2;     // alternative location of 2nd linked atom
-    ResName  resName2;  // residue name of 2nd linked atom
-    ChainID  chainID2;  // chain ID of 2nd linked atom
-    int      seqNum2;   // sequence number of 2nd linked atom
-    InsCode  insCode2;  // insertion code of 2nd linked atom
-    int      s1,i1,j1,k1;  // sym id of 1st atom
-    int      s2,i2,j2,k2;  // sym id of 2nd atom
-
-    CLink ();
-    CLink ( cpstr S );
-    CLink ( RPCStream Object );
-    ~CLink();
-
-    void  PDBASCIIDump    ( pstr S, int N   );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_Link; }
-
-    void  Copy  ( PCContainerClass Link );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitLink();
-
-};
-
-//  ===================  CLinkRContainer  ====================
-
-DefineClass(CLinkRContainer);
-DefineStreamFunctions(CLinkRContainer);
-
-class CLinkRContainer : public CClassContainer  {
-
-  public :
-
-    CLinkRContainer  () : CClassContainer() {}
-    CLinkRContainer  ( RPCStream Object )
-                     : CClassContainer ( Object ) {}
-    ~CLinkRContainer () {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-};
-
-
-//  ====================  CLinkR  ============================
-
-DefineClass(CLinkR);
-DefineStreamFunctions(CLinkR);
-
-
-/*
-
-Garib's
-LINK             LYS A  27                     PLP A 255                PLPLYS
-LINK             MAN S   3                     MAN S   4                BETA1-4
-LINK        C6  BBEN B   1                O1  BMAF S   2                BEN-MAF
-LINK        OE2 AGLU A 320                C1  AMAF S   2                GLU-MAF
-LINK        OE2  GLU A  67        1.895   ZN   ZN  R   5                GLU-ZN
-LINK        NE2  HIS A  71        2.055   ZN   ZN  R   5                HIS-ZN
-LINK        O    ARG A  69        2.240   NA   NA  R   9                ARG-NA
-
-Coot's
-LINKR        O   VAL C 103                NA    NA C 401                VAL-NA
-LINKR        OD1 ASP D  58                NA    NA D 401                ASP-NA
-LINKR        O   ALA D  97                NA    NA D 401                ALA-NA
-LINKR        OG1 THR D  99                NA    NA D 401                THR-NA
-LINKR        O   SER D 101                NA    NA D 401                SER-NA
-LINKR        O   VAL D 103                NA    NA D 401                VAL-NA
-
-PDB's
-LINK         O   GLY A  49                NA    NA A6001     1555   1555  2.98
-LINK         OG1 THR A  51                NA    NA A6001     1555   1555  2.72
-LINK         OD2 ASP A  66                NA    NA A6001     1555   1555  2.72
-LINK         NE  ARG A  68                NA    NA A6001     1555   1555  2.93
-
-LINK         NE  ARG A  68                NA    NA A6001     1555   1555  2.93
-LINK         C21 2EG A   7                 C22 2EG B  19     1555   1555  1.56
-*/
-
-class CLinkR : public CContainerClass  {
-
-  public :
-    LinkRID  linkRID;   // link name
-    AtomName atName1;   // name of 1st linked atom
-    AltLoc   aloc1;     // alternative location of 1st linked atom
-    ResName  resName1;  // residue name of 1st linked atom
-    ChainID  chainID1;  // chain ID of 1st linked atom
-    int      seqNum1;   // sequence number of 1st linked atom
-    InsCode  insCode1;  // insertion code of 1st linked atom
-    AtomName atName2;   // name of 2nd linked atom
-    AltLoc   aloc2;     // alternative location of 2nd linked atom
-    ResName  resName2;  // residue name of 2nd linked atom
-    ChainID  chainID2;  // chain ID of 2nd linked atom
-    int      seqNum2;   // sequence number of 2nd linked atom
-    InsCode  insCode2;  // insertion code of 2nd linked atom
-    realtype dist;      // link distance
-
-    CLinkR ();
-    CLinkR ( cpstr S );
-    CLinkR ( RPCStream Object );
-    ~CLinkR();
-
-    void  PDBASCIIDump    ( pstr S, int N   );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_LinkR; }
-
-    void  Copy  ( PCContainerClass LinkR );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitLinkR();
-
-};
-
-
-
-//  ===================  CCisPepContainer  =====================
-
-DefineClass(CCisPepContainer);
-DefineStreamFunctions(CCisPepContainer);
-
-class CCisPepContainer : public CClassContainer  {
-
-  public :
-
-    CCisPepContainer  () : CClassContainer() {}
-    CCisPepContainer  ( RPCStream Object )
-                     : CClassContainer ( Object ) {} 
-    ~CCisPepContainer () {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-};
-
-
-//  =====================  CCisPep  ===========================
-
-DefineClass(CCisPep);
-DefineStreamFunctions(CCisPep);
-
-class CCisPep : public CContainerClass  {
-
-  public :
-    int      serNum;   //  record serial number
-    ResName  pep1;     //  residue name
-    ChainID  chainID1; //  chain identifier 1
-    int      seqNum1;  //  residue sequence number 1
-    InsCode  icode1;   //  insertion code 1
-    ResName  pep2;     //  residue name 2
-    ChainID  chainID2; //  chain identifier 2
-    int      seqNum2;  //  residue sequence number 2
-    InsCode  icode2;   //  insertion code 2
-    int      modNum;   //  model number
-    realtype measure;  //  measure of the angle in degrees.
-
-    CCisPep ();
-    CCisPep ( cpstr S );
-    CCisPep ( RPCStream Object );
-    ~CCisPep();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    int   ConvertPDBASCII ( cpstr S );
-
-//    void  MakeCIF         ( PCMMCIFData CIF, int N );
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-
-    int   GetClassID      () { return ClassID_CisPep; }
-
-    void  Copy  ( PCContainerClass CisPep );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitCisPep();
-
-};
-
-
-
-//  ====================  CModel  ===============================
-
-#define  SSERC_Ok            0
-#define  SSERC_noResidues    1
-#define  SSERC_noAminoacids  2
-#define  SSERC_noSSE         3
-
-#define  SORT_CHAIN_ChainID_Asc    0
-#define  SORT_CHAIN_ChainID_Desc   1
-
-DefineFactoryFunctions(CModel);
-
-class CModel : public CProModel  {
-
-  friend class CMMDBManager;
-  friend class CMMDBBondManager;
-  friend class CMMDBSelManager;
-  friend class CMMDBCoorManager;
-  friend class CMMDBFile;
-  friend class CChain;
-  friend class CResidue;
-  friend class CAtom;
-
-  public :
-
-    CModel ();  // SetMMDBFile() MUST be used after this constructor!
-    CModel ( PCMMDBManager MMDBF, int serialNum );
-    CModel ( RPCStream Object );
-    ~CModel();
-
-    void   SetMMDBManager   ( PCMMDBManager MMDBM, int serialNum );
-    PCMMDBManager GetCoordHierarchy() { return manager; }
-    
-    //   GetChainCreate() returns pointer on chain, whose identifier
-    // is given in chID. If such a chain is absent in the model,
-    // it is created. If enforceUniqueChainID is True and chain with
-    // the same first letter in chain ID already exists in the model,
-    // then the new chain ID will be appended with a serial number
-    // in order to keep it unique. The model will contain chains like
-    // A, A0, A1, A2, ... in such cases.
-    PCChain GetChainCreate ( const ChainID chID,
-                             Boolean enforceUniqueChainID );
-
-    //   CreateChain() creates a new chain with chain ID regardless
-    // the presence of same-ID chains in the model. This function
-    // was introduced only for compatibility with older CCP4
-    // applications and using it in any new developments should be
-    // strictly discouraged.
-    PCChain CreateChain    ( const ChainID chID );
-
-    cpstr  GetEntryID ();
-    void   SetEntryID ( const IDCode idCode );
-
-    int    GetSerNum  (); // returns the model's serial number
-
-    cpstr  GetModelID ( pstr modelID );  // returns "/mdl"
-
-    int    GetNumberOfModels  (); // returns TOTAL number of models
-    int    GetNumberOfAtoms   ( Boolean countTers ); // returns number
-                                              // of atoms in the model
-    int    GetNumberOfResidues(); // returns number of residues in
-                                  // the model
-
-
-    //  ----------------  Extracting chains  --------------------------
-
-    int  GetNumberOfChains();  // returns number of chains in the model
-    Boolean GetNewChainID ( ChainID chID, int length=1 );
-    //   GetChain() returns pointer on chain, whose identifier
-    // is given in chID. If such a chain is absent in the model,
-    // returns NULL.
-    PCChain GetChain ( const ChainID chID );
-    PCChain GetChain ( int chainNo ); // returns chainNo-th chain
-                                      // in the model;
-                                      // 0<=chainNo<nChains
-    void GetChainTable ( PPCChain & chainTable,
-                         int & NumberOfChains );
-
-    //  ------------------  Deleting chains  --------------------------
-
-    int  DeleteChain        ( const ChainID chID );
-    int  DeleteChain        ( int chainNo );
-    int  DeleteAllChains    ();
-    int  DeleteSolventChains();
-    void TrimChainTable     ();
-
-    //  -------------------  Adding chains  ---------------------------
-
-    int  AddChain ( PCChain chain );
-
-    //  --------------------  Sort chains  ----------------------------
-
-    void SortChains ( int sortKey ); // SORT_CHAIN_XXXX
-
-    //  ----------------  Extracting residues  ------------------------
-
-    int GetNumberOfResidues ( const ChainID chainID );
-    int GetNumberOfResidues ( int   chainNo );
-    PCResidue GetResidue ( const ChainID chainID, int seqNo,
-                           const InsCode insCode );
-    PCResidue GetResidue ( const ChainID chainID, int resNo );
-    PCResidue GetResidue ( int   chainNo, int seqNo,
-                           const InsCode insCode );
-    PCResidue GetResidue ( int   chainNo, int resNo );
-    int     GetResidueNo ( const ChainID chainID, int seqNo,
-                           const InsCode insCode );
-    int     GetResidueNo ( int   chainNo, int seqNo,
-                           const InsCode insCode );
-    void GetResidueTable ( PPCResidue & resTable,
-                           int & NumberOfResidues );
-    void GetResidueTable ( const ChainID chainID,
-                           PPCResidue & resTable,
-                           int & NumberOfResidues );
-    void GetResidueTable ( int   chainNo, PPCResidue & resTable,
-                           int & NumberOfResidues );
-
-    //  -----------------  Deleting residues  -------------------------
-
-    int DeleteResidue ( const ChainID chainID, int seqNo,
-                        const InsCode insCode );
-    int DeleteResidue ( const ChainID chainID, int resNo );
-    int DeleteResidue ( int   chainNo, int seqNo,
-                        const InsCode insCode );
-    int DeleteResidue ( int   chainNo, int resNo );
-    int DeleteAllResidues ( const ChainID chainID );
-    int DeleteAllResidues ( int   chainNo );
-    int DeleteSolvent     (); // in difference of DeleteSolventChains,
-                              // this will remove all solvent molecules
-                              // from the file rather then
-                              // solely-solvent chains
-    int DeleteAllResidues ();
-
-    //  ------------------  Adding residues  --------------------------
-
-    int AddResidue ( const ChainID chainID, PCResidue res );
-    int AddResidue ( int   chainNo, PCResidue res );
-
-    //  -------------------  Extracting atoms  ------------------------
-
-    int GetNumberOfAllAtoms(); // returns TOTAL number of atoms in all
-                               //    models
-    PPCAtom    GetAllAtoms (); // returns pointer to Atom array
-
-    int   GetNumberOfAtoms ( const ChainID chainID, int seqNo,
-                             const InsCode insCode );
-    int   GetNumberOfAtoms ( int   chainNo, int seqNo,
-                             const InsCode insCode );
-    int   GetNumberOfAtoms ( const ChainID chainID, int resNo );
-    int   GetNumberOfAtoms ( int   chainNo, int resNo );
-
-    PCAtom GetAtom ( const ChainID  chID,
-                     int            seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    PCAtom GetAtom ( const ChainID chID,    int seqNo,
-                     const InsCode insCode, int atomNo );
-    PCAtom GetAtom ( const ChainID  chID,
-                     int            resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    PCAtom GetAtom ( const ChainID  chID,  int resNo, int atomNo );
-    PCAtom GetAtom ( int chNo,  int seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    PCAtom GetAtom ( int chNo,  int seqNo, const InsCode insCode,
-                     int atomNo );
-    PCAtom GetAtom ( int chNo,  int resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc aloc );
-    PCAtom GetAtom ( int chNo,  int resNo, int atomNo );
-
-    void GetAtomTable ( const ChainID chainID, int seqNo,
-                        const InsCode insCode,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int   chainNo,       int seqNo,
-                        const InsCode insCode,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( const ChainID chainID, int resNo,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable ( int     chainNo,     int resNo,
-                        PPCAtom & atomTable, int & NumberOfAtoms );
-
-    //   GetAtomTable1(..) returns atom table without TER atoms and
-    // without NULL atom pointers. NumberOfAtoms returns the actual
-    // number of atom pointers in atomTable.
-    //   atomTable is allocated withing the function. If it was
-    // not set to NULL before calling the function, the latter will
-    // attempt to deallocate it first.
-    //   The application is responsible for deleting atomTable,
-    // however it must not touch atom pointers, i.e. use simply
-    // "delete atomTable;". Never pass atomTable from GetAtomTable(..)
-    // into this function, unless you set it to NULL before doing that.
-    void GetAtomTable1 ( const ChainID chainID, int seqNo,
-                         const InsCode insCode,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int   chainNo, int seqNo,
-                         const InsCode insCode,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( const ChainID chainID, int resNo,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-    void GetAtomTable1 ( int     chainNo,     int resNo,
-                         PPCAtom & atomTable, int & NumberOfAtoms );
-
-    void  GetAtomStatistics  ( RSAtomStat AS );
-    void  CalcAtomStatistics ( RSAtomStat AS );
-
-
-    //  --------------------  Deleting atoms  -------------------------
-
-    int DeleteAtom ( const ChainID  chID,
-                     int            seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( const ChainID chID,    int seqNo,
-                     const InsCode insCode, int atomNo );
-    int DeleteAtom ( const ChainID  chID,
-                     int            resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( const ChainID  chID,  int resNo, int atomNo );
-    int DeleteAtom ( int chNo,  int seqNo,
-                     const InsCode  insCode,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int chNo,  int seqNo, const InsCode insCode,
-                     int atomNo );
-    int DeleteAtom ( int chNo,  int resNo,
-                     const AtomName aname,
-                     const Element  elmnt,
-                     const AltLoc   aloc );
-    int DeleteAtom ( int chNo,  int resNo, int atomNo );
-
-    int DeleteAllAtoms ( const ChainID chID, int seqNo,
-                         const InsCode insCode );
-    int DeleteAllAtoms ( const ChainID chID, int resNo );
-    int DeleteAllAtoms ( const ChainID chID );
-    int DeleteAllAtoms ( int chNo, int seqNo, const InsCode insCode );
-    int DeleteAllAtoms ( int chNo, int resNo );
-    int DeleteAllAtoms ( int chNo );
-    int DeleteAllAtoms ();
-
-    //  DeleteAltLocs() leaves only alternative location with maximal
-    // occupancy, if those are equal or unspecified, the one with
-    // "least" alternative location indicator.
-    //  The function returns the number of deleted. All tables remain
-    // untrimmed, so that explicit trimming or calling
-    // FinishStructEdit() is required.
-    int DeleteAltLocs();
-
-
-    //  ---------------------  Adding atoms  --------------------------
-
-    int AddAtom ( const ChainID chID, int seqNo,
-                  const InsCode insCode, PCAtom atom );
-    int AddAtom ( const ChainID chID, int resNo, PCAtom  atom );
-    int AddAtom ( int   chNo, int seqNo, const InsCode insCode,
-                  PCAtom atom );
-    int AddAtom ( int   chNo, int resNo, PCAtom  atom );
-
-
-    //  ---------------------------------------------------------------
-
-    //   ConvertPDBString(..) interprets PDB records DBREF, SEQADV,
-    // SEQRES, MODRES.
-    //   Returns zero if the line was converted, otherwise returns a
-    // non-negative value of Error_XXXX.
-    //   PDBString must be not shorter than 81 characters.
-    int   ConvertPDBString ( pstr PDBString );
-
-    // PDBASCIIDumpPS(..) makes output of PDB primary structure records
-    // excluding cispeps
-    void  PDBASCIIDumpPS   ( RCFile f );
-
-    // PDBASCIIDumpCP(..) makes output of cispep records
-    void  PDBASCIIDumpCP   ( RCFile f );
-
-    // PDBASCIIDump(..) makes output of PDB coordinate (ATOM etc.)
-    // records
-    void  PDBASCIIDump     ( RCFile f );
-
-    void  MakeAtomCIF      ( PCMMCIFData CIF );
-    void  MakePSCIF        ( PCMMCIFData CIF );
-    int   GetCIF           ( PCMMCIFData CIF );
-
-    //   MoveChain(..) adds chain m_chain on the top Chain array.
-    // The pointer on chain is then set to NULL (m_chain=NULL).
-    // If chain_ext is greater than 0, the moved chain will be
-    // forcefully renamed; the new name is composed as the previous
-    // one + underscore + chain_ext (e.g. A_1). If thus generated
-    // name duplicates any of existing chain IDs, or if chain_ext
-    // was set to 0 and there is a duplication of chain IDs, the
-    // name is again modified as above, with the extension number
-    // generated automatically (this may result in IDs like
-    // A_1_10).
-    //   m_atom must give pointer to the Atom array, from which
-    // the atoms belonging to m_chain, are moved to Atom array
-    // given by 'atom', starting from poisition 'atom_index'.
-    // 'atom_index' is then automatically updated to the next
-    // free position in 'atom'.
-    //   Note1: the moved atoms will occupy a continuous range
-    // in 'atom' array; no checks on whether the corresponding
-    // cells are occupied or not, are performed.
-    //   Note2: the 'atom_index' is numbered from 0 on, i.e.
-    // it is equal to atom[atom_index]->index-1; atom[]->index
-    // is assigned automatically.
-    void  MoveChain ( PCChain & m_chain, PPCAtom m_atom,
-                      PPCAtom  atom, int & atom_index,
-                      int  chain_ext );
-
-    void  GetAIndexRange ( int & i1, int & i2 );
-
-    void  MaskAtoms      ( PCMask Mask );
-    void  MaskResidues   ( PCMask Mask );
-    void  MaskChains     ( PCMask Mask );
-    void  UnmaskAtoms    ( PCMask Mask );
-    void  UnmaskResidues ( PCMask Mask );
-    void  UnmaskChains   ( PCMask Mask );
-
-
-    //  ----  Getting Secondary Structure Elements
-
-    int  GetNumberOfHelices ();
-    int  GetNumberOfSheets  ();
-
-    PCHelix   GetHelix      ( int serialNum ); // 1<=serNum<=NofHelices
-
-    void      GetSheetID    ( int serialNum, SheetID sheetID );
-                                                 // '\0' for none
-
-    PCSheet   GetSheet      ( int   serialNum ); //1<=serNum<=NofSheets
-    PCSheet   GetSheet      ( const SheetID sheetID ); // NULL for none
-    int  GetNumberOfStrands ( int   sheetSerNum );
-    int  GetNumberOfStrands ( const SheetID sheetID );
-    PCStrand  GetStrand     ( int   sheetSerNum,
-                              int strandSerNum );
-    PCStrand  GetStrand     ( const SheetID sheetID,
-                              int strandSerNum );
-
-    PCSSContainer   GetHelices() { return &Helices;  }
-    PCSheets        GetSheets () { return &Sheets;   }
-
-    void  RemoveSecStructure();
-    int   CalcSecStructure  ( Boolean flagBulge=True,
-                              int aminoSelHnd=-1 );
-//    int   CalcSecStructure  ( Boolean flagBulge=True );
-
-    void  RemoveHetInfo     ();
-
-
-    //  ----  Working Links
-
-    int    GetNumberOfLinks ();
-    PCLink          GetLink ( int serialNum ); // 1<=serNum<=NofLinks
-    PCLinkContainer GetLinks() { return &Links; }
-
-    void   RemoveLinks();
-    void   AddLink    ( PCLink Link );
-
-    //  ----  Working Refmac Links
-
-    int    GetNumberOfLinkRs ();
-    PCLinkR          GetLinkR ( int serialNum ); // 1<=serNum<=NofLinks
-    PCLinkRContainer GetLinkRs() { return &LinkRs; }
-
-    void   RemoveLinkRs();
-    void   AddLinkR   ( PCLinkR LinkR );
-
-
-    //  ----  Working CisPeps
-
-    int       GetNumberOfCisPeps();
-    PCCisPep          GetCisPep ( int CisPepNum );
-    PCCisPepContainer GetCisPeps() { return &CisPeps; }
-
-    void  RemoveCisPeps();
-    void  AddCisPep    ( PCCisPep CisPep );
-
-
-
-    void  ApplyTransform ( mat44 & TMatrix );  // transforms all
-                                      // coordinates by multiplying
-                                      // with matrix TMatrix
-
-    Boolean isInSelection ( int selHnd );
-
-
-    // -------  user-defined data handlers
-    int   PutUDData ( int UDDhandle, int      iudd );
-    int   PutUDData ( int UDDhandle, realtype rudd );
-    int   PutUDData ( int UDDhandle, cpstr    sudd );
-
-    int   GetUDData ( int UDDhandle, int      & iudd );
-    int   GetUDData ( int UDDhandle, realtype & rudd );
-    int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
-    int   GetUDData ( int UDDhandle, pstr     & sudd );
-
-
-    void  Copy             ( PCModel Model );
-    void  CopyHets         ( PCModel Model );
-    void  CopySecStructure ( PCModel Model );
-    void  CopyLinks        ( PCModel Model );
-    void  CopyLinkRs       ( PCModel Model );
-    void  CopyCisPeps      ( PCModel Model );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    int              serNum;       // the model serial number
-    PCMMDBManager    manager;      // pointer to mmdbmanager class
-
-    CHetCompounds    HetCompounds; // information on heterocompounds
-    CSSContainer     Helices;      // information on helices
-    CSheets          Sheets;       // information on sheets
-    CSSContainer     Turns;        // information on turns
-    CLinkContainer   Links;        // information on links
-    CLinkRContainer  LinkRs;       // information on refmac links
-    CCisPepContainer CisPeps;      // information on cispeps
-
-    int              nChains;      // number of chains
-    int              nChainsAlloc; // actual length of Chain[]
-    PPCChain         Chain;        // array of chains
-
-    Boolean          Exclude;      // used internally
-
-    void  InitModel        ();
-    void  FreeMemory       ();
-    void  ExpandChainArray ( int nOfChains );
-    int   GetCIFPSClass    ( PCMMCIFData CIF, int ClassID );
-
-    //   _ExcludeChain(..) excludes (but does not dispose!) a chain
-    // from the model. Returns 1 if the chain gets empty and 0
-    // otherwise.
-    int   _ExcludeChain ( const ChainID chainID );
-
-    //  _copy(PCModel) does not copy atoms! -- not for use in
-    // applications
-    void  _copy ( PCModel Model );
-
-    //  _copy(PCModel,PPCAtom,int&) does copy atoms into array 'atom'
-    // starting from position atom_index. 'atom' should be able to
-    // accept all new atoms - no checks on the length of 'atom'
-    // is being made. This function should not be used in applications.
-    void  _copy ( PCModel Model, PPCAtom  atom, int & atom_index );
-
-    void  CheckInAtoms  ();
-
-};
-
-
-#endif
-
diff --git a/mmdb/mmdb_sbase.cpp b/mmdb/mmdb_sbase.cpp
deleted file mode 100755
index 2fa9418..0000000
--- a/mmdb/mmdb_sbase.cpp
+++ /dev/null
@@ -1,320 +0,0 @@
-//  $Id: mmdb_sbase.cpp,v 1.22 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    21.02.06   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_sbase  <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CSBase       ( structure base manager       )
-//       ~~~~~~~~~  CSBAtom      ( SB atom class                )
-//                  CSBBond      ( SB bond class                )
-//                  CSBStructure ( SB structure (monomer) class )
-//                  CSBIndex     ( SB index class               )
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MMDB_SBase__
-#include "mmdb_sbase.h"
-#endif
-
-
-//  =========================  CSBase  =============================
-
-CSBase::CSBase() : CSBase0()  {
-  InitSBase();
-}
-
-
-CSBase::~CSBase()  {
-  FreeMemory();
-}
-
-void CSBase::InitSBase()  {
-  minDAdist  = 2.0;
-  maxDAdist  = 3.9;  // max distance for H-bonds
-  maxSBdist  = 4.0;  // max distance for salt bridges
-  maxHAdist2 = 2.5*2.5;
-  maxDHAcos  = 0.0;
-  maxHAAcos  = 0.0;
-  maxDAAcos  = 0.0;
-  maxDDAcos  = 0.0;
-}
-
-void CSBase::FreeMemory()  {
-}
-
-void addAtomPair ( PCAtom a1, PCAtom a2,
-                   PSAtomPair & Pair, int & nPairs, int & nPAlloc )  {
-PSAtomPair AP;
-int        i,i1,i2,j1,j2;
-Boolean    Found;
-
-  Found = False;
-  i1    = a1->GetIndex();
-  i2    = a2->GetIndex();
-  for (i=0;(i<nPairs) && (!Found);i++)  {
-    j1 = Pair[i].a1->GetIndex();
-    j2 = Pair[i].a2->GetIndex();
-    Found = (((i1==j1) && (i2==j2)) ||
-             ((i1==j2) && (i2==j1)));
-  }
-
-  if (!Found)  {
-    if (nPairs>=nPAlloc)  {
-      nPAlloc = nPairs+20;
-      AP = new SAtomPair[nPAlloc];
-      for (i=0;i<nPairs;i++)  {
-        AP[i].a1 = Pair[i].a1;
-        AP[i].a2 = Pair[i].a2;
-      }
-      if (Pair)  delete[] Pair;
-      Pair = AP;
-    }
-    Pair[nPairs].a1 = a1;
-    Pair[nPairs].a2 = a2;
-    nPairs++;
-  }
-
-}
-
-int  CSBase::CalcHBonds ( PPCResidue Res1, int nres1,
-                          PPCResidue Res2, int nres2,
-                          RPSAtomPair   HBond, int & nHBonds,
-                          RPSAtomPair SBridge, int & nSBridges,
-                          PCFile structFile, pstr altLoc,
-                          Boolean ignoreNegSigOcc )  {
-PCFile        sFile;
-PCMMDBManager MMDB;
-PPCAtom       Donor1,Acceptor1, Donor2,Acceptor2;
-PCAtom        D,A,H;
-PSContact     Contact;
-PSAtomBond    ABond,DBond;
-SDASelHandles selHandles1,selHandles2;
-pstr          resName;
-int           nDonors1,nAcceptors1, nDonors2,nAcceptors2, nContacts;
-int           i,j,k,nDBonds,nABonds,nHBAlloc,nSBAlloc;
-Boolean       isHBond,isSBridge;
-
-  if (HBond)  {
-    delete[] HBond;
-    HBond = NULL;
-  }
-  nHBonds  = 0;
-  nHBAlloc = 0;
-
-  if (SBridge)  {
-    delete[] SBridge;
-    SBridge = NULL;
-  }
-  nSBridges = 0;
-  nSBAlloc  = 0;
-
-  //  1. Calculate bonds between atoms in given residues and
-  //     select donors and acceptors
-
-  i = 0;
-  while ((i<nres1) && (!Res1[i]))  i++;
-  if (i>=nres1)  return SBASE_EmptyResSet;
-
-  MMDB = PCMMDBManager(Res1[i]->GetCoordHierarchy());
-  if (!MMDB)  return SBASE_noCoordHierarchy;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  selHandles1.getNewHandles ( MMDB );
-  for (i=0;i<nres1;i++)
-    if (Res1[i])
-      MakeBonds ( Res1[i],altLoc,sFile,&selHandles1,ignoreNegSigOcc );
-  selHandles1.makeSelIndexes ( MMDB );
-
-  selHandles2.getNewHandles ( MMDB );
-  for (i=0;i<nres2;i++)
-    if (Res2[i])
-      MakeBonds ( Res2[i],altLoc,sFile,&selHandles2,ignoreNegSigOcc );
-  selHandles2.makeSelIndexes ( MMDB );
-
-  if (!structFile)  delete sFile;
-
-  // 2. Calculate contacts between donors and acceptors as
-  //    potential hydrogen bond contacts
-
-  MMDB->GetSelIndex ( selHandles1.selHndDonor,Donor1,nDonors1 );
-  MMDB->GetSelIndex ( selHandles2.selHndDonor,Donor2,nDonors2 );
-  if ((nDonors1<=0) && (nDonors2<=0))  {
-    selHandles1.deleteSelections ( MMDB );
-    selHandles2.deleteSelections ( MMDB );
-    return SBASE_noDonors;
-  }
-
-  MMDB->GetSelIndex(selHandles1.selHndAcceptor,Acceptor1,nAcceptors1);
-  MMDB->GetSelIndex(selHandles2.selHndAcceptor,Acceptor2,nAcceptors2);
-  if ((nAcceptors1<=0) && (nAcceptors2<=0))  {
-    selHandles1.deleteSelections ( MMDB );
-    selHandles2.deleteSelections ( MMDB );
-    return SBASE_noAcceptors;
-  }
-
-  if ((nDonors1*nAcceptors2<=0) && (nDonors2*nAcceptors1<=0))  {
-    selHandles1.deleteSelections ( MMDB );
-    selHandles2.deleteSelections ( MMDB );
-    return SBASE_noHBonds;
-  }
-
-  //   We now calculate contacts such that 1st contacting atom, either
-  // acceptor or donor, belongs to 1st set of residues, and the second
-  // one - to 2nd set of residues. Therefore we run SeekContacts on
-  // two sets of donors and acceptors, identified by different group
-  // id, merging the array of contacts for convenience.
-  Contact   = NULL;
-  nContacts = 0;
-  MMDB->SeekContacts ( Donor1,nDonors1,Acceptor2,nAcceptors2,
-                       minDAdist,RMax(maxDAdist,maxSBdist),0,Contact,
-                       nContacts,0,NULL,1,0 );
-  MMDB->SeekContacts ( Acceptor1,nAcceptors1,Donor2,nDonors2,
-                       minDAdist,RMax(maxDAdist,maxSBdist),0,Contact,
-                       nContacts,0,NULL,2,0 );
-  if (nContacts<=0)  {
-    selHandles1.deleteSelections ( MMDB );
-    selHandles2.deleteSelections ( MMDB );
-    return SBASE_noHBonds;
-  }
-
-
-  // 3. Check all contacts for h-bond geometry
-
-  // merge all hydrogens into one selection as it is used
-  // for checking with only
-  MMDB->Select ( selHandles1.selHndHydrogen,STYPE_ATOM,
-                 selHandles2.selHndHydrogen,SKEY_OR );
-
-  for (i=0;i<nContacts;i++)  {
-    if (Contact[i].group<=1)  {
-      D = Donor1   [Contact[i].id1];
-      A = Acceptor2[Contact[i].id2];
-    } else  {
-      A = Acceptor1[Contact[i].id1];
-      D = Donor2   [Contact[i].id2];
-    }
-    if (Contact[i].dist<=maxDAdist)  {
-      // Check for H-bond
-      D->GetBonds ( DBond,nDBonds );
-      A->GetBonds ( ABond,nABonds );
-      if (nABonds>0)  {
-        // Check whether there are hydrogens bound to the donor,
-        // and if they are then calculate h-bonds using them
-        H = NULL;
-        for (j=0;j<nDBonds;j++)
-          if ((DBond[j].atom->occupancy>0.0)  &&
-               DBond[j].atom->isInSelection(
-                                selHandles1.selHndHydrogen))  {
-            H = DBond[j].atom;
-            if ((H->GetDist2(A)<maxHAdist2) && 
-                (H->GetCosine(D,A)<=maxDHAcos))  {
-              // Check angles with all acceptor neighbours
-              isHBond = True;
-              for (k=0;(k<nABonds) && isHBond;k++)
-                isHBond = (A->GetCosine(H,ABond[k].atom)<=maxHAAcos);
-              if (isHBond)  {
-                if (Contact[i].group<=1)
-                      addAtomPair ( H,A,HBond,nHBonds,nHBAlloc );
-                else  addAtomPair ( A,H,HBond,nHBonds,nHBAlloc );
-              }
-            }
-          }
-        if ((!H) && (nDBonds>0))  {
-          // There were no hydrogens bonded to donor, assume that
-          // the structure is incomplete and check donor-acceptor
-          // geometry for possible h-bonding.
-          isHBond = True;
-          for (j=0;(j<nDBonds) && isHBond;j++)
-            isHBond = (D->GetCosine(DBond[j].atom,A)<=maxDDAcos);
-          for (j=0;(j<nABonds) && isHBond;j++)
-            isHBond = (A->GetCosine(D,ABond[j].atom)<=maxDAAcos);
-          if (isHBond)  {
-            if (Contact[i].group<=1)
-                  addAtomPair ( D,A,HBond,nHBonds,nHBAlloc );
-            else  addAtomPair ( A,D,HBond,nHBonds,nHBAlloc );
-          }
-        }
-      }
-    }
-    if ((Contact[i].dist<=maxSBdist)       && 
-        (D->GetResidue()!=A->GetResidue()) &&
-        (!strcmp(D->element," N")) && (!strcmp(A->element," O")))  {
-      // Check for salt bridge, which may be formed only by N-O
-      // pairs of aminoacid atoms at distances less then maxSBdist
-      if (!strcmp(D->name," N  "))  {
-        // mainchain nitrogen can form salt bridge only at N-terminus
-        isSBridge = D->isNTerminus();
-      } else  {
-        // other nitrogens can form salt bridge only in LYS, ARG
-        // and HIS
-        resName   = D->GetResName();
-        isSBridge = ((!strcmp(resName,"LYS")) ||
-                     (!strcmp(resName,"ARG")) ||
-                     (!strcmp(resName,"HIS")));
-      }
-      if (isSBridge)  {
-        if ((!strcmp(A->name," O  ")) || (!strcmp(A->name," OXT")))  {
-          // mainchain oxygens can form salt bridge only at C-terminus
-          isSBridge = A->isCTerminus();
-        } else  {
-          // other oxygens can form salt bridge only in GLU and ASP
-          resName   = A->GetResName();
-          isSBridge = ((!strcmp(resName,"GLU")) ||
-                       (!strcmp(resName,"ASP")));
-        }
-        if (isSBridge)  {
-          if (Contact[i].group<=1)
-                addAtomPair ( D,A,SBridge,nSBridges,nSBAlloc );
-          else  addAtomPair ( A,D,SBridge,nSBridges,nSBAlloc );
-        }
-      }
-    }
-  }
-
-  if (Contact)  delete[] Contact;
-
-  selHandles1.deleteSelections ( MMDB );
-  selHandles2.deleteSelections ( MMDB );
-
-  return SBASE_Ok;
-
-}
diff --git a/mmdb/mmdb_sbase.h b/mmdb/mmdb_sbase.h
deleted file mode 100755
index 32224f3..0000000
--- a/mmdb/mmdb_sbase.h
+++ /dev/null
@@ -1,142 +0,0 @@
-//  $Id: mmdb_sbase.h,v 1.21 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    21.02.06   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_sbase  <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CSBase       ( structure base manager       )
-//       ~~~~~~~~~  CSBAtom      ( SB atom class                )
-//                  CSBBond      ( SB bond class                )
-//                  CSBStructure ( SB structure (monomer) class )
-//                  CSBIndex     ( SB index class               )
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __MMDB_SBase__
-#define  __MMDB_SBase__
-
-#ifndef  __MMDB_Manager__
-#include "mmdb_manager.h"
-#endif
-
-#ifndef  __MMDB_SBase0__
-#include "mmdb_sbase0.h"
-#endif
-
-
-
-//  ===========================  CSBase  ============================
-
-DefineStructure(SAtomPair);
-
-struct SAtomPair  {
-  PCAtom a1,a2;
-};
-
-
-DefineClass(CSBase);
-
-class CSBase : public CSBase0  {
-
-  public :
-
-    CSBase ();
-    ~CSBase();
-
-    //   CalcHBonds(..) calculates hydrogen bonds and salt bridges
-    // between atoms of residues given in Res1[0..nres1-1] and
-    // Res2[0..nres2-1]. H-bonds are returned in HBond[0..nHBonds-1]
-    // and salt bridges are returned in SBridge[0..nSBridges-1].
-    //
-    //   On input:
-    //     Res1, Res2         must belong to the same MMDB
-    //     HBond, SBridge     should be set NULL, otherwise the
-    //                        function attempts to deallocate them
-    //     nHBonds, nSBridges ignored
-    //     structFile         may be a pointer to open SBase stucture
-    //                        file in order to save on file open
-    //                        operation. If structFile is set NULL,
-    //                        the function will open the SBase
-    //                        structure file by itself
-    //     altLoc             specifies the alternative location for
-    //                        donors and acceptors.
-    //                          altLoc==NULL  the highest occupancy
-    //                                        atoms are taken. If all
-    //                                        occupancies are equal
-    //                                        equal then atom with
-    //                                        first altLoc taken
-    //                          altLoc!=NULL  atoms with given altLoc
-    //                                        are taken. If such
-    //                                        altLoc is not found,
-    //                                        the function acts as
-    //                                        if NULL value for altLoc
-    //                                        were given.
-    //     ignoreNegSigOcc    if it is set True, then the function
-    //                        ignores atoms with negative occupancy
-    //                        standard deviation. Such atoms may be
-    //                        hydrogens added by
-    //                        CSBase0::AddHydrogen(..) function, in
-    //                        general any atoms added by
-    //                        CSBAtom::MakeCAtom(..) function. Such
-    //                        added hydrogens are note guaranteed to
-    //                        be in correct place, therefore the
-    //                        function may mistake on some hydrogen
-    //                        bonds if they are not neglected.
-    //
-    //   On output:
-    //     Allocated arrays HBond[0..nHBonds-1] and
-    //     SBridge[0..nSBridges-1]. If no bonds/bridges were found,
-    //     the corresponding array is not allocated and set NULL.
-    //     Application is responsible for deallocation of the arrays,
-    //     when not needed, using statements
-    //       if (HBond)    delete[] HBond;
-    //       if (SBridge)  delete[] SBridge;
-    //     HBond[i].a1, SBridge[i].a1 always refer atom from Res1[],
-    //     and HBond[i].a2, SBridge[i].a2 always refer atom from
-    //     Res2[].
-    //
-    int  CalcHBonds ( PPCResidue Res1, int nres1,
-                      PPCResidue Res2, int nres2,
-                      RPSAtomPair   HBond, int & nHBonds,
-                      RPSAtomPair SBridge, int & nSBridges,
-                      PCFile structFile=NULL, pstr altLoc=NULL,
-                      Boolean ignoreNegSigOcc=False );
-
-  protected :
-    // Geometry parameters for H-bond calculations
-    realtype minDAdist,maxSBdist,maxDAdist,maxHAdist2;
-    realtype maxDHAcos,maxHAAcos,maxDAAcos,maxDDAcos;
-
-    void InitSBase ();
-    void FreeMemory();
-
-};
-
-#endif
diff --git a/mmdb/mmdb_sbase0.cpp b/mmdb/mmdb_sbase0.cpp
deleted file mode 100755
index c7a5451..0000000
--- a/mmdb/mmdb_sbase0.cpp
+++ /dev/null
@@ -1,3124 +0,0 @@
-//  $Id: mmdb_sbase0.cpp,v 1.19 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_sbase0 <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CSBase0      ( structure base manager 0     )
-//       ~~~~~~~~~  CSBAtom      ( SB atom class                )
-//                  CSBBond      ( SB bond class                )
-//                  CSBStructure ( SB structure (monomer) class )
-//                  CSBIndex     ( SB index class               )
-//
-//   (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-
-#ifndef  __LinAlg__
-#include "linalg_.h"
-#endif
-
-#ifndef  __MMDB_SBase0__
-#include "mmdb_sbase0.h"
-#endif
-
-#ifndef  __MMDB_Tables__
-#include "mmdb_tables.h"
-#endif
-
-
-
-//  ======================  SB Atom Class  =========================
-
-CSBAtom::CSBAtom() : CStream()  {
-  SBAtomInit();
-}
-
-CSBAtom::CSBAtom ( RPCStream Object ) : CStream(Object)  {
-  SBAtomInit();
-}
-
-CSBAtom::~CSBAtom() {}
-
-void CSBAtom::SBAtomInit()  {
-  sca_name    [0] = char(0);
-  pdb_name    [0] = char(0);
-  old_pdb_name[0] = char(0);
-  element     [0] = char(0);
-  energyType  [0] = char(0);
-  x               = -MaxReal;
-  y               = -MaxReal;
-  z               = -MaxReal;
-  x_esd           = 0.0;
-  y_esd           = 0.0;
-  z_esd           = 0.0;
-  ccp4_charge     = 0.0;  // atom charge from ccp4 libs
-  sca_charge      = 0.0;  // formal atom charge (MSD)
-  partial_charge  = 0.0;  // partial atom charge (MSD)
-  vdw_radius      = 0.0;
-  vdwh_radius     = 0.0;
-  ion_radius      = 0.0;
-  valency         = 0;
-  chirality       = 'N';
-  leaving         = 'N';
-  hb_type         = 'N';
-}
-
-void CSBAtom::Copy ( PCSBAtom A )  {
-  strcpy ( sca_name    ,A->sca_name     );
-  strcpy ( pdb_name    ,A->pdb_name     );
-  strcpy ( old_pdb_name,A->old_pdb_name );
-  strcpy ( element     ,A->element      );
-  strcpy ( energyType  ,A->energyType   );
-  x              = A->x;
-  y              = A->y;
-  z              = A->z;
-  x_esd          = A->x_esd;
-  y_esd          = A->y_esd;
-  z_esd          = A->z_esd;
-  ccp4_charge    = A->ccp4_charge;
-  sca_charge     = A->sca_charge;
-  partial_charge = A->partial_charge;
-  vdw_radius     = A->vdw_radius;
-  vdwh_radius    = A->vdwh_radius;
-  ion_radius     = A->ion_radius;
-  valency        = A->valency;
-  chirality      = A->chirality;
-  leaving        = A->leaving;
-  hb_type        = A->hb_type;
-}
-
-void CSBAtom::makeCAtom ( RPCAtom a )  {
-  if (!a)  a = newCAtom();
-  a->SetAtomName    ( 0,0,pdb_name,"","",element );
-  a->SetCharge      ( ccp4_charge );
-  a->SetCoordinates ( x,y,z,1.0,0.0  );
-  strcpy ( a->energyType,energyType  );
-  a->sigOcc = -1.0;  // signal that atom was added from SBase
-}
-
-PCAtom CSBAtom::makeCAtom()  {
-PCAtom a;
-  a = newCAtom();
-  a->SetAtomName    ( 0,0,pdb_name,"","",element );
-  a->SetCharge      ( ccp4_charge );
-  a->SetCoordinates ( x,y,z,1.0,0.0 );
-  strcpy ( a->energyType,energyType );
-  a->sigOcc = -1.0;  // signal that atom was added from SBase
-  return a;
-}
-
-
-void CSBAtom::write ( RCFile f )  {
-int Version=5;
-  f.WriteInt  ( &Version                      );
-  f.WriteFile ( sca_name    ,sizeof(sca_name)     );
-  f.WriteFile ( pdb_name    ,sizeof(pdb_name)     );
-  f.WriteFile ( old_pdb_name,sizeof(old_pdb_name) );
-  f.WriteFile ( element     ,sizeof(element)      );
-  f.WriteFile ( energyType  ,sizeof(energyType)   );
-  f.WriteReal ( &x                            );
-  f.WriteReal ( &y                            );
-  f.WriteReal ( &z                            );
-  f.WriteReal ( &x_esd                        );
-  f.WriteReal ( &y_esd                        );
-  f.WriteReal ( &z_esd                        );
-  f.WriteReal ( &ccp4_charge                  );
-  f.WriteReal ( &sca_charge                   );
-  f.WriteReal ( &partial_charge               );
-  f.WriteReal ( &vdw_radius                   );
-  f.WriteReal ( &vdwh_radius                  );
-  f.WriteReal ( &ion_radius                   );
-  f.WriteInt  ( &valency                      );
-  f.WriteFile ( &chirality,sizeof(chirality)  );
-  f.WriteFile ( &leaving  ,sizeof(leaving)    );
-  f.WriteFile ( &hb_type  ,sizeof(hb_type)    );
-}
-
-void CSBAtom::read ( RCFile f )  {
-int Version;
-  f.ReadInt  ( &Version                      );
-  f.ReadFile ( sca_name  ,sizeof(sca_name)   );
-  f.ReadFile ( pdb_name  ,sizeof(pdb_name)   );
-  if (Version>4)
-    f.ReadFile ( old_pdb_name,sizeof(old_pdb_name) );
-  else  strcpy ( old_pdb_name,pdb_name );
-  f.ReadFile ( element   ,sizeof(element)    );
-  f.ReadFile ( energyType,sizeof(energyType) );
-  f.ReadReal ( &x                            );
-  f.ReadReal ( &y                            );
-  f.ReadReal ( &z                            );
-  f.ReadReal ( &x_esd                        );
-  f.ReadReal ( &y_esd                        );
-  f.ReadReal ( &z_esd                        );
-  if (Version>2)
-    f.ReadReal ( &ccp4_charge    );
-  if (Version>3)  {
-    f.ReadReal ( &sca_charge     );
-    f.ReadReal ( &partial_charge );
-  }
-  if (Version>1)  {
-    f.ReadReal ( &vdw_radius  );
-    f.ReadReal ( &vdwh_radius );
-    f.ReadReal ( &ion_radius  );
-    f.ReadInt  ( &valency     );
-  }
-  f.ReadFile ( &chirality,sizeof(chirality)  );
-  f.ReadFile ( &leaving  ,sizeof(leaving)    );
-  if (Version>1)
-    f.ReadFile ( &hb_type,sizeof(hb_type) );
-}
-
-MakeStreamFunctions(CSBAtom)
-
-
-
-//  =======================  SB Bond Class  =======================
-
-CSBBond::CSBBond() : CStream()  {
-  SBBondInit();
-}
-
-CSBBond::CSBBond ( RPCStream Object ) : CStream(Object)  {
-  SBBondInit();
-}
-
-CSBBond::~CSBBond() {}
-
-void CSBBond::SBBondInit()  {
-  atom1      = -1;
-  atom2      = -1;
-  order      = BOND_SINGLE;
-  length     = 0.0;
-  length_esd = 0.0;
-}
-
-void CSBBond::SetBond ( int at1, int at2, int ord )  {
-  atom1 = at1;
-  atom2 = at2;
-  order = ord;
-}
-
-void CSBBond::Copy ( PCSBBond B )  {
-  atom1      = B->atom1;
-  atom2      = B->atom2;
-  order      = B->order;
-  length     = B->length;
-  length_esd = B->length_esd;
-}
-
-void CSBBond::write ( RCFile f )  {
-int Version=1;
-  f.WriteInt  ( &Version    );
-  f.WriteInt  ( &atom1      );
-  f.WriteInt  ( &atom2      );
-  f.WriteInt  ( &order      );
-  f.WriteReal ( &length     );
-  f.WriteReal ( &length_esd );
-}
-
-void CSBBond::read ( RCFile f )  {
-int Version;
-  f.ReadInt  ( &Version    );
-  f.ReadInt  ( &atom1      );
-  f.ReadInt  ( &atom2      );
-  f.ReadInt  ( &order      );
-  f.ReadReal ( &length     );
-  f.ReadReal ( &length_esd );
-}
-
-
-MakeStreamFunctions(CSBBond)
-
-
-
-//  =======================  SB Angle Class  =====================
-
-CSBAngle::CSBAngle() : CStream()  {
-  SBAngleInit();
-}
-
-CSBAngle::CSBAngle ( RPCStream Object ) : CStream(Object)  {
-  SBAngleInit();
-}
-
-CSBAngle::~CSBAngle() {}
-
-void CSBAngle::SBAngleInit()  {
-  atom1     = -1;
-  atom2     = -1;
-  atom3     = -1;
-  angle     = 0.0;
-  angle_esd = 0.0;
-}
-
-void CSBAngle::Copy ( PCSBAngle G )  {
-  atom1     = G->atom1;
-  atom2     = G->atom2;
-  atom3     = G->atom3;
-  angle     = G->angle;
-  angle_esd = G->angle_esd;
-}
-
-void CSBAngle::write ( RCFile f )  {
-int Version=1;
-  f.WriteInt  ( &Version   );
-  f.WriteInt  ( &atom1     );
-  f.WriteInt  ( &atom2     );
-  f.WriteInt  ( &atom3     );
-  f.WriteReal ( &angle     );
-  f.WriteReal ( &angle_esd );
-}
-
-void CSBAngle::read ( RCFile f )  {
-int Version;
-  f.ReadInt  ( &Version   );
-  f.ReadInt  ( &atom1     );
-  f.ReadInt  ( &atom2     );
-  f.ReadInt  ( &atom3     );
-  f.ReadReal ( &angle     );
-  f.ReadReal ( &angle_esd );
-}
-
-
-MakeStreamFunctions(CSBAngle)
-
-
-
-//  ======================  SB Torsion Class  ===================
-
-CSBTorsion::CSBTorsion() : CStream()  {
-  SBTorsionInit();
-}
-
-CSBTorsion::CSBTorsion ( RPCStream Object ) : CStream(Object)  {
-  SBTorsionInit();
-}
-
-CSBTorsion::~CSBTorsion() {}
-
-void CSBTorsion::SBTorsionInit()  {
-  atom1       = -1;
-  atom2       = -1;
-  atom3       = -1;
-  atom4       = -1;
-  torsion     = 0.0;
-  torsion_esd = 0.0;
-}
-
-void CSBTorsion::Copy ( PCSBTorsion T )  {
-  atom1       = T->atom1;
-  atom2       = T->atom2;
-  atom3       = T->atom3;
-  atom4       = T->atom4;
-  torsion     = T->torsion;
-  torsion_esd = T->torsion_esd;
-}
-
-void CSBTorsion::write ( RCFile f )  {
-int Version=1;
-  f.WriteInt  ( &Version     );
-  f.WriteInt  ( &atom1       );
-  f.WriteInt  ( &atom2       );
-  f.WriteInt  ( &atom3       );
-  f.WriteInt  ( &atom4       );
-  f.WriteReal ( &torsion     );
-  f.WriteReal ( &torsion_esd );
-}
-
-void CSBTorsion::read ( RCFile f )  {
-int Version;
-  f.ReadInt  ( &Version     );
-  f.ReadInt  ( &atom1       );
-  f.ReadInt  ( &atom2       );
-  f.ReadInt  ( &atom3       );
-  f.ReadInt  ( &atom4       );
-  f.ReadReal ( &torsion     );
-  f.ReadReal ( &torsion_esd );
-}
-
-
-MakeStreamFunctions(CSBTorsion)
-
-
-
-//  ====================  Structure Class  =========================
-
-CSBStructure::CSBStructure() : CStream()  {
-  SBStructureInit();
-}
-
-CSBStructure::CSBStructure ( RPCStream Object ) : CStream(Object)  {
-  SBStructureInit();
-}
-
-CSBStructure::~CSBStructure() {
-  FreeMemory();
-}
-
-void CSBStructure::Reset()  {
-  FreeMemory();
-  SBStructureInit();
-}
-
-void CSBStructure::FreeMemory()  {
-int i;
-
-  if (Formula) delete[] Formula;
-  if (Name)    delete[] Name;
-  if (Synonym) delete[] Synonym;
-  if (Charge)  delete[] Charge;
-  Formula = NULL;
-  Name    = NULL;
-  Synonym = NULL;
-  Charge  = NULL;
-
-  FreeVectorMemory ( leavingAtom,0 );
-  FreeVectorMemory ( bondedAtom ,0 );
-  nLeavingAtoms = 0;
-
-  for (i=0;i<nAAlloc;i++)
-    if (Atom[i])  delete Atom[i];
-  if (Atom)  delete[] Atom;
-  Atom    = NULL;
-  nAtoms  = 0;
-  nAAlloc = 0;
-
-  for (i=0;i<nBAlloc;i++)
-    if (Bond[i])  delete Bond[i];
-  if (Bond)  delete[] Bond;
-  Bond    = NULL;
-  nBonds  = 0;
-  nBAlloc = 0;
-
-  for (i=0;i<nGAlloc;i++)
-    if (Angle[i])  delete Angle[i];
-  if (Angle)  delete[] Angle;
-  Angle   = NULL;
-  nAngles = 0;
-  nGAlloc = 0;
-
-  for (i=0;i<nTAlloc;i++)
-    if (Torsion[i])  delete Torsion[i];
-  if (Torsion)  delete[] Torsion;
-  Torsion   = NULL;
-  nTorsions = 0;
-  nTAlloc   = 0;
-
-}
-
-void CSBStructure::SBStructureInit()  {
-
-  compoundID[0] = char(0);
-
-  Formula = NULL;
-  Name    = NULL;
-  Synonym = NULL;
-  Charge  = NULL;
-
-  nLeavingAtoms = 0;
-  leavingAtom   = NULL;
-  bondedAtom    = NULL;
-
-  Atom      = NULL;
-  nAtoms    = 0;
-  nAAlloc   = 0;
-
-  Bond      = NULL;
-  nBonds    = 0;
-  nBAlloc   = 0;
-
-  Angle     = NULL;
-  nAngles   = 0;
-  nGAlloc   = 0;
-
-  Torsion   = NULL;
-  nTorsions = 0;
-  nTAlloc   = 0;
-
-  xyz_source = 'N';
-
-}
-
-void CSBStructure::PutFormula ( cpstr F )  {
-  CreateCopy ( Formula,F );
-}
-
-void CSBStructure::PutName ( cpstr N )  {
-  CreateCopy ( Name,N );
-}
-
-void CSBStructure::PutSynonym ( cpstr S )  {
-  CreateCopy ( Synonym,S );
-}
-
-void CSBStructure::PutCharge ( cpstr G )  {
-  CreateCopy ( Charge,G );
-}
-
-void CSBStructure::AddAtom ( PCSBAtom atom )  {
-PPCSBAtom Atom1;
-int       i;
-  if (nAtoms>=nAAlloc)  {
-    nAAlloc += 50;
-    Atom1 = new PCSBAtom[nAAlloc];
-    for (i=0;i<nAtoms;i++)
-      Atom1[i] = Atom[i];
-    for (i=nAtoms;i<nAAlloc;i++)
-      Atom1[i] = NULL;
-    if (Atom)  delete[] Atom;
-    Atom = Atom1;
-  }
-  Atom[nAtoms++] = atom;
-}
-
-void CSBStructure::AddBond ( PCSBBond bond )  {
-//  should be called after all atoms are set up
-PPCSBBond Bond1;
-int       i;
-  if (nBonds>=nBAlloc)  {
-    nBAlloc += 50;
-    Bond1 = new PCSBBond[nBAlloc];
-    for (i=0;i<nBonds;i++)
-      Bond1[i] = Bond[i];
-    for (i=nBonds;i<nBAlloc;i++)
-      Bond1[i] = NULL;
-    if (Bond)  delete[] Bond;
-    Bond = Bond1;
-  }
-  Bond[nBonds++] = bond;
-}
-
-void CSBStructure::MakeLeavingAtoms()  {
-//  should be called after all atoms and bonds are set up
-int i,j;
-
-  FreeVectorMemory ( leavingAtom,0 );
-  FreeVectorMemory ( bondedAtom ,0 );
-
-  nLeavingAtoms = 0;
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i]->leaving=='Y')
-      nLeavingAtoms++;
-
-  if (nLeavingAtoms>0)  {
-    GetVectorMemory ( leavingAtom,nLeavingAtoms,0 );
-    GetVectorMemory ( bondedAtom ,nLeavingAtoms,0 );
-    j = 0;
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i]->leaving=='Y')  {
-        leavingAtom[j] = i+1;
-        bondedAtom [j] = 0;
-        j++;
-      }
-    for (i=0;i<nLeavingAtoms;i++)
-      for (j=0;j<nBonds;j++)  {
-        if ((leavingAtom[i]==Bond[j]->atom1) &&
-            (strcmp(Atom[Bond[j]->atom2-1]->element," H")))
-          bondedAtom[i] = Bond[j]->atom2;
-        else if ((leavingAtom[i]==Bond[j]->atom2) &&
-            (strcmp(Atom[Bond[j]->atom1-1]->element," H")))
-          bondedAtom[i] = Bond[j]->atom1;
-      }
-  }
-
-}
-
-void CSBStructure::AddAngle ( PCSBAngle angle )  {
-PPCSBAngle Angle1;
-int        i;
-  if (nAngles>=nGAlloc)  {
-    nGAlloc += 50;
-    Angle1 = new PCSBAngle[nGAlloc];
-    for (i=0;i<nAngles;i++)
-      Angle1[i] = Angle[i];
-    for (i=nAngles;i<nGAlloc;i++)
-      Angle1[i] = NULL;
-    if (Angle)  delete[] Angle;
-    Angle = Angle1;
-  }
-  Angle[nAngles++] = angle;
-}
-
-void CSBStructure::AddTorsion ( PCSBTorsion torsion )  {
-PPCSBTorsion Torsion1;
-int          i;
-  if (nTorsions>=nTAlloc)  {
-    nTAlloc += 50;
-    Torsion1 = new PCSBTorsion[nTAlloc];
-    for (i=0;i<nTorsions;i++)
-      Torsion1[i] = Torsion[i];
-    for (i=nTorsions;i<nTAlloc;i++)
-      Torsion1[i] = NULL;
-    if (Torsion)  delete[] Torsion;
-    Torsion = Torsion1;
-  }
-  Torsion[nTorsions++] = torsion;
-}
-
-void CSBStructure::RemoveEnergyTypes()  {
-int i;
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])  Atom[i]->energyType[0] = char(0);
-}
-
-int  CSBStructure::SetEnergyType ( cpstr sca_name,
-                                   cpstr energyType,
-                                   realtype partial_charge )  {
-int n;
-  n = GetAtomNo ( sca_name );
-  if (n>0)  {
-    strcpy ( Atom[n-1]->energyType,energyType );
-    Atom[n-1]->partial_charge = partial_charge;
-  }
-  return n;
-}
-
-int CSBStructure::GetAtomNo ( cpstr sca_name )  {
-int n,i;
-  n = 0;
-  for (i=0;(i<nAtoms) && (!n);i++)
-    if (Atom[i])  {
-      if (!strcmp(sca_name,Atom[i]->sca_name))
-        n = i+1;
-    }
-  return n;
-}
-
-int CSBStructure::GetAtomNo_nss ( cpstr sca_name )  {
-// disregards leading and trailing spaces
-AtomName name_0;
-AtomName name_i;
-int n,i;
-  strcpy_css ( name_0,sca_name );
-//  printf ( " name_0 = '%s'\n",name_0 );
-  n = 0;
-  for (i=0;(i<nAtoms) && (!n);i++)
-    if (Atom[i])  {
-      strcpy_css ( name_i,Atom[i]->sca_name );
-//      printf ( " name_i = '%s'\n",name_i );
-      if (!strcmp(name_0,name_i))
-        n = i+1;
-    }
-  return n;
-}
-
-PCSBAtom CSBStructure::GetAtom ( cpstr sca_name )  {
-int n;
-  n = GetAtomNo ( sca_name );
-  if (n>0)  return Atom[n-1];
-      else  return NULL;
-}
-
-
-void CSBStructure::GetAtomTable ( PPCAtom & atomTable,
-                                  int & nOfAtoms )  {
-int i;
-  nOfAtoms = nAtoms;
-  if (nAtoms>0)  {
-    atomTable = new PCAtom[nAtoms];
-    for (i=0;i<nAtoms;i++)  {
-      atomTable[i] = NULL;
-      if (Atom[i])  Atom[i]->makeCAtom ( atomTable[i] );
-    }
-  } else
-    atomTable = NULL;
-}
-
-void CSBStructure::GetAtomNameMatch ( PPCAtom A, int nat, pstr altLoc,
-                                      ivector anmatch )  {
-//  GetAtomNameMatch(..) returns anmatch[i], i=0..nAtoms-1, equal
-// to j such that name(Atom[i])==name(A[j]). Note that atom names
-// are similarly aligned and space-padded in both MMDb and SBase.
-// If ith atom in the structue is not found in A, anmatch[i] is
-// set -1.
-//   If array A contains atoms in different alternative conformations,
-// the the value of altLoc is interpreted as follows:
-//    NULL  - the highest occupancy atom will be taken
-//            if all occupancies are equal then atom with
-//            first altLoc taken
-//    other - atoms with given altLoc are taken. If such
-//            altLoc is not found, the function does as if
-//            NULL value for altLoc is given.
-//   A clean PDB file is anticipated, so that atoms with alternative
-// conformations are grouped together.
-//   It is Ok to have NULL pointers in A.
-int     i,j,k;
-Boolean done;
-
-  for (i=0;i<nAtoms;i++)  {
-    k    = -1;
-    j    = 0;
-    done = False;
-    while ((j<nat) && (!done))  {
-      if (A[j])  {
-        if ((!A[j]->Ter) && (!strcmp(A[j]->name,Atom[i]->pdb_name)))  {
-          k = j;  // atom found
-          // check now for altLocs
-          j++;
-          while ((j<nat) && (!done))  {
-            if (A[j])  {
-              done = (A[j]->Ter ||
-                      (strcmp(A[j]->name,Atom[i]->pdb_name)));
-              if (!done)  {
-                if (A[j]->occupancy>A[k]->occupancy)  k = j;
-                if (altLoc)  {
-                  if (!strcmp(A[j]->altLoc,altLoc))  {
-                    k    = j;
-                    done = True;
-                  }
-                } 
-              }
-            }
-            j++;
-          }
-        }
-      }
-      j++;
-    }
-    anmatch[i] = k;
-  }
-
-}
-
-int CSBStructure::CheckAtoms()  {
-//  CheckAtoms() returns -1 if there is no atoms
-//                       -2 if not all atoms are annotated
-//                       -3 if not all coordinates are set
-//                        0 otherwise
-int i,rc;
-  if (nAtoms<=0)  return -1;
-  for (i=0;i<nAtoms;i++)
-    if (!Atom[i])  {
-      rc = -2;
-      break;
-    } else if (Atom[i]->x==-MaxReal)
-      rc = -3;
-  return rc;
-}
-
-PCResidue CSBStructure::makeCResidue ( Boolean includeHydrogens,
-                                       Boolean makeTer )  {
-PCResidue Res;
-int       i;
-  Res = newCResidue();
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])  {
-      if ((makeTer || strcmp(&(Atom[i]->pdb_name[2]),"XT")) &&
-          (includeHydrogens || strcmp(Atom[i]->element," H")))
-          Res->AddAtom ( Atom[i]->makeCAtom() );
-    }
-  return Res;
-}
-
-
-
-int  superpose_atoms ( mat44 & T, PPCSBAtom A1, PPCAtom A2, int nAtoms,
-                       rmatrix & A, rmatrix & U, rmatrix & V,
-                       rvector & W, rvector & RV1 )  {
-//   Given two sets of atoms, A1 and A2, superpose_atoms(...)
-// calculates the rotational-translational matrix T such that
-// |T*A1 - A2| is minimal in least-square terms. The transfomation
-// superposes exactly the atoms A1[0] and A2[0].
-realtype det,B;
-vect3    vc1,vc2;
-int      i,j,k;
-
-  //  1.  Calculate the correlation matrix. The rotation will be
-  //      done around
-
-  for (i=1;i<=3;i++)
-    for (j=1;j<=3;j++)
-      A[i][j] = 0.0;
-
-  for (k=1;k<nAtoms;k++)  {
-    vc1[0] = A1[k]->x - A1[0]->x;
-    vc1[1] = A1[k]->y - A1[0]->y;
-    vc1[2] = A1[k]->z - A1[0]->z;
-    vc2[0] = A2[k]->x - A2[0]->x;
-    vc2[1] = A2[k]->y - A2[0]->y;
-    vc2[2] = A2[k]->z - A2[0]->z;
-    for (i=1;i<=3;i++)
-      for (j=1;j<=3;j++)
-        A[i][j] += vc1[j-1]*vc2[i-1];
-  }
-
-  //  2. Calculate transformation matrix (to be applied to A1)
-
-  det = A[1][1]*A[2][2]*A[3][3] + 
-        A[1][2]*A[2][3]*A[3][1] +
-        A[2][1]*A[3][2]*A[1][3] -
-        A[1][3]*A[2][2]*A[3][1] -
-        A[1][1]*A[2][3]*A[3][2] -
-        A[3][3]*A[1][2]*A[2][1];
-
-  //  2.1 SV-decompose the correlation matrix
-
-  SVD ( 3,3,3,A,U,V,W,RV1,True,True,i );
-
-  if (i!=0)  return SPOSEAT_SVD_Fail;
-
-  //  2.2 Check for parasite inversion and fix it if found
-
-  if (det<=0.0)  {
-    k = 0;
-    B = MaxReal;
-    for (j=1;j<=3;j++)
-      if (W[j]<B)  {
-        B = W[j];
-        k = j;
-      }
-    for (j=1;j<=3;j++)
-      V[j][k] = -V[j][k];
-  }
-
-  //  2.3 Calculate rotational part of T
-
-  for (j=1;j<=3;j++)
-    for (k=1;k<=3;k++)  {
-      B = 0.0;
-      for (i=1;i<=3;i++)
-        B += U[j][i]*V[k][i];
-      T[j-1][k-1] = B;
-    }
-
-  //  2.4 Add translational part to T
-
-  T[0][3] = A2[0]->x - T[0][0]*A1[0]->x - T[0][1]*A1[0]->y -
-                       T[0][2]*A1[0]->z;
-  T[1][3] = A2[0]->y - T[1][0]*A1[0]->x - T[1][1]*A1[0]->y -
-                       T[1][2]*A1[0]->z;
-  T[2][3] = A2[0]->z - T[2][0]*A1[0]->x - T[2][1]*A1[0]->y -
-                       T[2][2]*A1[0]->z;
-
-  return SPOSEAT_Ok;
-
-}
-
-
-int CSBStructure::AddHydrogens ( PCResidue R )  {
-//
-//   Return:
-//     SBASE_Ok             success
-//     SBASE_EmptyResidue   residue R does not contain atoms
-//     SBASE_NoAtomsFound   SBStructure does not contain atoms
-//     SBASE_NoBonds        SBStructure does not contain bonds
-//     SBASE_NoAtomsData    SBStructure is not complete
-//     SBASE_NoSimilarity   too few coomon atom names in R and SBase
-//                          entry with the same structure name
-//     SBASE_SuperpositionFailed  failed residue superposition
-//
-// NOTE1: the function does not rearranges existing atoms in the
-// residue, but places the hydrogens on top of them (leaving the
-// Ter pseudoatom, if found, on top of the list).
-//
-// NOTE2: in case of alternative locations, the first one in the
-// residue is chosen.
-//
-PPCAtom  H;
-PCSBAtom sa1[10];
-PCAtom   sa2[10];
-rmatrix  D,U,V;
-rvector  W,RV1;
-imatrix  c;
-ivector  A,nb;
-mat44    T;
-int      i,j,k,m,n,mm,nTer,nH;
-
-  //  1.  Make simple checks
-
-  if (nAtoms<=2)          return SBASE_NoAtomsFound;
-  if (nBonds<=0)          return SBASE_NoBonds;
-  if (R->nAtoms<=2)       return SBASE_EmptyResidue;
-  if (nAtoms==R->nAtoms)  return SBASE_Ok;
-
-  //  2.  Map existing atoms from the residue onto a local array
-
-  GetVectorMemory ( A,nAtoms,0 );
-  nTer = 20000;
-  for (i=0;i<nAtoms;i++)  {
-    A[i] = -1;  // signal "no atom"
-    for (j=0;(j<R->nAtoms) && (A[i]<0);j++)
-      if (R->atom[j])  {
-        if (R->atom[j]->Ter)
-          nTer = j;
-        else if (!strcmp(Atom[i]->pdb_name,R->atom[j]->name))
-          A[i] = j;  // here is the place to check for altlocs
-      }
-  }
-
-  //  3.  Make bond matrix
-
-  GetMatrixMemory ( c ,nAtoms,10,0,0 );
-  GetVectorMemory ( nb,nAtoms,0 );
-
-  for (i=0;i<nAtoms;i++)
-    nb[i] = 0;  // number of bonds at ith atom
-
-  for (i=0;i<nBonds;i++)  {
-    j = Bond[i]->atom1-1;
-    k = Bond[i]->atom2-1;
-    c[j][nb[j]] = k;
-    c[k][nb[k]] = j;
-    nb[j]++;
-    nb[k]++;
-  }
-
-  //  4.  Loop over all hydrogens. Locate core atoms bonded to
-  //      hydrogen in SBStructure and superpose them with the
-  //      corresponding atoms in the residue. Using the superposition
-  //      matrix, add hydrogens to the residue.
-
-  GetMatrixMemory ( D  ,3,3,1,1 );
-  GetMatrixMemory ( U  ,3,3,1,1 );
-  GetMatrixMemory ( V  ,3,3,1,1 );
-  GetVectorMemory ( W  ,3,1 );
-  GetVectorMemory ( RV1,3,1 );
-
-  H  = new PCAtom[nAtoms];
-  nH = 0;
-
-  for (i=0;i<nAtoms;i++)
-    if ((!strcmp(Atom[i]->element," H")) && (A[i]<0) && (nb[i]>0) &&
-        (Atom[i]->x>-MaxReal)) {
-      // ith atom is a hydrogen which is not found in the residue.
-      // Find 3+ core atoms that are most closely bonded to this one.
-      n = c[i][0];  // core atom bonded to the hydrogen
-      if (A[n]>=0)  {
-        sa1[0] = Atom[n];
-        sa2[0] = R->atom[A[n]];
-        mm = 1;
-        m  = 1;
-        while ((m<3) && (mm<2))  {
-          k = n;
-          for (j=0;(j<nb[k]) && (m<10);j++)  {
-            n = c[k][j];
-            if (A[n]>=0)  {
-              sa1[m] = Atom[n];
-              sa2[m] = R->atom[A[n]];
-              m++;
-            }
-          }
-          mm++;
-        }
-        if (m>=3)  {
-          // superpose atoms and add the hydrogen to the residue
-          k = superpose_atoms ( T,sa1,sa2,m,D,U,V,W,RV1 );
-          if (k==SPOSEAT_Ok)  {
-            H[nH] = Atom[i]->makeCAtom();
-            H[nH]->Transform ( T );
-            nH++;
-          }
-        }
-      }
-    }
-
-  //  5.  Put hydrogens into the residue
-
-  for (i=0;i<nH;i++)  {
-    R->InsertAtom ( H[i],nTer );
-    nTer++;
-  }
-
-  //  6.  Release memory and return
-
-  if (H)  delete[] H;
-  FreeVectorMemory ( A,0 );
-
-  FreeVectorMemory ( RV1,1 );
-  FreeVectorMemory ( W  ,1 );
-  FreeMatrixMemory ( V  ,3,1,1 );
-  FreeMatrixMemory ( U  ,3,1,1 );
-  FreeMatrixMemory ( D  ,3,1,1 );
-
-  FreeVectorMemory ( nb,0 );
-  FreeMatrixMemory ( c ,nAtoms,0,0 );
-
-  return SBASE_Ok;
-
-}
-
-void CSBStructure::Copy ( PCSBStructure S )  {
-int i;
-
-  FreeMemory();
-
-  strcpy     ( compoundID,S->compoundID );
-  CreateCopy ( Formula   ,S->Formula    );
-  CreateCopy ( Name      ,S->Name       );
-  CreateCopy ( Synonym   ,S->Synonym    );
-  CreateCopy ( Charge    ,S->Charge     );
-  xyz_source = S->xyz_source;
-
-  nLeavingAtoms = S->nLeavingAtoms;
-  if (nLeavingAtoms>0)  {
-    GetVectorMemory ( leavingAtom,nLeavingAtoms,0 );
-    GetVectorMemory ( bondedAtom ,nLeavingAtoms,0 );
-    for (i=0;i<nLeavingAtoms;i++)  {
-      leavingAtom[i] = S->leavingAtom[i];
-      bondedAtom [i] = S->bondedAtom [i];
-    }
-  }
-
-  nAtoms  = S->nAtoms;
-  nAAlloc = nAtoms;
-  if (nAtoms>0) {
-    Atom = new PCSBAtom[nAtoms];
-    for (i=0;i<nAtoms;i++)  {
-      Atom[i] = new CSBAtom();
-      Atom[i]->Copy ( S->Atom[i] );
-    }
-  }
-
-  nBonds  = S->nBonds;
-  nBAlloc = nBonds;
-  if (nBonds>0)  {
-    Bond = new PCSBBond[nBonds];
-    for (i=0;i<nBonds;i++)  {
-      Bond[i] = new CSBBond();
-      Bond[i]->Copy ( S->Bond[i] );
-    }
-  }
-
-  nAngles = S->nAngles;
-  nGAlloc = nAngles;
-  if (nAngles>0)  {
-    Angle = new PCSBAngle[nAngles];
-    for (i=0;i<nAngles;i++)  {
-      Angle[i] = new CSBAngle();
-      Angle[i]->Copy ( S->Angle[i] );
-    }
-  }
-
-  nTorsions = S->nTorsions;
-  nTAlloc   = nTorsions;
-  if (nTorsions>0)  {
-    Torsion = new PCSBTorsion[nTorsions];
-    for (i=0;i<nTorsions;i++)  {
-      Torsion[i] = new CSBTorsion();
-      Torsion[i]->Copy ( S->Torsion[i] );
-    }
-  }
-
-}
-
-
-void CSBStructure::write ( RCFile f )  {
-int i,Version=1;
-
-  f.WriteInt    ( &Version );
-
-  f.WriteFile   ( compoundID,sizeof(compoundID) );
-  f.CreateWrite ( Formula  );
-  f.CreateWrite ( Name     );
-  f.CreateWrite ( Synonym  );
-  f.CreateWrite ( Charge  );
-  f.WriteFile   ( &xyz_source,sizeof(xyz_source) );
-
-  f.WriteInt    ( &nLeavingAtoms );
-  for (i=0;i<nLeavingAtoms;i++)  {
-    f.WriteInt ( &(leavingAtom[i]) );
-    f.WriteInt ( &(bondedAtom [i]) );
-  }
-
-  f.WriteInt ( &nAtoms );
-  for (i=0;i<nAtoms;i++)
-    StreamWrite ( f,Atom[i] );
-
-  f.WriteInt ( &nBonds );
-  for (i=0;i<nBonds;i++)
-    StreamWrite ( f,Bond[i] );
-
-  f.WriteInt ( &nAngles );
-  for (i=0;i<nAngles;i++)
-    StreamWrite ( f,Angle[i] );
-
-  f.WriteInt ( &nTorsions );
-  for (i=0;i<nTorsions;i++)
-    StreamWrite ( f,Torsion[i] );
-
-}
-
-void CSBStructure::read ( RCFile f )  {
-int i,Version;
-
-  FreeMemory();
-
-  f.ReadInt    ( &Version );
-
-  f.ReadFile   ( compoundID,sizeof(compoundID) );
-  f.CreateRead ( Formula  );
-  f.CreateRead ( Name     );
-  f.CreateRead ( Synonym  );
-  f.CreateRead ( Charge  );
-  f.ReadFile   ( &xyz_source,sizeof(xyz_source) );
-
-  f.ReadInt ( &nLeavingAtoms );
-  if (nLeavingAtoms>0)  {
-    GetVectorMemory ( leavingAtom,nLeavingAtoms,0 );
-    GetVectorMemory ( bondedAtom ,nLeavingAtoms,0 );
-    for (i=0;i<nLeavingAtoms;i++)  {
-      f.ReadInt ( &(leavingAtom[i]) );
-      f.ReadInt ( &(bondedAtom [i]) );
-    }
-  }
-
-  f.ReadInt ( &nAtoms );
-  nAAlloc = nAtoms;
-  if (nAtoms>0) {
-    Atom = new PCSBAtom[nAtoms];
-    for (i=0;i<nAtoms;i++)  {
-      Atom[i] = NULL;
-      StreamRead ( f,Atom[i] );
-    }
-  }
-
-  f.ReadInt ( &nBonds );
-  nBAlloc = nBonds;
-  if (nBonds>0)  {
-    Bond = new PCSBBond[nBonds];
-    for (i=0;i<nBonds;i++)  {
-      Bond[i] = NULL;
-      StreamRead ( f,Bond[i] );
-    }
-  }
-
-  f.ReadInt ( &nAngles );
-  nGAlloc = nAngles;
-  if (nAngles>0)  {
-    Angle = new PCSBAngle[nAngles];
-    for (i=0;i<nAngles;i++)  {
-      Angle[i] = NULL;
-      StreamRead ( f,Angle[i] );
-    }
-  }
-
-  f.ReadInt ( &nTorsions );
-  nTAlloc = nTorsions;
-  if (nTorsions>0)  {
-    Torsion = new PCSBTorsion[nTorsions];
-    for (i=0;i<nTorsions;i++)  {
-      Torsion[i] = NULL;
-      StreamRead ( f,Torsion[i] );
-    }
-  }
-
-}
-
-MakeStreamFunctions(CSBStructure)
-
-
-
-//  ====================  Index Class  ==============================
-
-CSBIndex::CSBIndex() : CStream()  {
-  SBIndexInit();
-}
-
-CSBIndex::CSBIndex ( RPCStream Object ) : CStream(Object)  {
-  SBIndexInit();
-}
-
-CSBIndex::~CSBIndex() {
-  if (Comp1)  delete[] Comp1;
-  if (Comp2)  delete[] Comp2;
-}
-
-void CSBIndex::SBIndexInit ()  {
-  compoundID[0] = char(0);
-  nAtoms        = 0;
-  nBonds        = 0;
-  fGraphPos     = -1;
-  fStructPos    = -1;
-  loadPos       = -1;   // -1 <=> not loaded
-  nXTs          = 0;    // total number of "XT"-atoms
-  Comp1         = NULL;
-  Comp2         = NULL;
-}
-
-int CSBIndex::MakeCompositions ( PCSBStructure SBS )  {
-//    MakeCompositions(..) makes the compositions strings for the
-//  given structure.
-//    A composition string consists of records E(N), where E stands
-//  for chemical element name, and N - for the number of atoms of this
-//  element in the structure. The records E(N) follow in alphabetical
-//  order of E without spaces and contain no spaces, records with N=0
-//  are excluded.
-//    Comp2 differs of Comp1 only if there are leaving atoms and
-//  represents the composition with leaving atoms taken into account.
-//  If there is no leaving atoms, Comp2==Comp1.
-//    The function returns the number of leaving atoms in the.
-//  structure.
-char    Cmp1[1000];
-char    Cmp2[1000];
-char    N[50];
-ivector elem;
-int     i,k,x,l,nl;
-short   n0,n;
-
-  nAtoms = SBS->nAtoms;
-  nBonds = SBS->nBonds;
-
-  strcpy ( Cmp1,"" );
-  strcpy ( Cmp2,"" );
-
-  GetVectorMemory ( elem,nAtoms,0 );
-  for (i=0;i<nAtoms;i++)
-    elem[i] = getElementNo ( SBS->Atom[i]->element );
-
-  n0 = -1;
-  n  = 0;
-  nl = 0;
-  for (i=0;(i<nAtoms) && (n<nElementNames);i++)  {
-    n = 10000;
-    for (k=0;k<nAtoms;k++)
-      if ((elem[k]>n0) && (elem[k]<n))  n = elem[k];
-    if (n<nElementNames)   {
-      x = 0;
-      l = 0;
-      for (k=0;k<nAtoms;k++)
-        if (elem[k]==n)  {
-          x++;
-          if (SBS->Atom[k]->leaving=='Y')  l++;
-        }
-      nl += l;
-      sprintf ( N,"%s(%i)",ElementName[n-1],x );
-      strcat  ( Cmp1,N );
-      sprintf ( N,"%s(%i)",ElementName[n-1],x-l );
-      strcat  ( Cmp2,N );
-      n0 = n;
-    }
-  }
-
-  FreeVectorMemory ( elem,0 );
-
-  CreateCopy ( Comp1,Cmp1 );
-  CreateCopy ( Comp2,Cmp2 );
-
-  return nl;
-
-}
-
-
-void CSBIndex::write ( RCFile f )  {
-int Version=1;
-  f.WriteInt    ( &Version    );
-  f.WriteFile   ( compoundID,sizeof(compoundID) );
-  f.WriteInt    ( &nAtoms     );
-  f.WriteInt    ( &nBonds     );
-  f.WriteInt    ( &fGraphPos  );
-  f.WriteInt    ( &fStructPos );
-  f.WriteInt    ( &nXTs       );
-  f.CreateWrite ( Comp1       );
-  f.CreateWrite ( Comp2       );
-}
-
-void CSBIndex::read ( RCFile f )  {
-int Version;
-  f.ReadInt    ( &Version    );
-  f.ReadFile   ( compoundID,sizeof(compoundID) );
-  f.ReadInt    ( &nAtoms     );
-  f.ReadInt    ( &nBonds     );
-  f.ReadInt    ( &fGraphPos  );
-  f.ReadInt    ( &fStructPos );
-  f.ReadInt    ( &nXTs       );
-  f.CreateRead ( Comp1       );
-  f.CreateRead ( Comp2       );
-}
-
-MakeStreamFunctions(CSBIndex)
-
-
-
-//  =========================  CSBase0  ============================
-
-CSBase0::CSBase0()  {
-  InitSBase0();
-}
-
-
-CSBase0::~CSBase0()  {
-  FreeMemory0();
-}
-
-void CSBase0::InitSBase0()  {
-  dirpath     = NULL;
-  Index       = NULL;
-  nStructures = 0;
-  nIAlloc     = 0;
-  nLoad       = 0;
-  nLAlloc     = 0;
-  ldGraph     = NULL;
-  ldStructure = NULL;
-}
-
-void CSBase0::FreeMemory0()  {
-int i;
-  if (dirpath)  delete[] dirpath;
-  dirpath = NULL;
-  if (Index)  {
-    for (i=0;i<nStructures;i++)
-      delete Index[i];
-    delete[] Index;
-  }
-  Index       = NULL;
-  nStructures = 0;
-  nIAlloc     = 0;
-  for (i=0;i<nLAlloc;i++)  {
-    if (ldGraph[i])      delete ldGraph[i];
-    if (ldStructure[i])  delete ldStructure[i];
-  }
-  if (ldGraph)     delete[] ldGraph;
-  if (ldStructure) delete[] ldStructure;
-  nLoad       = 0;
-  nLAlloc     = 0;
-  ldGraph     = NULL;
-  ldStructure = NULL;
-}
-
-pstr CSBase0::GetPath ( pstr & S, cpstr FName )  {
-  if (dirpath)  {
-    if (S)  delete[] S;
-    S = new char[strlen(dirpath)+strlen(FName)+10];
-    strcpy ( S,dirpath );
-    strcat ( S,FName   );
-  } else
-    CreateCopy ( S,FName );
-  return S;
-}
-
-int CSBase0::LoadIndex1 ( cpstr EnvVar )  {
-  return LoadIndex ( getenv(EnvVar) );
-}
-
-int CSBase0::LoadIndex ( cpstr path )  {
-CFile      f;
-pstr       S;
-int        i;
-PPCSBIndex Index1;
-
-  FreeMemory0();
-
-  if (path)  {
-    i = strlen(path);
-    dirpath = new char[i+10];
-    strcpy ( dirpath,path );
-    if (i>0)  {
-      if (dirpath[i-1]!='/')  strcat ( dirpath,"/" );
-    }
-  }
-
-  S = NULL;
-  f.assign ( GetPath(S,sbIndexFile),False,True );
-  if (S)  delete[] S;
-
-  if (f.reset(True))  {
-    while ((!f.FileEnd()) && f.Success())  {
-      if (nStructures>=nIAlloc)  {
-        nIAlloc += 5000;
-        Index1   = new PCSBIndex[nIAlloc];
-        for (i=0;i<nStructures;i++)
-          Index1[i] = Index[i];
-        for (i=nStructures;i<nIAlloc;i++)
-          Index1[i] = NULL;
-        if (Index)  delete[] Index;
-        Index = Index1;
-      }
-      Index[nStructures] = new CSBIndex();
-      StreamRead ( f,Index[nStructures] );
-      if (!f.Success())  {
-        delete Index[nStructures];
-        Index[nStructures] = NULL;
-      } else
-        nStructures++;
-    }
-    f.shut();
-    return SBASE_Ok;
-  } else
-    return SBASE_FileNotFound;
-
-}
-
-
-int CSBase0::LoadStructure ( cpstr compoundID )  {
-//   LoadStructure(..) reads structure from *.sbase files and
-// stores it in RAM for faster access. There are no special
-// functions to access loaded structures, all requests to
-// *.sbase files and RAM-storage are dispatched automatically.
-PCFile         structFile,graphFile;
-PCGraph        G;
-PCSBStructure  SBS;
-PPCGraph       ldG;
-PPCSBStructure ldS;
-int            structNo,i,k,RC;
-
-  SBS      = NULL;
-  G        = NULL;
-  RC       = SBASE_Ok;
-  structNo = GetStructNo ( compoundID );
-
-  if (structNo!=SBASE_StructNotFound)  {
-    if (Index[structNo]->loadPos>=0)
-      RC = SBASE_AlreadyLoaded;
-    else  {
-      structFile = GetStructFile();
-      if (structFile)  {
-        structFile->seek ( Index[structNo]->fStructPos );
-        StreamRead       ( *structFile,SBS );
-        structFile->shut ();
-        delete structFile;
-        if (!SBS)  RC = SBASE_ReadError;
-      } else
-        RC = SBASE_FileNotFound;
-    }
-    if (RC==SBASE_Ok) {
-      graphFile = GetGraphFile();
-      if (graphFile)  {
-        graphFile->seek ( Index[structNo]->fGraphPos );
-        StreamRead      ( *graphFile,G );
-        graphFile->shut ();
-        if (!G)  RC = SBASE_ReadError;
-        delete graphFile;
-      } else
-        RC = SBASE_FileNotFound;
-    }
-  } else 
-    RC = SBASE_StructNotFound;
-
-  if (RC==SBASE_Ok)  {
-    k = -1;
-    for (i=0;(i<nLAlloc) && (k<0);i++)
-      if (!ldStructure[i])  k = i;
-    if (k<0)  {
-      nLAlloc += 100;
-      ldS = new PCSBStructure[nLAlloc];
-      ldG = new PCGraph      [nLAlloc];
-      for (i=0;i<nLoad;i++)  {
-        ldS[i] = ldStructure[i];
-        ldG[i] = ldGraph    [i];
-      }
-      for (i=nLoad;i<nLAlloc;i++)  {
-        ldS[i] = NULL;
-        ldG[i] = NULL;
-      }
-      if (ldStructure)  delete[] ldStructure;
-      if (ldGraph)      delete[] ldGraph;
-      ldStructure = ldS;
-      ldGraph     = ldG;
-      k           = nLoad;
-    }
-    ldStructure[k] = SBS;
-    ldGraph    [k] = G;
-    Index[structNo]->loadPos = k;
-  } else  {
-    if (SBS) delete SBS;
-    if (G)   delete G;
-  }
-
-  return RC;
-
-}
-
-int  CSBase0::UnloadStructure ( cpstr compoundID )  {
-//   UnloadStructure(..) deletes strtucture from RAM and releases
-// its memory. The structure is then accessible through a normal
-// way from *.sbase files, which is slower.
-int  structNo,ldPos;
-  structNo = GetStructNo ( compoundID );
-  if (structNo==SBASE_StructNotFound)
-    return structNo;
-  else   {
-    ldPos = Index[structNo]->loadPos;
-    if (ldPos<0) return SBASE_AlreadyUnloaded;
-    if (ldStructure[ldPos])  {
-      delete ldStructure[ldPos];
-      ldStructure[ldPos] = NULL;
-    }
-    if (ldGraph[ldPos])  {
-      delete ldGraph[ldPos];
-      ldGraph[ldPos] = NULL;
-    }
-    Index[structNo]->loadPos = -1;
-  }
-  return SBASE_Ok;
-}
-
-
-int MakeChirInd ( char chirality )  {
-  if (chirality=='S')  return -1;
-  if (chirality=='R')  return +1;
-  return 0;
-}
-
-int MakeElementType ( int ElType, int Chirality, Boolean Cflag )  {
-  if (Cflag)  {
-    if (Chirality<0)  return ElType | CHIRAL_LEFT;
-    if (Chirality>0)  return ElType | CHIRAL_RIGHT;
-  }
-  return ElType;
-}
-
-int MakeElementType ( int ElType, char chirality, Boolean Cflag )  {
-  if (Cflag)  {
-    if (chirality=='S')  return ElType | CHIRAL_LEFT;
-    if (chirality=='R')  return ElType | CHIRAL_RIGHT;
-  }
-  return ElType;
-}
-
-int CSBase0::GetStructNo ( cpstr compoundID )  {
-int  l1,l2,l,k;
-char id[20];
-
-  strcpy_css ( id,compoundID );
-
-  k = -1;
-
-  if (nStructures<=3)  {
-    for (l=0;(l<nStructures) && (k<0);l++)
-      if (!strcasecmp(Index[l]->compoundID,id))
-        k = l;
-    if (k>=0)  return k;
-    return SBASE_StructNotFound;
-  }
-
-  l  = 0;
-  l1 = 0;
-  l2 = nStructures-1;
-  while (l1<l2-1)  {
-    l = (l1+l2)/2;
-    k = strcasecmp ( Index[l]->compoundID,id );
-    if (k<0)       l1 = l;
-    else if (k>0)  l2 = l;
-    else {
-      l1 = l;
-      l2 = l;
-    }
-  }
-
-  if (k==0)  return l;
-  else if (l==l1)  {
-    if (!strcasecmp(Index[l2]->compoundID,id))  return l2;
-  } else if (l==l2)  {
-    if (!strcasecmp(Index[l1]->compoundID,id))  return l1;
-  }
-
-  return SBASE_StructNotFound;
-
-}
-
-PCFile CSBase0::GetStructFile()  {
-PCFile structFile;
-pstr   S;
-  structFile = new CFile();
-  S = NULL;
-  structFile->assign ( GetPath(S,sbStructFile),False,True );
-  if (S)  delete[] S;
-  if (!structFile->reset(True))  {
-    delete structFile;
-    structFile = NULL;
-  }
-  return structFile;
-}
-
-PCFile CSBase0::GetGraphFile()  {
-PCFile graphFile;
-pstr   S;
-  graphFile = new CFile();
-  S = NULL;
-  graphFile->assign ( GetPath(S,sbGraphFile),False,True );
-  if (S)  delete[] S;
-  if (!graphFile->reset(True))  {
-    delete graphFile;
-    graphFile = NULL;
-  }
-  return graphFile;
-}
-
-
-PCSBStructure CSBase0::GetStructure ( cpstr compoundID )  {
-//   GetStructure returns pointer to the monomer structure
-// identified by 3-letter compoundID. If such structure is not
-// found, the function returns NULL.
-//   The function returns a pointer to a private copy of the
-// structure. Modifying it will not change data in the structural
-// database. The application is responsible for deallocating
-// the structure after use (simply use delete).
-//   See description of CSBStructure for the explanation of
-// its fields.
-PCFile        structFile;
-PCSBStructure SBS;
-int           structNo;
-  SBS      = NULL;
-  structNo = GetStructNo ( compoundID );
-  if (structNo!=SBASE_StructNotFound)  {
-    if (Index[structNo]->loadPos>=0)  {
-      SBS = new CSBStructure();
-      SBS->Copy ( ldStructure[Index[structNo]->loadPos] );
-    } else  {
-      structFile = GetStructFile();
-      if (structFile)  {
-        structFile->seek ( Index[structNo]->fStructPos );
-        StreamRead       ( *structFile,SBS );
-        structFile->shut ();
-        delete structFile;
-      }
-    }
-  }
-  return SBS;
-}
-
-PCSBStructure CSBase0::GetStructure ( int structNo,
-                                      PCFile structFile )  {
-PCFile        sFile;
-PCSBStructure SBS;
-  SBS = NULL;
-  if ((0<=structNo) && (structNo<nStructures))  {
-    if (Index[structNo]->loadPos>=0)  {
-      SBS = new CSBStructure();
-      SBS->Copy ( ldStructure[Index[structNo]->loadPos] );
-    } else  {
-      if (!structFile)  sFile = GetStructFile();
-                  else  sFile = structFile;
-      if (sFile)  {
-        sFile->seek ( Index[structNo]->fStructPos );
-        StreamRead  ( *sFile,SBS );
-        if (!structFile)  delete sFile;
-      }
-    }
-  }
-  return SBS;
-}
-
-PCSBStructure CSBase0::GetStructure ( cpstr compoundID,
-                                      PCFile structFile )  {
-//   Another form of GetStructure(..) uses an open structure
-// file, which allows to save on opening/closing file if
-// multiple access to SBase structures is required.
-PCFile        sFile;
-PCSBStructure SBS;
-int           structNo;
-  SBS      = NULL;
-  structNo = GetStructNo ( compoundID );
-  if (structNo!=SBASE_StructNotFound)  {
-    if (Index[structNo]->loadPos>=0)  {
-      SBS = new CSBStructure();
-      SBS->Copy ( ldStructure[Index[structNo]->loadPos] );
-    } else  {
-      if (!structFile)  sFile = GetStructFile();
-                  else  sFile = structFile;
-      if (sFile)  {
-        sFile->seek ( Index[structNo]->fStructPos );
-        StreamRead  ( *sFile,SBS );
-        if (!structFile)  delete sFile;
-      }
-    }
-  }
-  return SBS;
-}
-
-
-PCResidue CSBase0::makeCResidue ( cpstr compoundID, 
-                                  PCFile     structFile,
-                                  Boolean    includeHydrogens,
-                                  Boolean    makeTer )  {
-PCSBStructure SBS;
-PCResidue     Res;
-  SBS = GetStructure ( compoundID,structFile );
-  if (SBS)  {
-    Res = SBS->makeCResidue ( includeHydrogens,makeTer );
-    delete SBS;
-    return Res;
-  } else
-    return NULL;
-}
-
-PCResidue CSBase0::makeCResidue ( int     structNo, 
-                                  PCFile  structFile,
-                                  Boolean includeHydrogens,
-                                  Boolean makeTer )  {
-PCSBStructure SBS;
-PCResidue     Res;
-  SBS = GetStructure ( structNo,structFile );
-  if (SBS)  {
-    Res = SBS->makeCResidue ( includeHydrogens,makeTer );
-    delete SBS;
-    return Res;
-  } else
-    return NULL;
-}
-
-
-int  CSBase0::GetNofAtoms ( int  structNo )  {
-  if ((0<=structNo) && (structNo<nStructures))
-        return Index[structNo]->nAtoms;
-  else  return SBASE_StructNotFound;
-}
-
-int  CSBase0::GetNofAtoms ( cpstr compoundID )  {
-int  structNo;
-  structNo = GetStructNo ( compoundID );
-  if (structNo!=SBASE_StructNotFound)
-        return GetNofAtoms(structNo);
-  else  return SBASE_StructNotFound;
-}
-
-int  CSBase0::GetGraph ( PCFile graphFile, int structNo, RPCGraph G,
-                         int Hflag )  {
-//   GetGraph(..) retrieves data for chemical structure number structNo
-// (as described in Index) from graph file graphFile, then allocates
-// and builds the corresponding graph, which is returned in G.
-//   If Hflag is set to 1, all hydrogens are removed from the graph.
-//   If Hflag is set to 2, element types of atoms, to which hydrogens
-// are bonded, are modified with flag HYDROGEN_BOND and moved to
-// the end.
-//   Returns 0 in case of success.
-int rc,htype;
-
-  if ((structNo<0) || (structNo>=nStructures))
-    return SBASE_WrongIndex;
-
-  rc = SBASE_Ok;
-
-  if (Index[structNo]->loadPos>=0)  {
-
-    if (!G)  G = new CGraph();
-    G->Copy ( ldGraph[Index[structNo]->loadPos] );
-
-  } else  {
-
-    graphFile->seek ( Index[structNo]->fGraphPos );
-    graphFile->SetSuccess();
-    StreamRead ( *graphFile,G );
-
-    if (!graphFile->Success())  {
-      rc = SBASE_ReadError;
-      if (G)  delete G;
-      G = NULL;
-    }
-
-  }
-
-  if (G)  {
-    G->MakeVertexIDs();
-    if (Hflag>=1)  {
-      htype = getElementNo(pstr("H"));
-      if (Hflag==2)  G->HideType    ( htype );
-               else  G->ExcludeType ( htype );
-    }
-    G->Build ( False );
-  }
-
-  return rc;
-
-}
-
-int  CSBase0::GetGraph ( PCFile graphFile, RPCGraph G, int Hflag )  {
-//   GetGraph(..) retrieves data for chemical structure, which is
-// next in the graph file, then allocates and builds the corresponding
-// graph, which is returned in G.
-//   If Hflag is set to 1, all hydrogens are removed from the graph.
-//   If Hflag is set to 2, element types of atoms, to which hydrogens
-// are bonded, are modified with flag HYDROGEN_BOND and moved to
-// the end.
-//   Returns 0 in case of success.
-int rc,htype;
-
-  rc = 0;
-
-  graphFile->SetSuccess();
-  StreamRead ( *graphFile,G );
-
-  if (!graphFile->Success())  {
-    rc = SBASE_ReadError;
-    if (G)  delete G;
-    G = NULL;
-  }
-
-  if (G)  {
-    G->MakeVertexIDs();
-    if (Hflag>=1)  {
-      htype = getElementNo(pstr("H"));
-      if (Hflag==2)  G->HideType    ( htype );
-               else  G->ExcludeType ( htype );
-    }
-    G->Build ( False );
-  }
-
-  return rc;
-
-}
-
-int  CSBase0::GetGraph ( int structNo, RPCGraph G, int Hflag )  {
-PCFile graphFile;
-int    htype;
-
-  if ((0<=structNo) && (structNo<nStructures))  {
-    if (Index[structNo]->loadPos>=0)  {
-      if (!G) G = new CGraph();
-      G->Copy ( ldGraph[Index[structNo]->loadPos] );
-    } else  {
-      graphFile = GetGraphFile();
-      if (graphFile)  {
-        graphFile->seek ( Index[structNo]->fGraphPos );
-        StreamRead  ( *graphFile,G );
-        graphFile->shut ();
-        delete graphFile;
-      } else  {
-        if (G)  delete G;
-        G = NULL;
-        return SBASE_FileNotFound;
-      }
-    }
-  } else  {
-    if (G)  delete G;
-    G = NULL;
-    return SBASE_WrongIndex;
-  }
-
-  if (G)  {
-    G->MakeVertexIDs();
-    if (Hflag>=1)  {
-      htype = getElementNo(pstr("H"));
-      if (Hflag==2)  G->HideType    ( htype );
-               else  G->ExcludeType ( htype );
-    }
-    G->Build ( False );
-  }
-
-  return SBASE_Ok;
-
-  /*
-  graphFile = GetGraphFile();
-  if (graphFile)  {
-    rc = GetGraph ( graphFile,G,Hflag );
-    graphFile->shut();
-    delete graphFile;
-    return rc;
-  } else  {
-    if (G)  delete G;
-    G = NULL;
-    return SBASE_FileNotFound;
-  }
-  */
-
-}
-
-int  CSBase0::GetGraph ( cpstr compoundID, RPCGraph G,
-                         int Hflag )  {
-PCFile graphFile;
-int    structNo,htype;
-
-  structNo = GetStructNo ( compoundID );
-
-  if (structNo!=SBASE_StructNotFound)  {
-    if (Index[structNo]->loadPos>=0)  {
-      if (!G )  G = new CGraph();
-      G->Copy ( ldGraph[Index[structNo]->loadPos] );
-    } else  {
-      graphFile = GetGraphFile();
-      if (graphFile)  {
-        graphFile->seek ( Index[structNo]->fGraphPos );
-        StreamRead      ( *graphFile,G );
-        graphFile->shut ();
-        delete graphFile;
-      } else  {
-        if (G)  delete G;
-        G = NULL;
-        return SBASE_FileNotFound;
-      }
-    }
-  }
-
-  if (G)  {
-    G->MakeVertexIDs();
-    if (Hflag>=1)  {
-      htype = getElementNo(pstr("H"));
-      if (Hflag==2)  G->HideType    ( htype );
-               else  G->ExcludeType ( htype );
-    }
-    G->Build ( False );
-  }
-
-  return  structNo;
-
-  /*
-  if (structNo!=SBASE_StructNotFound)  {
-    return  GetGraph ( structNo,G,Hflag );
-  } else  {
-    if (G)  delete G;
-    G = NULL;
-    return  structNo;
-  }
-  */
-
-}
-
-int  CSBase0::CheckGraph ( PCGraph G, int Hflag,
-                           Boolean Cflag,
-                           int & nInStructure,
-                           int & nMatched,
-                           ivector match,
-                           int minMatchSize )  {
-//   CheckGraph(..) checks graph G against the same-name
-// structure in the database. The name must be passed in
-// G->name as a standard 3-letter code.
-//   If Hflag is set >= 1, all hydrogens are removed from the graph.
-// If Hflag is set to 2, element types of atoms, to which hydrogens
-// are bonded, are modified with flag HYDROGEN_BOND.
-//   If Cflag is set to True, then chirality information is
-// assumed in the input graph G and it is used for the
-// checking. If Cflag is set to False, then chirality
-// information is neither assumed nor used for the checking.
-//   If a same-name structure is found in the database,
-// the function returns the number of matched vertices
-// (nMatched) from those found in the database (nInStructure).
-// The correspondence between the input and database graphs
-// is returned in array match (it should be of sufficient
-// length) such that ith vertex of input graph corresponds
-// to the match[i]th vertex of the database graph. The
-// function then returns SBASE_Ok if the number of matched
-// vertices coincides with nInStructure and nMatched, and
-// the return is SBASE_CheckFail otherwise.
-//   If a same-name structure is not found, the function
-// returns SBASE_StructNotFound or SBASE_FileNotFound.
-PCFile       graphFile;
-PCGraphMatch U;
-PCGraph      G1;
-PAtomName    atName;
-ivector      F1,F2;
-realtype     p1,p2;
-int          structNo,rc,j,k, nAtoms,nH, minMatch;
-
-  nMatched     = 0;
-  nInStructure = 0;
-
-  structNo = GetStructNo ( G->GetName() );
-  if (structNo==SBASE_StructNotFound)
-    return  SBASE_StructNotFound;
-
-  if (Index[structNo]->loadPos<0)  {
-    graphFile = GetGraphFile();
-    if (!graphFile)  return SBASE_FileNotFound;
-  } else
-    graphFile = NULL;
-
-  G1 = NULL;
-  rc = GetGraph ( graphFile,structNo,G1,Hflag );
-  if ((!G1) || (rc!=SBASE_Ok))  return rc;
-
-  if (graphFile)  {
-    graphFile->shut();
-    delete graphFile;
-  }
-
-  if (!Cflag)  G1->RemoveChirality();
-
-  nInStructure = G1->GetNofVertices();
-
-  if (minMatchSize>0)
-       minMatch = minMatchSize;
-  else minMatch = nInStructure - Index[structNo]->nXTs;
-
-  U = new CGraphMatch();
-  U->MatchGraphs ( G,G1,minMatch );
-  k = U->GetNofMatches();
-  if (k>0)  {
-    U->GetMatch ( 0,F1,F2,nMatched,p1,p2 );
-    for (j=1;j<=nMatched;j++)
-      match[F1[j]-1] = F2[j]-1;
-  }
-
-  if ((nInStructure==G->GetNofVertices()) &&
-      (nInStructure==nMatched))  {
-    rc = SBASE_Ok;
-  } else if (nMatched>0)  {
-    // check if atoms that were not matched are the
-    // teminating ones ("-XT")
-    atName = new AtomName[nInStructure*2+1];
-    if (Hflag>=1)  nH = -1;  // remove hydrogens
-             else  nH =  0;
-    k = 1;
-    if (GetAtNames(structNo,atName,nAtoms,nH)==SBASE_Ok)  {
-      for (j=1;j<=nMatched;j++)
-        atName[F2[j]-1][0] = char(0);
-      k = 0;
-      for (j=0;(j<nInStructure) && (!k);j++)
-        if (atName[j][0] && (strcmp(&(atName[j][2]),"XT")))  k = 1;
-    }
-    if (!k)  rc = SBASE_Ok;
-       else  rc = SBASE_CheckFail;
-    delete[] atName;
-  } else
-    rc = SBASE_CheckFail;
-
-  delete U;
-  delete G1;
-
-  return rc;
-
-}
-
-int CSBase0::CheckResidue ( PCResidue R,
-                            int Hflag, Boolean Cflag,
-                            int & nInResidue, int & nInStructure,
-                            int & nMatched,   ivector match,
-                            cpstr altLoc, int minMatchSize )  {
-PCGraph G;
-int     rc,htype;
-
-  G = new CGraph ( R,altLoc );
-
-  if (Hflag>=1) {
-    htype = getElementNo(pstr("H"));
-    if (Hflag==2)  G->HideType    ( htype );
-             else  G->ExcludeType ( htype );
-  }
-
-  G->Build ( False );
-
-  nInResidue = G->GetNofVertices();
-  if (nInResidue<=0)  {
-    rc = SBASE_NoAtomsFound;
-    nInStructure = 0;
-    nMatched     = 0;
-  } else
-    rc = CheckGraph ( G,Hflag,Cflag,nInStructure,nMatched,match,
-                      minMatchSize );
-  delete G;
-
-  return rc;
-
-}
-
-
-void SDASelHandles::getNewHandles ( PCMMDBManager MMDB )  {
-  selHndDonor    = MMDB->NewSelection();
-  selHndAcceptor = MMDB->NewSelection();
-  selHndHydrogen = MMDB->NewSelection();
-  selKey = SKEY_OR;
-}
-
-void SDASelHandles::makeSelIndexes ( PCMMDBManager MMDB )  {
-  MMDB->MakeSelIndex ( selHndDonor    );
-  MMDB->MakeSelIndex ( selHndAcceptor );
-  MMDB->MakeSelIndex ( selHndHydrogen );
-}
-
-void SDASelHandles::deleteSelections ( PCMMDBManager MMDB )  {
-  MMDB->DeleteSelection ( selHndDonor    );
-  MMDB->DeleteSelection ( selHndAcceptor );
-  MMDB->DeleteSelection ( selHndHydrogen );
-}
-
-
-int CSBase0::MakeBonds ( PCResidue R, pstr altLoc,
-                         PCFile         structFile,
-                         PSDASelHandles selHandles,
-                         Boolean     ignoreNegSigOcc )  {
-//   MakeBonds(..) makes bonds between atoms in MMDB's residue R
-// from data found in SBase. Residue R must be associated with
-// coordinate hierarchy. Data is retrieved from SBase on the basis
-// of residue name only. In case of multiple conformations, if
-// altLoc:
-//    NULL  - the highest occupancy atom will be taken
-//            if all occupancies are equal then atom with
-//            first altLoc taken
-//    other - atoms with given altLoc are taken. If such
-//            altLoc is not found, the function does as if
-//            NULL value for altLoc is given.
-//   If selHandles is not NULL, the function also selects atoms
-// in the residue according to their hydrogen bond attributes.
-// This is a special option for hydrogen bond calculations.
-//   If ignoreNegSigOcc is set True then the function will ignore
-// atoms with negative occupancy standard deviation. Such atoms
-// may be hydrogens added by CSBase0::AddHydrogens(..) function,
-// in general any atoms added by CSBAtom::MakeCAtom(..) function.
-// Added hydrogens may be ignored if MakeBonds is used in
-// CSbase::CalcHBonds(..) function.
-//   Return:
-//     SBASE_Ok             success
-//     SBASE_FileNotFound   non-initiated SBase
-//     SBASE_StructNotFound the residue's name is not found in SBase
-//     SBASE_EmptyResidue   residue R does not contain atoms
-//     SBASE_NoAtomsFound   SBase entry does not contain atoms
-//     SBASE_BrokenBonds    some bonds could not be set up because
-//                          of missing atoms in R. This could be
-//                          a result of residue R named wrongly.
-PCSBStructure SBS;
-PCMMDBManager MMDB;
-PPCAtom       A;
-ivector       anmatch;
-int           natoms,i,i1,i2,rc;
-
-  R->GetAtomTable ( A,natoms );
-  if (!A)  return SBASE_EmptyResidue;
-
-  for (i=0;i<natoms;i++)
-    if (A[i])  A[i]->FreeBonds();
-
-  SBS = GetStructure ( R->GetResName(),structFile );
-  if (!SBS)  return SBASE_StructNotFound;
-
-  if (SBS->nAtoms<=0)  {
-    delete SBS;
-    return SBASE_NoAtomsFound;
-  }
-
-  GetVectorMemory ( anmatch,SBS->nAtoms,0 );
-  SBS->GetAtomNameMatch ( A,natoms,altLoc,anmatch );
-  if (ignoreNegSigOcc)
-    for (i=0;i<SBS->nAtoms;i++)  {
-      i1 = anmatch[i];
-      if (i1>=0)  {
-        if (A[i1]->sigOcc<0.0)  anmatch[i] = -1;
-      }
-    }
-
-  if (selHandles)  {
-    MMDB = PCMMDBManager(R->GetCoordHierarchy());
-    if (MMDB)  {
-      i2 = selHandles->selKey;
-      for (i=0;i<SBS->nAtoms;i++)  {
-        i1 = anmatch[i];
-        if (i1>=0)
-          switch (SBS->Atom[i]->hb_type)  {
-            case 'D' :  MMDB->SelectAtom ( selHandles->selHndDonor,
-                                           A[i1],i2,False );
-                      break;
-            case 'A' :  MMDB->SelectAtom ( selHandles->selHndAcceptor,
-                                           A[i1],i2,False );
-                      break;
-            case 'B' :  MMDB->SelectAtom ( selHandles->selHndDonor,
-                                           A[i1],i2,False );
-                        MMDB->SelectAtom ( selHandles->selHndAcceptor,
-                                           A[i1],i2,False );
-                      break;
-            case 'H' :  MMDB->SelectAtom ( selHandles->selHndHydrogen,
-                                           A[i1],i2,False );
-                      break;
-            default  :
-            case 'N' : ;
-          }
-      }
-    }
-  }
-
-  rc = SBASE_Ok;
-  for (i=0;i<SBS->nBonds;i++)  {
-    i1 = anmatch[SBS->Bond[i]->atom1-1];
-    i2 = anmatch[SBS->Bond[i]->atom2-1];
-    if ((i1>=0) && (i2>=0))  {
-      A[i1]->AddBond ( A[i2],SBS->Bond[i]->order,2 );
-      A[i2]->AddBond ( A[i1],SBS->Bond[i]->order,2 );
-    } else
-      rc = SBASE_BrokenBonds;
-  }
-
-  FreeVectorMemory ( anmatch,0 );
-  delete SBS;
-
-  return rc;
-
-}
-
-
-int CSBase0::GetEnergyTypes ( PCResidue R, PCFile structFile )  {
-PCSBStructure SBS;
-PPCAtom       A;
-int           i,j,rc,natoms;
-
-  R->GetAtomTable ( A,natoms );
-  if (!A)  return SBASE_EmptyResidue;
-
-  for (i=0;i<natoms;i++)
-    if (A[i])  A[i]->energyType[0] = char(0);
-
-  SBS = GetStructure ( R->GetResName(),structFile );
-  if (SBS)  {
-    if (SBS->nAtoms>0)  {
-      for (i=0;i<natoms;i++)
-        if (A[i])  {
-          for (j=0;j<SBS->nAtoms;j++)
-            if (SBS->Atom[j]) {
-              if (!strcmp(A[i]->name,SBS->Atom[j]->pdb_name))  {
-                strcpy ( A[i]->energyType,SBS->Atom[j]->energyType );
-                A[i]->charge = SBS->Atom[j]->ccp4_charge;
-              }
-            }
-        }
-      rc = SBASE_Ok;
-    } else
-      rc =  SBASE_NoAtomsFound;
-    delete SBS;
-  } else  
-    rc = SBASE_StructNotFound;
-
-  return rc;
-
-}
-
-
-int CSBase0::GetEnergyTypes ( PPCResidue R, int nRes,
-                              PCFile structFile )  {
-PCFile        sFile;
-PCSBStructure SBS;
-PPCAtom       A;
-bvector       B;
-int           i,j,k,n,natoms;
-
-  GetVectorMemory ( B,nRes,0 );
-  for (i=0;i<nRes;i++)
-    B[i] = (!R[i]);
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-  if (!sFile)  return SBASE_FileNotFound;
-
-  i = 0;
-  while (i<nRes)  {
-    while (i<nRes)
-      if (B[i])  i++;
-           else  break;
-    if (i<nRes)  {
-      SBS = GetStructure ( R[i]->GetResName(),sFile );
-      j   = i;
-      while (j<nRes)  {
-        B[j] = True;
-        R[j]->GetAtomTable ( A,natoms );
-        if (A)  {
-          for (k=0;k<natoms;k++)
-            if (A[k])  A[k]->energyType[0] = char(0);
-          if (SBS)  {
-            if (SBS->nAtoms>0)  {
-              for (k=0;k<natoms;k++)
-                if (A[k])  {
-                  for (n=0;n<SBS->nAtoms;n++)
-                    if (SBS->Atom[n]) {
-                      if (!strcmp(A[k]->name,SBS->Atom[n]->pdb_name)) {
-                        strcpy ( A[k]->energyType,
-                                 SBS->Atom[n]->energyType );
-                        A[k]->charge = SBS->Atom[n]->ccp4_charge;
-                      }
-                    }
-                }
-            }
-          } 
-        }
-        j++;
-        while (j<nRes)
-          if (!B[j])  {
-            if (!strcmp(R[i]->name,R[j]->name))  break;
-                                           else  j++;
-          } else
-            j++;
-      }
-      if (SBS)  {
-        delete SBS;
-        SBS = NULL;
-      }
-      i++;
-    }
-  }
-
-  if (!structFile)  delete sFile;
-  FreeVectorMemory ( B,0 );
-
-  return SBASE_Ok;
-
-}
-
-
-int CSBase0::GetEnergyTypes ( PCChain chain, PCFile structFile )  {
-PPCResidue Res;
-int        nRes;
-  chain->GetResidueTable ( Res,nRes );
-  if (nRes>0)
-        return GetEnergyTypes ( Res,nRes,structFile );
-  else  return SBASE_EmptyResSet;
-}
-
-int CSBase0::GetEnergyTypes ( PCModel model, PCFile structFile )  {
-PPCResidue    Res;
-PPCChain      chain;
-PCMMDBManager MMDB;
-int           rc,selHnd,i,nRes,nChains;
- 
-  rc   = SBASE_Ok;
-  MMDB = PCMMDBManager(model->GetCoordHierarchy());
-
-  if (MMDB)  {
-
-    selHnd = MMDB->NewSelection();
-    MMDB->Select ( selHnd,STYPE_RESIDUE,model->GetSerNum(),
-                   "*",ANY_RES,"*",ANY_RES,"*",
-                   "*","*","*","*",SKEY_NEW );
-    MMDB->GetSelIndex ( selHnd,Res,nRes );
-    if (nRes>0)  rc = GetEnergyTypes ( Res,nRes,structFile );
-           else  rc = SBASE_EmptyResSet;
-    MMDB->DeleteSelection ( selHnd );
-
-  } else  {
-
-    model->GetChainTable ( chain,nChains );
-    for (i=0;i<nChains;i++)
-      if (chain[i])  {
-        chain[i]->GetResidueTable ( Res,nRes );
-        if (nRes>0) GetEnergyTypes ( Res,nRes,structFile );
-      }
-
-  }
-
-  return rc;
-
-}
-
-int CSBase0::GetEnergyTypes ( PCMMDBManager MMDB, PCFile structFile ) {
-PPCResidue Res;
-int        rc,selHnd,nRes;
-
-  rc = SBASE_Ok;
-
-  selHnd = MMDB->NewSelection();
-  MMDB->Select ( selHnd,STYPE_RESIDUE,0,
-                 "*",ANY_RES,"*",ANY_RES,"*",
-                 "*","*","*","*",SKEY_NEW );
-  MMDB->GetSelIndex ( selHnd,Res,nRes );
-  if (nRes>0)  rc = GetEnergyTypes ( Res,nRes,structFile );
-         else  rc = SBASE_EmptyResSet;
-
-  MMDB->DeleteSelection ( selHnd );
-
-  return rc;
-
-}
-
-int CSBase0::AddHydrogens ( PCResidue R, PCFile structFile )  {
-//   Return:
-//     SBASE_Ok             success
-//     SBASE_EmptyResidue   residue R does not contain atoms
-//     SBASE_NoAtomsFound   SBStructure does not contain atoms
-//     SBASE_NoBonds        SBStructure does not contain bonds
-//     SBASE_NoAtomsData    SBStructure is not complete
-//     SBASE_NoSimilarity   too few coomon atom names in R and SBase
-//                          entry with the same structure name
-//     SBASE_SuperpositionFailed  failed residue superposition
-// NOTE: the function does not rearranges existing atoms in the
-// residue, but places the hydrogens on top of them (leaving the
-// Ter pseudoatom, if found, on top of the list)
-PCFile        sFile;
-PCSBStructure SBS;
-int           rc;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  SBS = GetStructure ( R->GetResName(),sFile );
-  if (!structFile)  delete sFile;
-
-  if (!SBS)  return SBASE_StructNotFound;
-
-  rc = SBS->AddHydrogens ( R );
-
-  delete SBS;
-
-  return rc;
-
-}
-
-int CSBase0::AddHydrogens ( PCChain chain, PCFile structFile )  {
-PCFile     sFile;
-PPCResidue Res;
-int        i,k,nRes,rc;
-Boolean    B;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  rc = SBASE_Ok;
-  B  = False;
-  chain->GetResidueTable ( Res,nRes );
-  for (i=0;i<nRes;i++)
-    if (Res[i])  {
-      k = AddHydrogens ( Res[i],sFile );
-      if (k==SBASE_Ok)  B = True;
-                  else  rc = SBASE_Incomplete;
-    }
-  if (!B)  rc = SBASE_Fail;
-
-  if (!structFile)  delete sFile;
-
-  return rc;
-
-}
-
-
-int CSBase0::AddHydrogens ( PCModel model, PCFile structFile )  {
-PCFile     sFile;
-PPCChain   chain;
-PPCResidue Res;
-int        i,j,k,nChains,nRes,rc;
-Boolean    B;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  rc = SBASE_Ok;
-  B  = False;
-  model->GetChainTable ( chain,nChains );
-  for (i=0;i<nChains;i++)
-    if (chain[i])  {
-      chain[i]->GetResidueTable ( Res,nRes );
-      for (j=0;j<nRes;j++)
-        if (Res[j])  {
-          k = AddHydrogens ( Res[j],sFile );
-          if (k==SBASE_Ok)  B = True;
-                      else  rc = SBASE_Incomplete;
-        }
-    }
-  if (!B)  rc = SBASE_Fail;
-
-  if (!structFile)  delete sFile;
-
-  return rc;
-
-}
-
-int CSBase0::AddHydrogens ( PCMMDBManager MMDB, PCFile structFile )  {
-PCFile     sFile;
-PPCModel   model;
-PPCChain   chain;
-PPCResidue Res;
-int        i,j,n,k,nModels,nChains,nRes,rc;
-Boolean    B;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  rc = SBASE_Ok;
-  B  = False;
-  MMDB->GetModelTable ( model,nModels );
-  for (i=0;i<nModels;i++)
-    if (model[i])  {
-      model[i]->GetChainTable ( chain,nChains );
-      for (j=0;j<nChains;j++)
-        if (chain[j])  {
-          chain[j]->GetResidueTable ( Res,nRes );
-          for (n=0;n<nRes;n++)
-            if (Res[n])  {
-              k = AddHydrogens ( Res[n],sFile );
-              if (k==SBASE_Ok)  B = True;
-                          else  rc = SBASE_Incomplete;
-            }
-        }
-    }
-  if (!B)  rc = SBASE_Fail;
-
-  if (!structFile)  delete sFile;
-
-  return rc;
-
-}
-
-
-
-int CSBase0::ComplementResidue ( PCResidue R, int complFlag,
-                                 PCFile structFile )  {
-//   ComplementResidue(..) extracts data from SBase by residue
-// name, then superposes atoms having identical names and
-// adds the residue with atoms that are found in SBase but are
-// absent in the residue. The added atoms are rotated and translated
-// such as to comply with the superposed parts.
-//   complFlag:
-//     CMPLF_Hydrogens complement residue with hydrogens
-//     CMPLF_nonHs     complement residue with non-hydrogens
-//     CMPLF_XT        complement with C-terminus
-//   Return:
-//     SBASE_Ok             success
-//     SBASE_FileNotFound   non-initiated SBase
-//     SBASE_StructNotFound the residue's name is not found in SBase
-//     SBASE_EmptyResidue   residue R does not contain atoms
-//     SBASE_NoAtomsFound   SBase entry does not contain atoms
-//     SBASE_NoAtomsData    SBase entry is not complete
-//     SBASE_NoSimilarity   too few coomon atom names in R and SBase
-//                          entry with the same structure name
-//     SBASE_SuperpositionFailed  failed residue superposition
-// NOTE: the function rearranges ALL atoms in the residue according
-// to PDB order as written in SBase.
-PCFile        sFile;
-PCSBStructure SBS;
-PPCAtom       A1,A2,A3;
-ivector       c,x;
-mat44         T;
-Element       Hydrogen;
-pstr          aname;
-int           i,j,k,natoms1,natoms2,rc;
-Boolean       complH,complNH,complXT;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  SBS = GetStructure ( R->GetResName(),sFile );
-  if (!structFile)  delete sFile;
-
-  if (!SBS)  return SBASE_StructNotFound;
-
-  /*  ---  temporary commented because of incompleteness of data
-           in SBase files
-  if (SBS->CheckAtoms()<0)  {
-    delete SBS;
-    return SBASE_NoAtomData;
-  }
-  ---------- */
-
-  rc = SBASE_Ok;
-
-  SBS->GetAtomTable ( A1,natoms1 );
-  if (!A1)  {
-    delete SBS;
-    return SBASE_NoAtomsFound;
-  }
-
-  /*  --- temporary fix, simply neglect atoms that do not have
-          coordinates. This code should be removed and the
-          code above uncommented  ----------- */
-  j = 0;
-  for (i=0;i<natoms1;i++)
-    if (A1[i]->x==-MaxReal)  delete A1[i];
-    else {
-      if (j<i)  A1[j] = A1[i];
-      j++;
-    }
-  natoms1 = j;
-  for (i=j;i<natoms1;i++)
-    A1[i] = NULL;
-
-  /* ---------------------------------------- */
-
-  A2 = NULL;
-  R->GetAtomTable ( A2,natoms2 );
-  if (!A2)  {
-    delete SBS;
-    return SBASE_EmptyResidue;
-  }
-
-  GetVectorMemory ( c,natoms1,0 );
-  GetVectorMemory ( x,natoms2,0 );
-  for (j=0;j<natoms2;j++)
-    x[j] = -1;
-
-  k = 0;
-  for (i=0;i<natoms1;i++)  {
-    c[i] = -1;
-    for (j=0;j<natoms2;j++)
-      if (A2[j])  {
-        if ((!A2[j]->isTer()) &&
-            (!strcmp(A1[i]->GetAtomName(),A2[j]->GetAtomName())))  {
-          if (c[i]<0) {
-            c[i] = j;
-            k++;
-          }
-          x[j] = i;
-        }
-      }
-  }
-
-  if (k>2)  {
-
-    // the rotational-translational matrix T such that |T*A1 - A2| is
-    // as A1[i] <-> A2[C[i]] only for those i that C[i]>=0 .
-    // The default
-    k = SuperposeAtoms ( T,A1,natoms1,A2,c );
-    if (k!=SPOSEAT_Ok)  rc = SBASE_SuperpositionFailed;
-    else  {
-      complH  = ((complFlag & CMPLF_Hydrogens)!=0);
-      complNH = ((complFlag & CMPLF_nonHs)!=0);
-      complXT = ((complFlag & CMPLF_XT)!=0);
-      strcpy ( Hydrogen,ElementName[0] );
-      CutSpaces ( Hydrogen,SCUTKEY_BEGEND );
-      A3 = new PCAtom[natoms1+natoms2+1];
-      k  = 0;
-      for (i=0;i<natoms1;i++)
-        if (c[i]>=0)  {
-          A3[k] = A1[i];
-          A3[k]->Copy ( A2[c[i]] );
-          A1[i] = NULL;
-          k++;
-          // check for altlocs
-          for (j=c[i]+1;j<natoms2;j++)
-            if (x[j]==i)  {
-              A3[k] = newCAtom();
-              A3[k]->Copy ( A2[j] );
-              k++;
-            }
-        } else  {
-          A3[k] = NULL;
-          aname = A1[i]->GetAtomName();
-          if (strcmp(A1[i]->GetElementName(),Hydrogen))  {
-            //  a non-hydrogen atom, check if it should be added
-            if (complNH &&  
-                     (complXT || (strcmp(aname," OXT"))))
-              A3[k] = A1[i];
-          } else if (complH)  {
-            //  a hydrogen and hydrogens are to be added
-            if (complXT)
-              A3[k] = A1[i];  // add unconditionally
-            else if (!strcmp(aname," HXT"))  {
-              // add HXT only if OXT is present in the residue
-              for (j=0;(j<natoms2) && (!A3[k]);j++)
-                if (A2[j])  {
-                  if ((!A2[j]->isTer()) &&
-                      (!strcmp(A2[j]->GetAtomName()," OXT")))
-                    A3[k] = A1[i];
-                }
-            } else  // add non-HXT anyway
-              A3[k] = A1[i];
-          }
-          if (A3[k])  {
-            A3[k]->Transform ( T );
-            A1[i] = NULL;
-            k++;
-          }
-        }
-      // add all atoms of original residue which were not superposed;
-      // these include Ter, if any is present
-      for (j=0;j<natoms2;j++)
-        if (x[j]<0)  {
-          A3[k] = newCAtom();
-          A3[k]->Copy ( A2[j] );
-          k++;
-        }
-      R->DeleteAllAtoms();
-      for (i=0;i<k;i++)
-        R->AddAtom ( A3[i] );
-      delete[] A3;
-    }
-
-  } else
-    rc = SBASE_NoSimilarity;
-
-  FreeVectorMemory ( x,0 );
-  FreeVectorMemory ( c,0 );
-  for (i=0;i<natoms1;i++)
-    if (A1[i])  delete A1[i];
-  delete[] A1;
-  delete   SBS;
-
-  return rc;
-
-}
-
-int CSBase0::ComplementChain ( PCChain chain, int complFlag,
-                               PCFile structFile )  {
-PCFile     sFile;
-PPCResidue Res;
-int        i,k,nRes,rc;
-Boolean    B;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  rc = SBASE_Ok;
-  B  = False;
-  chain->GetResidueTable ( Res,nRes );
-  for (i=0;i<nRes;i++)
-    if (Res[i])  {
-      k = ComplementResidue ( Res[i],complFlag,sFile );
-      if (k==SBASE_Ok)  B = True;
-                  else  rc = SBASE_Incomplete;
-    }
-  if (!B)  rc = SBASE_Fail;
-
-  if (!structFile)  delete sFile;
-
-  return rc;
-
-}
-
-int CSBase0::ComplementModel ( PCModel model, int complFlag,
-                               PCFile structFile )  {
-PCFile     sFile;
-PPCChain   chain;
-PPCResidue Res;
-int        i,j,k,nChains,nRes,rc;
-Boolean    B;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  rc = SBASE_Ok;
-  B  = False;
-  model->GetChainTable ( chain,nChains );
-  for (i=0;i<nChains;i++)
-    if (chain[i])  {
-      chain[i]->GetResidueTable ( Res,nRes );
-      for (j=0;j<nRes;j++)
-        if (Res[j])  {
-          k = ComplementResidue ( Res[j],complFlag,sFile );
-          if (k==SBASE_Ok)  B = True;
-                      else  rc = SBASE_Incomplete;
-        }
-    }
-  if (!B)  rc = SBASE_Fail;
-
-  if (!structFile)  delete sFile;
-
-  return rc;
-
-}
-
-int CSBase0::ComplementFile ( PCMMDBManager MMDB, int complFlag,
-                              PCFile structFile )  {
-PCFile     sFile;
-PPCModel   model;
-PPCChain   chain;
-PPCResidue Res;
-int        i,j,n,k,nModels,nChains,nRes,rc;
-Boolean    B;
-
-  if (structFile)  sFile = structFile;
-             else  sFile = GetStructFile();
-
-  if (!sFile)  return SBASE_FileNotFound;
-
-  rc = SBASE_Ok;
-  B  = False;
-  MMDB->GetModelTable ( model,nModels );
-  for (i=0;i<nModels;i++)
-    if (model[i])  {
-      model[i]->GetChainTable ( chain,nChains );
-      for (j=0;j<nChains;j++)
-        if (chain[j])  {
-          chain[j]->GetResidueTable ( Res,nRes );
-          for (n=0;n<nRes;n++)
-            if (Res[n])  {
-              k = ComplementResidue ( Res[n],complFlag,sFile );
-              if (k==SBASE_Ok)  B = True;
-                          else  rc = SBASE_Incomplete;
-            }
-        }
-    }
-  if (!B)  rc = SBASE_Fail;
-
-  if (!structFile)  delete sFile;
-
-  return rc;
-
-}
-
-
-int CSBase0::GetAtNames ( int structNo, PAtomName AtName,
-                          int & nAtoms, int & nH )  {
-int    rc;
-PCFile structFile;
-  if ((structNo<0) || (structNo>=nStructures))
-    return SBASE_WrongIndex;
-  if (Index[structNo]->loadPos>=0)  {
-    rc = GetAtNames ( NULL,structNo,AtName,nAtoms,nH );
-  } else  {
-    structFile = GetStructFile();
-    if (structFile)  {
-      rc = GetAtNames ( structFile,structNo,AtName,nAtoms,nH );
-      structFile->shut();
-      delete structFile;
-    } else
-      return SBASE_FileNotFound;
-  }
-  return rc;
-}
-
-
-int CSBase0::GetAtNames ( PCFile structFile, int structNo,
-                          PAtomName AtName,
-                          int & nAtoms, int & nH )  {
-PCSBStructure SBS;
-PCSBAtom      atom;
-int           i,j;
-pstr          p1,p2;
-Boolean       removeHydrogens;
-
-  if ((structNo<0) || (structNo>=nStructures))
-    return SBASE_WrongIndex;
-
-  removeHydrogens = (nH==-1);
-
-  if (Index[structNo]->loadPos>=0)  {
-
-    SBS = ldStructure[Index[structNo]->loadPos];
-
-  } else  {
-
-    structFile->seek ( Index[structNo]->fStructPos );
-    SBS = NULL;
-    StreamRead ( *structFile,SBS );
-
-    if ((!SBS) || (!structFile->Success()))  {
-      if (SBS)  delete SBS;
-      return SBASE_ReadError;
-    }
-
-  }
-
-  nAtoms = Index[structNo]->nAtoms;
-  nH     = 0;
-  if (Index[structNo]->Comp1)  {
-    p1 = strstr ( Index[structNo]->Comp1,"H(" );
-    if (p1)  {
-      p1 += 2;
-      p2  = p1;
-      while ((*p2) && (*p2!=')'))  p2++;
-      if (*p2==')')  {
-        *p2 = char(0);
-        nH  = mround(strtod(p1,NULL));
-        *p2 = ')';
-      }
-    }
-  }
-
-  if (removeHydrogens)  {
-    j = 0;
-    for (i=0;i<nAtoms;i++)  {
-      atom = SBS->Atom[i];
-      if (atom)  {
-        if ((atom->element[0]!='H') || (atom->element[1]))
-          strcpy ( AtName[j++],atom->pdb_name );
-      }
-    }
-  } else  {
-    for (i=0;i<nAtoms;i++)  {
-      atom = SBS->Atom[i];
-      if (atom)
-        strcpy ( AtName[i],atom->pdb_name );
-    }
-  }
-
-  if (Index[structNo]->loadPos<0)  delete SBS;
-
-  return SBASE_Ok;
-
-}
-
-int FindName ( PAtomName Nams, pstr N, int len )  {
-int      i;
-AtomName Nam;
-  i = 0;
-  while (i<len)  {
-    strcpy ( Nam,Nams[i] );
-    if (!strcmp(N,Nam))  break;
-    i++;
-  }
-  if (i>=len)  i = -1;
-  return i;
-}
-
-int CSBase0::GetNofAtoms ( int structNo,  int & nNonHAtoms,
-                           int & nHAtoms )  {
-pstr  p1,p2;
-
-  nNonHAtoms = 0;
-  nHAtoms    = 0;
-
-  if ((structNo<0) || (structNo>=nStructures))
-    return SBASE_WrongIndex;
-
-  nNonHAtoms = Index[structNo]->nAtoms;
-  nHAtoms    = 0;
-  if (Index[structNo]->Comp1)  {
-    p1 = strstr ( Index[structNo]->Comp1,"H(" );
-    if (p1)  {
-      p1 += 2;
-      p2  = p1;
-      while ((*p2) && (*p2!=')'))  p2++;
-      if (*p2==')')  {
-        *p2 = char(0);
-        nHAtoms = mround(strtod(p1,NULL));
-        *p2 = ')';
-      }
-    }
-  }
-
-  nNonHAtoms -= nHAtoms;
-
-  return SBASE_Ok;
-
-}
-
-int CSBase0::GetAtoms ( cpstr name,
-                        int & nNonHAtoms, PAtomName NonHAtName,
-                        int & nHAtoms,    PAtomName HAtName,
-                        ivector Hconnect, ivector Elem,
-                        ivector Chiral )  {
-PCSBStructure SBS;
-PCSBAtom      atom,atom2;
-PCSBBond      bond;
-int           i,j,structNo,rc;
-PCFile        structFile;
-
-  nNonHAtoms = 0;
-  nHAtoms    = 0;
-
-  structNo = GetStructNo ( name );
-  if (structNo<0)  return SBASE_StructNotFound;
-
-  if (Index[structNo]->loadPos>=0)  {
-
-    SBS = ldStructure[Index[structNo]->loadPos];
-
-  } else  {
-  
-    structFile = GetStructFile();
-    if (!structFile)  return SBASE_FileNotFound;
-
-    SBS = NULL;
-    structFile->seek ( Index[structNo]->fStructPos );
-    StreamRead       ( *structFile,SBS );
-    structFile->shut ();
-
-    if ((!SBS) || (!structFile->Success()))  {
-      if (SBS)  delete SBS;
-      delete structFile;
-      return SBASE_ReadError;
-    }
-    delete structFile;
-
-  }
-
-  rc = SBASE_Ok;
-
-  for (i=0;i<Index[structNo]->nAtoms;i++)  {
-    atom = SBS->Atom[i];
-    if (atom)  {
-      Elem[i] = getElementNo ( atom->element );
-      if ((atom->element[0]==' ') && (atom->element[1]=='H') &&
-          (!atom->element[2]))  {
-        strcpy ( HAtName[nHAtoms],atom->pdb_name );
-        nHAtoms++;
-      } else  {
-        strcpy ( NonHAtName[nNonHAtoms],atom->pdb_name );
-        nNonHAtoms++;
-      }
-      Chiral[i] = MakeChirInd ( atom->chirality );
-    }
-  }
-
-  if (nHAtoms>0)  {
-    for (j=0;j<nHAtoms;j++)
-      Hconnect[j] = -1;
-    for (i=0;i<Index[structNo]->nBonds;i++)  {
-      bond = SBS->Bond[i];
-      if (bond)  {
-        atom  = SBS->Atom[bond->atom1-1];
-        atom2 = SBS->Atom[bond->atom2-1];
-        if (atom && atom2)  {
-          j = FindName ( HAtName,atom->pdb_name,nHAtoms );
-          if (j>=0)
-            Hconnect[j] = FindName ( NonHAtName,atom2->pdb_name,
-                                     nNonHAtoms );
-          else  {
-            j = FindName ( HAtName,atom2->pdb_name,nHAtoms );
-            if (j>=0)
-              Hconnect[j] = FindName ( NonHAtName,atom->pdb_name,
-                                       nNonHAtoms );
-          }
-        }
-      }
-    }
-    j = 0;
-    while ((j<nHAtoms) && (Hconnect[j]>=0)) j++;
-    if (j<nHAtoms) 
-      rc = SBASE_ConnectivityError;
-  }
-
-  if (Index[structNo]->loadPos<0)  delete SBS;
-
-  return rc;
-
-}
-
-
-int  CSBase0::GetBonds ( cpstr    name,
-                         ivector nBonds, imatrix bondPair,
-                         int &   nAtoms, int     maxNAtoms,
-                         int     maxNBonds )  {
-PCGraph G;
-PCEdge  edge;
-PCFile  graphFile;
-int     structNo,i, a1,a2;
-
-  for (i=0;i<maxNAtoms;i++)
-    nBonds[i] = 0;
-
-  nAtoms = 0;
-
-  structNo = GetStructNo ( name );
-  if (structNo<0)  return SBASE_StructNotFound;
-
-  nAtoms = Index[structNo]->nAtoms;
-  if (nAtoms<=0)  return SBASE_Ok;
-
-  if (Index[structNo]->loadPos>=0)  {
-
-    G = ldGraph[Index[structNo]->loadPos];
-
-  } else  {
-
-    graphFile = GetGraphFile();
-    if (!graphFile)  return SBASE_FileNotFound;
-
-    G = NULL;
-    graphFile->seek ( Index[structNo]->fGraphPos );
-    StreamRead      ( *graphFile,G );
-    graphFile->shut ();
-
-    if ((!G) || (!graphFile->Success()))  {
-      if (G)  delete G;
-      delete graphFile;
-      return SBASE_ReadError;
-    }
-    delete graphFile;
-
-  }
-
-  for (i=0;i<G->nEdges;i++) {
-    edge = G->Edge[i];
-    if (edge)  {
-      if (edge->v1<edge->v2)  {
-        a1 = edge->v1;  a2 = edge->v2;
-      } else  {
-        a1 = edge->v2;  a2 = edge->v1;
-      }
-      a1--;  a2--;
-      if (nBonds[a1]<maxNBonds)  {
-        bondPair[a1][nBonds[a1]] = a2;
-        nBonds[a1]++;
-      }
-    }
-  }
-  
-  if (Index[structNo]->loadPos<0)  delete G;
-
-  return SBASE_Ok;
-
-}
-
-
-int  CSBase0::GetHetInfo ( cpstr       name,
-                           pstr        Formula,
-                           pstr        Hname,
-                           pstr        Hsynonym,
-                           pstr        Hcharge,
-                           PAtomName & ClinkAtom,
-                           PElement  & ClinkEle,
-                           PAtomName & SlinkAtom,
-                           PElement  & SlinkEle,
-                           int       & nLeavingAtoms )  {
-PCSBStructure SBS;
-PCFile        structFile;
-int           i,structNo;
-
-  Formula [0] = char(0);
-  Hname   [0] = char(0);
-  Hsynonym[0] = char(0);
-  Hcharge [0] = char(0);
-  ClinkAtom   = NULL;
-  ClinkEle    = NULL;
-  SlinkAtom   = NULL;
-  SlinkEle    = NULL;
-  nLeavingAtoms = 0;
-
-  structNo = GetStructNo ( name );
-  if (structNo<0)  return SBASE_StructNotFound;
-
-  structFile = GetStructFile();
-  if (!structFile)  return SBASE_FileNotFound;
-
-  SBS = NULL;
-  structFile->seek ( Index[structNo]->fStructPos );
-  StreamRead       ( *structFile,SBS );
-  structFile->shut ();
-
-  if ((!SBS) || (!structFile->Success()))  {
-    if (SBS)  delete SBS;
-    delete structFile;
-    return SBASE_ReadError;
-  }
-  delete structFile;
-
-  if (SBS->Formula) strcpy ( Formula ,SBS->Formula );
-  if (SBS->Synonym) strcpy ( Hsynonym,SBS->Synonym );
-  if (SBS->Name)    strcpy ( Hname   ,SBS->Name    );
-  if (SBS->Charge)  strcpy ( Hcharge ,SBS->Charge  );
-
-  nLeavingAtoms = SBS->nLeavingAtoms;
-  if (nLeavingAtoms>0)  {
-    SlinkAtom = new AtomName[nLeavingAtoms];
-    SlinkEle  = new Element [nLeavingAtoms];
-    ClinkAtom = new AtomName[nLeavingAtoms];
-    ClinkEle  = new Element [nLeavingAtoms];
-    for (i=0;i<nLeavingAtoms;i++)  {
-      strcpy (SlinkAtom[i],SBS->Atom[SBS->leavingAtom[i]-1]->pdb_name);
-      strcpy (SlinkEle [i],SBS->Atom[SBS->leavingAtom[i]-1]->element );
-      if (SBS->bondedAtom[i]>0)  {
-        strcpy(ClinkAtom[i],SBS->Atom[SBS->bondedAtom[i]-1]->pdb_name);
-        strcpy(ClinkEle [i],SBS->Atom[SBS->bondedAtom[i]-1]->element );
-      } else  {
-        ClinkAtom[i][0] = char(0);
-        ClinkEle [i][0] = char(0);
-      }
-    }
-  }
-
-  delete SBS;
-
-  return SBASE_Ok;
-
-}
-
diff --git a/mmdb/mmdb_sbase0.h b/mmdb/mmdb_sbase0.h
deleted file mode 100755
index 00e108d..0000000
--- a/mmdb/mmdb_sbase0.h
+++ /dev/null
@@ -1,746 +0,0 @@
-//  $Id: mmdb_sbase0.h,v 1.17 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_sbase0 <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CSBase0      ( structure base manager 0     )
-//       ~~~~~~~~~  CSBAtom      ( SB atom class                )
-//                  CSBBond      ( SB bond class                )
-//                  CSBStructure ( SB structure (monomer) class )
-//                  CSBIndex     ( SB index class               )
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef  __MMDB_SBase0__
-#define  __MMDB_SBase0__
-
-#ifndef  __MMDB_Manager__
-#include "mmdb_manager.h"
-#endif
-
-#ifndef  __MMDB_Graph__
-#include "mmdb_graph.h"
-#endif
-
-
-//  =================================================================
-
-//  --  oracle data field lengths
-#define compoundID_len       10
-#define formula_len          1000
-#define charge_len           5000
-#define name_len             1000
-#define synonym_len          1000
-#define sca_name_len         20
-#define pdb_name_len         20
-#define element_len          5
-#define sca_leaving_atom_len 3
-#define chirality_len        1
-#define scb_bond_order_len   10
-#define energy_type_len      8
-
-
-typedef char CompoundID   [compoundID_len+1];
-typedef char SBPDBName    [pdb_name_len+1];
-typedef char SBElementName[element_len+1];
-
-//  -- names for graph files
-#define sbIndexFile   cpstr("index.sbase")
-#define sbGraphFile   cpstr("graph.sbase")
-#define sbStructFile  cpstr("struct.sbase")
-
-
-//  ======================  SB Atom Class  =========================
-
-DefineClass(CSBAtom);
-
-class CSBAtom : public CStream  {
-
-  public :
-    char sca_name  [sca_name_len+1];    // SCA atom name
-    char pdb_name  [pdb_name_len+1];    // PDB atom name (aligned)
-    char old_pdb_name[pdb_name_len+1];  // old PDB atom name (aligned)
-    char element   [element_len+1];     // chemical element (aligned)
-    char energyType[energy_type_len+1]; // energy type; set to empty
-                                        // string "" if not provided
-    realtype x,y,z;                     // cartesian coordinates; set
-                                        // to -MaxReal if not provided
-    realtype x_esd,y_esd,z_esd;         // ESDs for cartesian coordi-
-                                        //   nates; set to 0.0 if not
-                                        //   provided
-    realtype ccp4_charge;               // atom charge from ccp4 libs
-    realtype sca_charge;                // formal atom charge (MSD)
-    realtype partial_charge;            // partial atom charge (MSD)
-    realtype vdw_radius;                // Van-der-Waals radius
-    realtype vdwh_radius;               // Van-der-Waals radius with
-                                        //   hydrogen
-    realtype ion_radius;                // ion radius
-    int      valency;                   // valency
-    char     chirality;                 // chirality: 'R', 'S' or 'N'
-    char     leaving;                   // leaving atom: 'Y' or 'N'
-    char     hb_type;                   // hydrogen bond type:
-                                        //   'D' donor
-                                        //   'A' acceptor
-                                        //   'B' both
-                                        //   'H' hydrogen candidate
-                                        //   'N' neither
-
-    CSBAtom ();
-    CSBAtom ( RPCStream Object );
-    ~CSBAtom();
-
-    void   makeCAtom ( RPCAtom a );
-    PCAtom makeCAtom ();
-
-    virtual void Copy  ( PCSBAtom A );
-
-    void read  ( RCFile f );
-    void write ( RCFile f );
-
-  protected :
-    void SBAtomInit();
-
-};
-
-DefineStreamFunctions(CSBAtom);
-
-
-
-//  =======================  SB Bond Class  ========================
-
-DefineClass(CSBBond);
-
-class CSBBond : public CStream  {
-
-  public :
-    int      atom1,atom2,order;  //   bonded atoms ordinal numbers in
-                                 // reference to the atom array in
-                                 // CSBStructure; atom1 and atom2
-                                 // number atoms like 1,2 on; these
-                                 // fields are always provided
-    realtype length,length_esd;  //   bond length in A and its esd;
-                                 // set to 0.0 if not provided by
-                                 // data base
-
-    CSBBond ();
-    CSBBond ( RPCStream Object );
-    ~CSBBond();
-
-    void  SetBond ( int at1, int at2, int ord );
-
-    virtual void  Copy ( PCSBBond B );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-  protected :
-    void  SBBondInit();
-
-};
-
-DefineStreamFunctions(CSBBond);
-
-
-
-//  =======================  SB Angle Class  =======================
-
-DefineClass(CSBAngle);
-
-class CSBAngle : public CStream  {
-
-  public :
-    int      atom1,atom2,atom3;  // number atoms like 1,2 on; always
-                                 // provided
-    realtype angle,angle_esd;    // angle is always provided; esd
-                                 // is set to 0.0 if not provided
-
-    CSBAngle ();
-    CSBAngle ( RPCStream Object );
-    ~CSBAngle();
-
-    virtual void  Copy  ( PCSBAngle G );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-  protected :
-    void  SBAngleInit();
-
-};
-
-DefineStreamFunctions(CSBAngle);
-
-
-//  ======================  SB Torsion Class  ======================
-
-DefineClass(CSBTorsion);
-
-class CSBTorsion : public CStream  {
-
-  public :
-    int   atom1,atom2,atom3,atom4; // number atoms like 1,2 on;
-                                   // always provided
-    realtype torsion,torsion_esd;  // torsion is always provided;
-                                   // esd is set to 0.0 if not provided
-
-    CSBTorsion ();
-    CSBTorsion ( RPCStream Object );
-    ~CSBTorsion();
-
-    virtual void  Copy  ( PCSBTorsion T );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-  protected :
-    void  SBTorsionInit();
-
-};
-
-DefineStreamFunctions(CSBTorsion);
-
-
-//  ====================  Structure Class  =========================
-
-DefineClass(CSBStructure);
-
-class CSBStructure : public CStream  {
-
-  public :
-    CompoundID   compoundID;  // CIF ID  -- always provided
-    pstr         Formula;     // NULL if not provided
-    pstr         Name;        // NULL if not provided
-    pstr         Synonym;     // NULL if not provided
-    pstr         Charge;      // NULL if not provided
-
-    //   Atom, Bond, Angle and Torsion point on the vectors of
-    // PCSBAtom[nAtoms], PCSBBond[nBonds], PCSBAngle[nAngles] and
-    // PCSBTorsion[nTorsions], respectively. Not all of them may be
-    // provided by the data base. If not provided, NULL is assigned.
-    int          nAtoms,nBonds,nAngles,nTorsions;
-    PPCSBAtom    Atom;        // always provided
-    PPCSBBond    Bond;        // report if not provided
-    PPCSBAngle   Angle;       // NULL if not provided
-    PPCSBTorsion Torsion;     // NULL if not provided
-
-    int          nLeavingAtoms;
-    ivector      leavingAtom;
-    ivector      bondedAtom;
-
-    char         xyz_source;  // 'A' for ACD coordinates,
-                              // 'R' for RCSB coordinates
-                              // 'P' for PDB coordinates
-                              // 'N' if xyz are not provided
-
-    CSBStructure ();
-    CSBStructure ( RPCStream Object );
-    ~CSBStructure();
-
-    void  Reset    ();
-
-    void  PutFormula ( cpstr F );
-    void  PutName    ( cpstr N );
-    void  PutSynonym ( cpstr S );
-    void  PutCharge  ( cpstr G );
-
-    void  AddAtom    ( PCSBAtom    atom    );
-    void  AddBond    ( PCSBBond    bond    );
-    void  MakeLeavingAtoms();
-    void  AddAngle   ( PCSBAngle   angle   );
-    void  AddTorsion ( PCSBTorsion torsion );
-
-    void  RemoveEnergyTypes();
-    int   SetEnergyType ( cpstr sca_name, cpstr energyType,
-                          realtype partial_charge );
-
-    int   GetAtomNo  ( cpstr sca_name ); // returns 0 if atom not
-                            // found, >0 gives the atom ordinal number
-    int   GetAtomNo_nss ( cpstr sca_name ); // same but disregards
-                            // leading and trailing spaces
-
-    PCSBAtom GetAtom ( cpstr sca_name );
-
-    //  GetAtomTable(..)  does not deallocate atomTable!
-    void  GetAtomTable ( PPCAtom & atomTable, int & nOfAtoms );
-
-    //  CheckAtoms() returns -1 if there is no atoms
-    //                       -2 if not all atoms are annotated
-    //                       -3 if not all coordinates are set
-    //                        0 otherwise
-    int   CheckAtoms();
-
-    //  GetAtomNameMatch(..) returns anmatch[i], i=0..nAtoms-1, equal
-    // to j such that name(Atom[i])==name(A[j]). Note that atom names
-    // are similarly aligned and space-padded in both MMDB and SBase.
-    // If ith atom in the structue is not found in A, anmatch[i] is
-    // set -1.
-    //   If array A contains atoms in different alternative
-    // conformations, the the value of altLoc is interpreted as
-    // follows:
-    //    NULL  - the highest occupancy atom will be taken
-    //            if all occupancies are equal then atom with
-    //            first altLoc taken
-    //    other - atoms with given altLoc are taken. If such
-    //            altLoc is not found, the function does as if
-    //            NULL value for altLoc is given.
-    //   A clean PDB file is anticipated, so that atoms with
-    // alternative conformations are grouped together.
-    //   It is Ok to have NULL pointers in A.
-    void  GetAtomNameMatch ( PPCAtom A, int nat, pstr altLoc,
-                             ivector anmatch );
-
-    PCResidue makeCResidue ( Boolean includeHydrogens=False,
-                             Boolean makeTer=False );
-
-    int       AddHydrogens ( PCResidue R );
-
-    virtual void  Copy ( PCSBStructure S );
-
-    void  read       ( RCFile f );
-    void  write      ( RCFile f );
-
-  protected :
-    int   nAAlloc,nBAlloc,nGAlloc,nTAlloc;
-    void  SBStructureInit();
-    void  FreeMemory     ();
-
-};
-
-DefineStreamFunctions(CSBStructure);
-
-
-
-//  ====================  Index Class  ==============================
-
-DefineClass(CSBIndex);
-
-class CSBIndex : public CStream  {
-
-  public :
-    CompoundID compoundID;  // CIF ID of the compound
-    int        nAtoms;      // number of atoms in the compound
-    int        nBonds;      // number of bonds in the compound
-    int        fGraphPos;   // offset for CGraph
-    int        fStructPos;  // offset for CSBStructure
-    int        loadPos;     // load ordinal number, not in the file
-    int        nXTs;        // total number of "XT"-atoms
-    pstr       Comp1;       // composition string
-    pstr       Comp2;       // composition string with leaving atom
-
-    CSBIndex ();
-    CSBIndex ( RPCStream Object );
-    ~CSBIndex();
-
-    int   MakeCompositions ( PCSBStructure SBS );
-
-    void  read  ( RCFile f );
-    void  write ( RCFile f );
-
-  protected :
-    void  SBIndexInit();
-
-};
-
-DefineStreamFunctions(CSBIndex);
-
-
-
-//  ==========================  CSBase0  ============================
-
-extern int MakeChirInd     ( char chirality );
-extern int MakeElementType ( int ElType, int  Chirality,
-                             Boolean Cflag );
-extern int MakeElementType ( int ElType, char chirality,
-                             Boolean Cflag );
-
-
-#define SBASE_noHBonds               6
-#define SBASE_noDonors               5
-#define SBASE_noAcceptors            4
-#define SBASE_Incomplete             3
-#define SBASE_AlreadyUnloaded        2
-#define SBASE_AlreadyLoaded          1
-#define SBASE_Ok                     0
-#define SBASE_FileNotFound          -1
-#define SBASE_StructNotFound        -2
-#define SBASE_WrongIndex            -3
-#define SBASE_ReadError             -4
-#define SBASE_ConnectivityError     -5
-#define SBASE_CheckFail             -6
-#define SBASE_NoAtomsFound          -7
-#define SBASE_NoBonds               -8
-#define SBASE_NoAtomData            -9
-#define SBASE_EmptyResidue         -10
-#define SBASE_NoSimilarity         -11
-#define SBASE_SuperpositionFailed  -12
-#define SBASE_Fail                 -13
-#define SBASE_BrokenBonds          -14
-#define SBASE_EmptyResSet          -15
-#define SBASE_noCoordHierarchy     -16
-
-#define CMPLF_Hydrogens  0x00000001
-#define CMPLF_nonHs      0x00000002
-#define CMPLF_XT         0x00000004
-#define CMPLF_All        0x00000007
-
-
-//   SDASelHandles is optionally used in MakeBonds(..), when
-// the latter works for hydrogen bond calculations.
-DefineStructure(SDASelHandles);
-struct SDASelHandles  {
-  int selHndDonor;
-  int selHndAcceptor;
-  int selHndHydrogen;
-  int selKey;
-  void getNewHandles    ( PCMMDBManager MMDB );
-  void makeSelIndexes   ( PCMMDBManager MMDB );
-  void deleteSelections ( PCMMDBManager MMDB );
-};
-
-
-DefineClass(CSBase0);
-
-class CSBase0  {
-
-  public :
-
-    CSBase0 ();
-    ~CSBase0();
-
-    //   LoadIndex() loads index of the structural database. 'path'
-    // must point on the directory containing the database files.
-    // The index must be loaded once before retrieving any
-    // information from the database.
-    //   LoadIndex() may return either SBASE_Ok or SBASE_FileNotFound.
-    int  LoadIndex  ( cpstr path   );
-    int  LoadIndex1 ( cpstr EnvVar );
-
-    //   LoadStructure(..) reads structure from *.sbase files and
-    // stores it in RAM for faster access. There is no special
-    // functions to access loaded structures, all requests to
-    // *.sbase files and RAM-storage are dispatched automatically.
-    int  LoadStructure   ( cpstr compoundID );
-    //   UnloadStructure(..) deletes strtucture from RAM and releases
-    // its memory. The structure is then accessible in the normal
-    // way from *.sbase files, which is slower.
-    int  UnloadStructure ( cpstr compoundID );
-
-    //   GetPath() returns full path to a file with file name FName
-    // in the database directory.  Length of S should suffice for
-    // accomodating the path. The function returns S.
-    //   GetPath() will work only after loading the database index.
-    pstr GetPath ( pstr & S, cpstr FName );
-
-    //   GetStructFile() creates and opens the database structure
-    // file and returns its pointer. In the case of errors returns
-    // NULL. Application is responsible for deleting this file.
-    PCFile GetStructFile();
-
-    //   GetGraphFile() creates and opens the database graph
-    // file and returns its pointer. In the case of errors returns
-    // NULL. Application is responsible for deleting this file.
-    PCFile GetGraphFile();
-
-    //   GetStructure(..) returns pointer to the monomer structure
-    // identified by 3-letter compoundID. If such structure is not
-    // found, the function returns NULL.
-    //   The function returns a pointer to a private copy of the
-    // structure. Modifying it will not change data in the structural
-    // database. The application is responsible for deallocating
-    // the structure after use (simply use delete).
-    //   See description of CSBStructure for the explanation of
-    // its fields.
-    PCSBStructure GetStructure ( cpstr compoundID );
-    PCSBStructure GetStructure ( int structNo, PCFile structFile );
-                                 // 0...nStructures-1
-
-    //   Another form of GetStructure(..) uses an open structure
-    // file, which allows to save on opening/closing file if
-    // multiple access to SBase structures is required. The file
-    // is neither open nor closed by the function
-    PCSBStructure GetStructure ( cpstr compoundID,
-                                 PCFile structFile );
-
-    PCResidue makeCResidue ( cpstr compoundID, 
-                             PCFile     structFile,
-                             Boolean    includeHydrogens=False,
-                             Boolean    makeTer=False );
-    PCResidue makeCResidue ( int        structNo, 
-                             PCFile     structFile,
-                             Boolean    includeHydrogens=False,
-                             Boolean    makeTer=False );
-
-
-    //   GetGraph(..) retrieves data for chemical structure number
-    // structNo (as described in Index) from graph file graphFile,
-    // then allocates and builds the corresponding graph, which is
-    // returned in G.
-    //   If Hflag is set >= 1, all hydrogens are removed from
-    // the graph. If Hflag is set to 2, element types of atoms,
-    // to which hydrogens are bonded, are modified with flag
-    // HYDROGEN_BOND.
-    //   Returns SBASE_Ok in case of success. Other return code are
-    // SBASE_WrongIndex and SBASE_ReadError.
-    int  GetGraph ( PCFile graphFile, int structNo, RPCGraph G,
-                    int Hflag );
-    int  GetGraph ( PCFile graphFile, RPCGraph G, int Hflag );
-    int  GetGraph ( int   structNo  , RPCGraph G, int Hflag );
-    int  GetGraph ( cpstr  compoundID, RPCGraph G, int Hflag );
-
-    //   GetStructNo() returns position of the structure with
-    // (3-letter) name 'name' as found in the database index.
-    //   Non-negative return means success, otherwise
-    // SBASE_StructNotFound indicates that the requested structure
-    // was not found in the database index.
-    int  GetStructNo ( cpstr compoundID );
-
-    int  GetNofAtoms ( cpstr compoundID );
-    int  GetNofAtoms ( int   structNo );
-
-    //   GetNofStructures() returns number of structures in the
-    // database index.
-    int  GetNofStructures() { return nStructures; }
-
-    //   CheckGraph(..) checks graph G against a same-name
-    // structure in the database. The name must be passed in
-    // G->name as a standard 3-letter code.
-    //   If Hflag is set >= 1, all hydrogens are removed from
-    // the graph. If Hflag is set to 2, element types of atoms,
-    // to which hydrogens are bonded, are modified with flag
-    // HYDROGEN_BOND.
-    //   If Cflag is set to True, then chirality information is
-    // assumed in the input graph G and it is used for the
-    // checking. If Cflag is set to False, then chirality
-    // information is neither assumed nor used for the checking.
-    // If chirality is there, all element IDs in the graph are
-    // assigned flag CHIRAL_RIGHT for 'R'-chirtality, CHIRAL_LEFT
-    // for 'S'-chirality and no flag if the atom is not a chiral
-    // center.
-    //   If a same-name structure is found in the database,
-    // the function returns the number of matched vertices
-    // (nMatched) from those found in the database (nInStructure).
-    // The correspondence between the input and database graphs
-    // is returned in array match (it should be of sufficient
-    // length) such that ith vertex of input graph corresponds
-    // to the match[i]th vertex of the database graph. The
-    // function then returns SBASE_Ok if the number of matched
-    // vertices coincides with nInStructure and nMatched, and
-    // the return is SBASE_CheckFail otherwise.
-    //   If a same-name structure is not found, the function
-    // returns SBASE_StructNotFound or SBASE_FileNotFound.
-    int  CheckGraph   ( PCGraph G, int Hflag, Boolean Cflag,
-                        int & nInStructure, int & nMatched,
-                        ivector match, int minMatchSize=0 );
-
-    //   In the current implementation of CheckResidue, Cflag
-    // must be always set False, as the chirality information
-    // cannot be calculated (in this version) from 3D coordinates.
-    // See the meaning of altLoc in mmdb_graph.h, other parameters
-    // are the same as in CheckGraph(..) above.
-    int  CheckResidue ( PCResidue R, int Hflag, Boolean Cflag,
-                        int & nInResidue, int & nInStructure,
-                        int & nMatched,   ivector match,
-                        cpstr altLoc=pstr(""),
-                        int minMatchSize=0 );
-
-
-
-    //   MakeBonds(..) makes bonds between atoms in MMDB's residue R
-    // from data found in SBase. Residue R must be associated with
-    // coordinate hierarchy. Data is retrieved from SBase on the basis
-    // of residue name only. In case of multiple conformations, if
-    // altLoc:
-    //    NULL  - the highest occupancy atom will be taken
-    //            if all occupancies are equal then atom with
-    //            first altLoc taken
-    //    other - atoms with given altLoc are taken. If such
-    //            altLoc is not found, the function does as if
-    //            NULL value for altLoc is given.
-    //   If selHandles is not NULL, the function also selects atoms
-    // in the residue according to their hydrogen bond attributes.
-    // This is a special option for hydrogen bond calculations
-    //   If ignoreNegSigOcc is set True then the function will ignore
-    // atoms with negative occupancy standard deviation. Such atoms
-    // may be hydrogens added by CSBase0::AddHydrogen(..) function,
-    // in general any atoms added by CSBAtom::MakeCAtom(..) function.
-    // Added hydrogens may be ignored if MakeBonds is used in
-    // CSbase::CalcHBonds(..) function.
-    //   Return:
-    //     SBASE_Ok             success
-    //     SBASE_FileNotFound   non-initiated SBase
-    //     SBASE_StructNotFound the residue's name is not found
-    //                          in SBase
-    //     SBASE_EmptyResidue   residue R does not contain atoms
-    //     SBASE_NoAtomsFound   SBase entry does not contain atoms
-    //     SBASE_BrokenBonds    some bonds could not be set up because
-    //                          of missing atoms in R. This could be
-    //                          a result of residue R named wrongly.
-    int  MakeBonds ( PCResidue      R,
-                     pstr           altLoc,
-                     PCFile         structFile,
-                     PSDASelHandles selHandles,
-                     Boolean        ignoreNegSigOcc );
-
-    int  GetEnergyTypes ( PCResidue  R,           PCFile structFile );
-    int  GetEnergyTypes ( PPCResidue R, int nRes, PCFile structFile );
-    int  GetEnergyTypes ( PCChain      chain,     PCFile structFile );
-    int  GetEnergyTypes ( PCModel      model,     PCFile structFile );
-    int  GetEnergyTypes ( PCMMDBManager MMDB,     PCFile structFile );
-
-
-    int  AddHydrogens   ( PCResidue        R, PCFile structFile );
-    int  AddHydrogens   ( PCChain      chain, PCFile structFile );
-    int  AddHydrogens   ( PCModel      model, PCFile structFile );
-    int  AddHydrogens   ( PCMMDBManager MMDB, PCFile structFile );
-
-
-    //   ComplementResidue(..) extracts data from SBase by residue
-    // name, then superposes atoms having identical names and
-    // adds the residue with atoms that are found in SBase but are
-    // absent in the residue. The added atoms are rotated and
-    // translated such as to comply with the superposed parts.
-    //   complFlag:
-    //     CMPLF_Hydrogens complement residue with hydrogens
-    //     CMPLF_nonHs     complement residue with non-hydrogens
-    //     CMPLF_XT        complement with C-terminus
-    //   Return:
-    //     SBASE_Ok             success
-    //     SBASE_FileNotFound   SBase is not initialized
-    //     SBASE_StructNotFound the residue's name is not found
-    //                          in SBase
-    //     SBASE_EmptyResidue   residue R does not contain atoms
-    //     SBASE_NoAtomsFound   SBase entry does not contain atoms
-    //     SBASE_NoAtomsData    SBase entry is not complete
-    //     SBASE_NoSimilarity   too few coomon atom names in R
-    //                          and SBase entry with the same
-    //                          structure name
-    //     SBASE_SuperpositionFailed  failed residue superposition
-    // NOTE: the function rearranges ALL atoms in the residue according
-    // to PDB order as written in SBase.
-    int  ComplementResidue ( PCResidue R, int complFlag,
-                             PCFile structFile=NULL );
-
-    //  The following will return
-    //     SBASE_Ok             success
-    //     SBASE_FileNotFound   SBase is not initialized
-    //     SBASE_Incomplete     some residues were not fully completed
-    //                          (warning)
-    //     SBASE_Fail           no residues were completed
-    int  ComplementChain   ( PCChain chain, int complFlag,
-                             PCFile structFile=NULL );
-    int  ComplementModel   ( PCModel model, int complFlag,
-                             PCFile structFile=NULL );
-    int  ComplementFile    ( PCMMDBManager MMDB, int complFlag,
-                             PCFile structFile=NULL );
-
-    //   GetAtomNames(...) returns atom names (AtName[i]), total
-    // number of atoms (nAtoms) and number of hydrogens (nH) for
-    // structure number structNo, as found in the database index.
-    // Length of AtName should allow for accomodating all atom
-    // names.
-    //   The function may return SBASE_Ok, SBASE_FileNotFound,
-    // SBASE_WrongIndex and SBASE_ReadError.
-    int  GetAtNames  ( int structNo,   PAtomName AtName,
-                       int & nAtoms, int & nH );
-
-    //   GetAtomNames(RCFile..) works exactly like its overload
-    // version above, however it allows to save time on reopening
-    // the database's description file (structFile). The file
-    // reference, passed to the function, should be associated with
-    // opened description file. The function does not close the file.
-    //   The function may return SBASE_Ok, SBASE_WrongIndex and
-    // SBASE_ReadError.
-    int  GetAtNames  ( PCFile structFile, int structNo,
-                       PAtomName  AtName, int & nAtoms, int & nH  );
-
-    //   GetNofAtoms(..) returns number of non-hydrogen atoms
-    // (nNonHAtoms) and number of hydrogens (nHAtoms) for structure
-    // number structNo, as found in the database index.
-    //   The function may return SBASE_Ok or SBASE_WrongIndex.
-    int  GetNofAtoms ( int structNo, int & nNonHAtoms, int & nHAtoms );
-
-    //   GetAtoms(...) retrieves the number of non-hydrogen atoms
-    // (nNonHAtoms), their names (NonHAtName), number of hydrogens
-    // (nHAtoms) and their names (HAtName), hydrogens' connectivity
-    // to non-hydrogen atoms (Hconnect), element IDs (Elem) and
-    // chiralities (Chiral) for structure named 'name'.
-    //   Hydrogen HAtName[i] is connected to non-hydrogen atom
-    // NonHAtom[Hconnect[i]], if Hconnect[i]>=0.
-    //   The function may return SBASE_Ok, SNASE_StructNotFound,
-    // SBASE_FileNotFound, SBASE_ReadError, SBASE_ConnectivityError.
-    int  GetAtoms ( cpstr compoundID,
-                    int & nNonHAtoms, PAtomName NonHAtName,
-                    int & nHAtoms,    PAtomName HAtName,
-                    ivector Hconnect, ivector Elem,
-                    ivector Chiral );
-
-    //   GetAtoms(...) retrieves the number of atoms (nAtoms) and
-    // number of bonds (nBonds[i]) and connectivity (bondPair[i][j])
-    // for all atoms in the structure named 'name'.  bondPair[i][j],
-    // 0<=i<nAtoms, 0<=j<nBonds[i], gives the number of atom connected
-    // to i-th atom. Only pairs i<j are returned.
-    //   maxNAtoms is the length of nBonds[] and bondPairs[],
-    // maxNBonds is the length of bondPairs[][].
-    //   The function may return SBASE_Ok, SBASE_StructNotFound,
-    // SBASE_FileNotFound, SBASE_ReadError.
-    int  GetBonds ( cpstr   compoundID,
-                    ivector nBonds, imatrix bondPair,
-                    int &   nAtoms, int     maxNAtoms,
-                    int     maxNBonds );
-
-
-    int  GetHetInfo ( cpstr       name,
-                      pstr        Formula,
-                      pstr        Hname,
-                      pstr        Hsynonym,
-                      pstr        Hcharge,
-                      PAtomName & ClinkAtom,  // will
-                      PElement  & ClinkEle,   //   be
-                      PAtomName & SlinkAtom,  //     allocated
-                      PElement  & SlinkEle,   //       or NULL
-                      int       & nLeavingAtoms );
-
-  protected :
-    pstr       dirpath;
-    PPCSBIndex Index;
-    int        nStructures;
-
-    void InitSBase0 ();
-    void FreeMemory0();
-
-  private :
-    int            nIAlloc,nLoad,nLAlloc;
-    PPCGraph       ldGraph;
-    PPCSBStructure ldStructure;
-
-};
-
-#endif
diff --git a/mmdb/mmdb_selmngr.cpp b/mmdb/mmdb_selmngr.cpp
deleted file mode 100755
index fca71c1..0000000
--- a/mmdb/mmdb_selmngr.cpp
+++ /dev/null
@@ -1,3393 +0,0 @@
-//  $Id: mmdb_selmngr.cpp,v 1.28 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_selmngr  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBSelManager ( MMDB atom selection manager )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __MMDB_SelMngr__
-#include "mmdb_selmngr.h"
-#endif
-
-
-
-//  ====================   CMMDBSelManager   =====================
-
-CMMDBSelManager::CMMDBSelManager() : CMMDBCoorManager()  {
-  InitMMDBSelManager();
-}
-
-CMMDBSelManager::CMMDBSelManager ( RPCStream Object )
-               : CMMDBCoorManager(Object)  {
-  InitMMDBSelManager();
-}
-
-CMMDBSelManager::~CMMDBSelManager()  {
-  DeleteAllSelections();
-}
-
-void  CMMDBSelManager::ResetManager()  {
-  CMMDBCoorManager::ResetManager();
-  DeleteAllSelections();
-  InitMMDBSelManager ();
-}
-
-void  CMMDBSelManager::InitMMDBSelManager()  {
-  nSelections = 0;     // number of selections
-  Mask        = NULL;  // vector of selections
-  SelType     = NULL;  // vector of selection types
-  nSelItems   = NULL;  // numbers of selected items
-  Selection   = NULL;  // vector of selected items
-}
-
-
-// ------------------------  Selection  -----------------------------
-
-int  CMMDBSelManager::NewSelection()  {
-int       i,l;
-PCMask    M;
-PPCMask   Mask1;
-PPCMask * Selection1;
-ivector   nSelItems1;
-ivector   SelType1;
-
-  M = new CMask();
-  M->NewMask ( Mask,nSelections );
-
-  i = 0;
-  while (i<nSelections)
-    if (!Mask[i])  break;
-             else  i++;
-
-  if (i>=nSelections)  {
-    l          = nSelections+10;
-    Mask1      = new PCMask [l];
-    Selection1 = new PPCMask[l];
-    nSelItems1 = new int[l];
-    SelType1   = new int[l];
-    for (i=0;i<nSelections;i++)  {
-      Mask1     [i] = Mask     [i];
-      Selection1[i] = Selection[i];
-      nSelItems1[i] = nSelItems[i];
-      SelType1  [i] = SelType  [i];
-    }
-    for (i=nSelections;i<l;i++)  {
-      Mask1     [i] = NULL;
-      Selection1[i] = NULL;
-      nSelItems1[i] = 0;
-      SelType1  [i] = STYPE_UNDEFINED;
-    }
-    if (Mask)      delete[] Mask;
-    if (Selection) delete[] Selection;
-    if (nSelItems) delete[] nSelItems;
-    if (SelType)   delete[] SelType;
-    Mask        = Mask1;
-    Selection   = Selection1;
-    nSelItems   = nSelItems1;
-    SelType     = SelType1;
-    i           = nSelections;
-    nSelections = l;
-  }
-
-  Mask[i] = M;
-  if (Selection[i])  delete[] Selection[i];
-  Selection[i] = NULL;
-  nSelItems[i] = 0;
-  SelType  [i] = STYPE_UNDEFINED;
-
-  return i+1;
-
-}
-
-int  CMMDBSelManager::GetSelType ( int selHnd )  {
-int k;
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    k = selHnd-1;
-    if (Mask[k])  return SelType[k];
-  }
-  return STYPE_INVALID;
-}
-
-void  CMMDBSelManager::DeleteSelection ( int selHnd )  {
-int i,k;
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    k = selHnd-1;
-    if (Mask[k])  {
-      for (i=0;i<nSelItems[k];i++)
-        if (Selection[k][i])
-          Selection[k][i]->RemoveMask ( Mask[k] );
-
-      //      for (i=0;i<nAtoms;i++)
-      //        if (Atom[i])
-      //          Atom[i]->RemoveMask ( Mask[k] );
-
-      delete Mask[k];
-    }
-    Mask[k] = NULL;
-    if (Selection[k])  delete[] Selection[k];
-    Selection[k] = NULL;
-    nSelItems[k] = 0;
-    SelType  [k] = STYPE_UNDEFINED;
-  }
-}
-
-
-PCMask CMMDBSelManager::GetSelMask ( int selHnd )  {
-  if ((selHnd>0) && (selHnd<=nSelections))
-       return Mask[selHnd-1];
-  else return NULL;
-}
-
-void  CMMDBSelManager::DeleteAllSelections()  {
-PCResidue res  ,res1;
-PCChain   chain,chain1;
-PCModel   model,model1;
-int       i;
-
-  if (Mask)  {
-    res   = NULL;
-    chain = NULL;
-    model = NULL;
-    if (Atom)
-      for (i=0;i<nAtoms;i++)
-        if (Atom[i])  {
-          Atom[i]->ClearMask();
-          res1 = Atom[i]->GetResidue();
-          if (res1!=res)  {
-            res = res1;
-            res->ClearMask();
-            chain1 = res->GetChain();
-            if (chain1!=chain)  {
-              chain = chain1;
-              chain->ClearMask();
-              model1 = chain->GetModel();
-              if (model1!=model)  {
-                model = model1;
-                model->ClearMask();
-              }
-            }
-          }
-        }
-    for (i=0;i<nSelections;i++)  {
-      if (Mask     [i])  delete   Mask[i];
-      if (Selection[i])  delete[] Selection[i];
-    }
-    delete[] Mask;
-    if (Selection) delete[] Selection;
-    if (nSelItems) delete[] nSelItems;
-    if (SelType)   delete[] SelType;
-  }
-
-  nSelections = 0;
-  Mask        = NULL;
-  Selection   = NULL;
-  nSelItems   = NULL;
-  SelType     = NULL;
-
-}
-
-void  CMMDBSelManager::SelectAtoms ( int selHnd, int iSer1, int iSer2,
-                                     int selKey )  {
-//   SelectAtoms(..) selects atoms in the serial number range
-// of iSer1 to iSer2 by adding them to the set of atoms
-// marked by the given mask. If iSer1=iSer2=0 then all atoms
-// are selected. Each atom may be selected by a number of masks
-// simultaneously
-int i,s1,s2,k, sk,nsel;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))           SelType[k] = STYPE_ATOM;
-  else if (SelType[k]!=STYPE_ATOM)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nAtoms;i++)
-                      if (Atom[i])  Atom[i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;             break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-  }
-
-  if ((iSer1==0) && (iSer2==0))  {
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        if (!Atom[i]->Ter)
-          SelectAtom ( Atom[i],k,sk,nsel );
-      }
-  } else  {
-    if (iSer1<=iSer2)  {
-      s1 = iSer1;
-      s2 = iSer2;
-    } else  {
-      s1 = iSer2;
-      s2 = iSer1;
-    }
-    // for a very general use, we allow the serial number
-    // to differ from the atom's index, although this is
-    // against PDB format. Therefore we apply here the most
-    // primitive and less efficient way of selection
-    for (i=0;i<nAtoms;i++)
-      if (Atom[i])  {
-        if (!Atom[i]->Ter)  {
-          if ((s1<=Atom[i]->serNum) && (Atom[i]->serNum<=s2))
-            SelectAtom ( Atom[i],k,sk,nsel );
-          else if (sk==SKEY_AND)
-            Atom[i]->RemoveMask ( Mask[k] );
-        }
-      }
-  }
-
-  MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
-
-}
-
-
-void  CMMDBSelManager::SelectAtoms ( int selHnd, ivector asn, int nsn,
-                                     int selKey )  {
-//   SelectAtoms(..) selects atoms with serial numbers given in
-// vector asn[0..nsn-1].
-CQuickSort QS;
-ivector    asn1;
-int        i,k,nsn1,j,j1,j2, sk,sn,nsel;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))           SelType[k] = STYPE_ATOM;
-  else if (SelType[k]!=STYPE_ATOM)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nAtoms;i++)
-                      if (Atom[i])  Atom[i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;             break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-  }
-
-  GetVectorMemory ( asn1,nsn,0 );
-  for (i=0;i<nsn;i++)
-    asn1[i] = asn[i];
-
-  QS.Sort ( asn1,nsn );
-  nsn1 = nsn-1;
-
-  for (i=0;i<nAtoms;i++)
-    if (Atom[i])  {
-      if (!Atom[i]->Ter)  {
-        sn = Atom[i]->serNum;
-        if ((asn1[0]<=sn) && (sn<=asn1[nsn1]))  {
-          // binary search
-          j1 = 0;
-          j2 = nsn1;
-          do  {
-            j = (j1+j2)/2;
-            if (sn<asn1[j])      j2 = j;
-            else if (sn>asn1[j]) j1 = j;
-                            else j1 = j2;
-          } while (j1<j2-1);
-          if ((sn==asn1[j]) || (sn==asn1[j1]) || (sn==asn1[j2]))
-            SelectAtom ( Atom[i],k,sk,nsel );
-          else if (sk==SKEY_AND)
-            Atom[i]->RemoveMask ( Mask[k] );
-        } else if (sk==SKEY_AND)
-          Atom[i]->RemoveMask ( Mask[k] );
-      }
-    }
-
-  FreeVectorMemory ( asn1,0 );
-
-  MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
-
-}
-
-
-void  CMMDBSelManager::UnselectAtoms ( int selHnd, int iSer1, int iSer2 )  {
-//   UnselectAtoms(..) clears the specified mask for atoms in
-// the serial number range of iSer1 to iSer2. If iSer1=iSer2=0
-// then all atoms are cleared of the specified mask. If selHnd
-// is set to 0, then the atoms are cleared of any mask.
-int i,s1,s2,k;
-
-  if ((selHnd<=nSelections) && (nAtoms>0))  {
-
-    k = selHnd-1;
-
-    if (SelType[k]==STYPE_UNDEFINED)  SelType[k] = STYPE_ATOM;
-    else if (SelType[k]!=STYPE_ATOM)  return;
-
-    if ((iSer1==0) && (iSer2==0))  {
-      if (k<0) {
-        for (i=0;i<nAtoms;i++)
-          if (Atom[i]) Atom[i]->ClearMask();
-      } else  {
-        for (i=0;i<nAtoms;i++)
-          if (Atom[i]) Atom[i]->RemoveMask ( Mask[k] );
-      }
-    } else  {
-      if (iSer1<=iSer2)  {
-        s1 = iSer1;
-        s2 = iSer2;
-      } else  {
-        s1 = iSer2;
-        s2 = iSer1;
-      }
-      // for a very general use, we allow the serial number
-      // to differ from the atom's index, although this is
-      // against PDB format. Therefore we apply here the most
-      // primitive and less efficient way of selection
-      if (k<0)  {
-        for (i=0;i<nAtoms;i++)
-          if (Atom[i])  {
-            if ((s1<=Atom[i]->serNum) && (Atom[i]->serNum<=s2))
-              Atom[i]->ClearMask();
-          }
-      } else  {
-        for (i=0;i<nAtoms;i++)
-          if (Atom[i])  {
-            if ((s1<=Atom[i]->serNum) && (Atom[i]->serNum<=s2))
-              Atom[i]->RemoveMask ( Mask[k] );
-          }
-      }
-    }
-
-    MakeSelIndex ( selHnd,STYPE_ATOM,-1 );
-
-  }
-
-}
-
-
-pstr MakeList ( cpstr S )  {
-// makes the list of selecting items:
-//   1st character - special use,
-//       then each item from S embraced by commas
-pstr L;
-int  i,j;
-  i = 0;
-  while (S[i]==' ')  i++;
-  if (S[i]!='*')  {
-    // compile a searchable list
-    L = new char[strlen(S)+5];
-    if (S[i]=='!')  {
-      L[0] = '!';
-      i++;
-    } else
-      L[0] = ' ';
-    if (strchr(S,'['))  L[1] = '"';
-                  else  L[1] = ' ';
-    L[2] = ',';
-    j    = 3;
-    while (S[i])  {
-      while (S[i]==' ')  i++;
-      if (S[i]=='[')  {
-        while (S[i] && (S[i]!=']'))
-          L[j++] = S[i++];
-        L[j++] = ']';
-        if (S[i]==']')  i++;
-      } else
-        while (S[i] && (S[i]!=' ') && (S[i]!=','))
-          L[j++] = S[i++];
-      while (S[i]==' ')  i++;
-      L[j++] = ',';
-      if (S[i]==',')  {
-        i++;
-        if (!S[i])  L[j++] = ',';  // blank chain ID at the end assumed
-      }
-    }
-    if (j==3)  L[j++] = ',';
-    L[j] = char(0);
-  } else
-    L = NULL;
-  return L;
-}
-
-Boolean MatchName ( pstr L, pstr N )  {
-char M[MaxMMDBNameLength+5];
-int  i,j;
-  if (L)  {
-    i    = 0;
-    M[0] = ',';
-    j    = 1;
-    while (N[i])
-      if (N[i]==' ')  i++;
-                else  M[j++] = N[i++];
-    M[j++] = ',';
-    M[j]   = char(0);
-    if (strstr(&(L[2]),M))  return (L[0]!='!');
-    else if (L[1]!='"')     return (L[0]=='!');
-    else  {
-      strcpy ( M,",[" );
-      strcat ( M,N    );
-      strcat ( M,"]," );
-      if (strstr(&(L[2]),M))  return (L[0]!='!');
-                        else  return (L[0]=='!');
-    }
-  } else
-    return True;
-}
-
-Boolean MatchCharge ( pstr L, PCAtom atom )  {
-char N[100];
-  if (L)  {
-    if (atom->WhatIsSet & ASET_Charge)  {
-      sprintf ( N,"%+2i",mround(atom->charge) );
-      return MatchName ( L,N );
-    } else
-      return False;
-  } else
-    return True;
-}
-
-
-void CMMDBSelManager::SelectAtom ( int selHnd, PCAtom A, int selKey,
-                                   Boolean makeIndex )  {
-int i, k, sk, nsel;
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))           SelType[k] = STYPE_ATOM;
-  else if (SelType[k]!=STYPE_ATOM)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-  }
-
-  SelectAtom ( A,k,sk,nsel);
-  if (makeIndex)  MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectResidue ( int selHnd, PCResidue Res,
-                                      int selType, int selKey,
-                                      Boolean makeIndex )  {
-//  Selects residue Res or all its atoms depending on selType
-PPCAtom A;
-int     i, k, sk, nsel, nat;
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))           SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-  }
-
-  switch (selType)  {
-    case STYPE_ATOM    :  Res->GetAtomTable ( A,nat );
-                          for (i=0;i<nat;i++)
-                            if (A[i])  {
-                              if (!A[i]->Ter)
-                                SelectAtom ( A[i],k,sk,nsel);
-                            }
-                        break ;
-    case STYPE_RESIDUE :  SelectObject ( Res,k,sk,nsel );
-                        break ;
-    default : ;
-  }
-
-  if (makeIndex)  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectChain ( int selHnd, PCChain Chain,
-                                    int selType, int selKey,
-                                    Boolean makeIndex )  {
-//  Selects chain Chain or all its residues or atoms depending on selType
-PPCAtom    A;
-PPCResidue Res;
-int        i,j, k, sk, nsel, nat,nres;
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))           SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-  }
-
-  switch (selType)  {
-    case STYPE_ATOM    :  Chain->GetResidueTable ( Res,nres );
-                          for (i=0;i<nres;i++)
-                            if (Res[i])  {
-                              Res[i]->GetAtomTable ( A,nat );
-                              for (j=0;j<nat;j++)
-                                if (A[j])  {
-                                  if (!A[j]->Ter)
-                                    SelectAtom ( A[j],k,sk,nsel);
-                                }
-                            }
-                        break ;
-    case STYPE_RESIDUE :  Chain->GetResidueTable ( Res,nres );
-                          for (i=0;i<nres;i++)
-                            if (Res[i])
-                              SelectObject ( Res[i],k,sk,nsel );
-                        break ;
-    case STYPE_CHAIN   :  SelectObject ( Chain,k,sk,nsel );
-                        break ;
-    default : ;
-  }
-
-  if (makeIndex)  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectModel ( int selHnd, PCModel model,
-                                    int selType, int selKey,
-                                    Boolean makeIndex )  {
-//  Selects model or all its chains or residues or atoms depending
-// on selType
-PPCAtom    A;
-PPCResidue Res;
-PPCChain   Chain;
-int        i,j,n, k, sk, nsel, nat,nres,nch;
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))           SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-  }
-
-  switch (selType)  {
-    case STYPE_ATOM    :  model->GetChainTable ( Chain,nch );
-                          for (i=0;i<nch;i++)
-                            if (Chain[i])  {
-                              Chain[i]->GetResidueTable ( Res,nres );
-                              for (j=0;j<nres;j++)
-                                if (Res[j])  {
-                                  Res[j]->GetAtomTable ( A,nat );
-                                  for (n=0;n<nat;n++)
-                                    if (A[n])  {
-                                      if (!A[n]->Ter)
-                                        SelectAtom ( A[n],k,sk,nsel);
-                                    }
-                                }
-                            }
-                        break ;
-    case STYPE_RESIDUE :  model->GetChainTable ( Chain,nch );
-                          for (i=0;i<nch;i++)
-                            if (Chain[i])  {
-                              Chain[i]->GetResidueTable ( Res,nres );
-                              for (j=0;j<nres;j++)
-                                if (Res[j])
-                                  SelectObject ( Res[j],k,sk,nsel );
-                            }
-                        break ;
-    case STYPE_CHAIN   :  model->GetChainTable ( Chain,nch );
-                          for (i=0;i<nch;i++)
-                            if (Chain[i])
-                              SelectObject ( Chain[i],k,sk,nsel );
-                        break ;
-    case STYPE_MODEL   :  SelectObject ( model,k,sk,nsel );
-                        break ;
-    default : ;
-  }
-
-  if (makeIndex)  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-int CMMDBSelManager::MakeSelIndex ( int selHnd )  {
-int k;
-  if ((selHnd<=0) || (selHnd>nSelections))  return 0;
-  k = selHnd-1;
-  if (SelType[k]==STYPE_UNDEFINED)  return 0;
-  MakeSelIndex ( selHnd,SelType[k],-1 );
-  return nSelItems[k];
-}
-
-void CMMDBSelManager::MakeAllSelIndexes()  {
-int k;
-  for (k=0;k<nSelections;k++)
-    if (SelType[k]!=STYPE_UNDEFINED)
-      MakeSelIndex ( k+1,SelType[k],-1 );
-}
-
-void  CMMDBSelManager::SelectAtoms (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   iModel,   // model number; iModel=0 means
-                             // 'any models'
-             cpstr Chains,   // may be several chains "A,B,W";
-                             // "*" means 'any chain' (in model)
-             int   ResNo1,   // starting residue number
-             cpstr Ins1,     // starting residue insertion code;
-                             // "*" means 'any code'
-             int   ResNo2,   // ending residue number.
-                             // ResNo1=ResNo2=ANY_RES
-                             // means 'any residue number'
-                             // (in chain)
-             cpstr Ins2,     // ending residue insertion code
-                             // "*" means 'any code'
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means
-                             // 'any residue name'
-             cpstr ANames,   // may be several names "CA,CB";
-                             // "*" means 'any atom' (in residue)
-             cpstr Elements, // may be several element types like
-                             // "H,C,O,CU"; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means 'any
-                             // alternative location'
-             cpstr Segments, // may be several segment IDs like
-                             // "S1,S2,A234"; "*" means 'any
-                             // segment'
-             cpstr Charges,  // may be several charges like
-                             // "+1,-2,  "; "*" means 'any charge'
-             realtype occ1,  // lowest occupancy
-             realtype occ2,  // highest occupancy;
-                             // occ1=occ2<0.0 means
-                             // "any occupancy"
-             realtype x0,    // reference x-point
-             realtype y0,    // reference y-point
-             realtype z0,    // reference z-point
-             realtype d0,    // selection distance from the reference
-                             // reference point; d0<=0.0 means
-                             // 'any distance" and values of
-                             // x0, y0 and z0 are ignored
-             int  selKey     // selection key
-                    )  {
-
-  Select ( selHnd,STYPE_ATOM,iModel,Chains,ResNo1,Ins1,ResNo2,Ins2,
-           RNames,ANames,Elements,altLocs,Segments,Charges,
-           occ1,occ2,x0,y0,z0,d0,selKey );
-
-}
-
-
-#define  hetIndicator '@'
-
-void  CMMDBSelManager::Select (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   selType,  // selection type STYPE_XXXXX
-             int   iModel,   // model number; iModel=0 means
-                             // 'any models'
-             cpstr Chains,   // may be several chains "A,B,W";
-                             // "*" means 'any chain' (in model)
-             int   ResNo1,   // starting residue number
-             cpstr Ins1,     // starting residue insertion code;
-                             // "*" means 'any code'
-             int   ResNo2,   // ending residue number.
-                             // ResNo1=ResNo2=ANY_RES means 'any
-                             // residue number' (in chain)
-             cpstr Ins2,     // ending residue insertion code
-                             // "*" means 'any code'
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means 'any
-                             // residue name'
-             cpstr ANames,   // may be several names "CA,CB";"*"
-                             // means 'any atom' (in residue)
-             cpstr Elements, // may be several element types like
-                             // "H,C,O,CU"; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means 'any
-                             // alternative location'
-             cpstr Segments, // may be several segment IDs like
-                             // "S1,S2,A234"; "*" means 'any
-                             // segment'
-             cpstr Charges,  // may be several charges like
-                             // "+1,-2,  "; "*" means 'any charge'
-             realtype occ1,  // lowest occupancy
-             realtype occ2,  // highest occupancy;
-                             // occ1=occ2<0.0 means
-                             // "any occupancy"
-             realtype x0,    // reference x-point
-             realtype y0,    // reference y-point
-             realtype z0,    // reference z-point
-             realtype d0,    // selection distance from the reference
-                             // reference point; d0<=0.0 means
-                             // 'any distance" and values of
-                             // x0, y0 and z0 are ignored
-             int  selKey     // selection key
-                    )  {
-int       i,j,k,n,m1,m2,c, sk,nsel;
-realtype  dx,dy,dz,d02;
-Boolean   noRes,Occ,Dist,Sel,selAND;
-Boolean   modelSel,chainSel,resSel;
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-PCAtom    atom;
-pstr      chain_l;
-pstr      res_l;
-pstr      atom_l;
-pstr      elem_l;
-pstr      altLocs1;
-pstr      aloc_l;
-pstr      segm_l;
-pstr      charge_l;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
-
-  modelSel = False;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;             break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-  selAND   = (selKey==SKEY_AND);
-
-  altLocs1 = NULL;
-  if (altLocs)  {
-    if (strchr(altLocs,hetIndicator))  {
-      CreateCopy ( altLocs1,altLocs );
-      DelSpaces  ( altLocs1 );
-      aloc_l = strchr ( altLocs1,hetIndicator );
-      aloc_l[0] = ' ';
-      if (aloc_l[1])  aloc_l[1] = ' ';  // instead of comma
-      else if (aloc_l!=altLocs1)  {
-        aloc_l--;
-        aloc_l[0] = ' ';
-      }
-      DelSpaces  ( altLocs1 );
-      aloc_l = MakeList ( altLocs1 );
-    } else
-      aloc_l = MakeList ( altLocs );
-  } else
-    aloc_l = MakeList ( altLocs );
-
-  chain_l  = MakeList ( Chains   );
-  res_l    = MakeList ( RNames   );
-  atom_l   = MakeList ( ANames   );
-  elem_l   = MakeList ( Elements );
-  segm_l   = MakeList ( Segments );
-  charge_l = MakeList ( Charges  );
-
-  //  noRes==True means no residue restrictions
-  noRes = (ResNo1==ResNo2)   && (ResNo1==ANY_RES) &&
-          (Ins1[0]==Ins2[0]) && (Ins1[0]=='*');
-
-  Occ  = (occ1>=0.0) || (occ2>=0.0);
-  Dist = (d0>0.0);
-  d02  = d0*d0;
-
-  m1   = iModel-1;
-
-  if (m1>=0)
-    m2 = m1+1;     // will take only this model
-  else  {
-    m1 = 0;        // will take
-    m2 = nModels;  //   all models
-  }
-
-  if (m1>=nModels)  return;
-
-  for (n=0;n<nModels;n++)  {
-    model = Model[n];
-    if (model)  {  // check for safety
-      if ((m1<=n) && (n<m2))  {
-        modelSel = False; // will be True on any selection in the model
-        for (c=0;c<model->nChains;c++)  {
-          chain = model->Chain[c];
-          if (chain)  {   // again check for safety
-            if (MatchName(chain_l,chain->chainID))  {
-              // the chain has to be taken
-              i = 0;
-              if (!noRes)
-                while (i<chain->nResidues)  {
-                  res = chain->Residue[i];
-                  if (res)  {
-                    if ((res->seqNum==ResNo1) &&
-                        MatchName(res_l,res->name) &&
-                        ((Ins1[0]=='*') ||
-                         (!strcmp(res->insCode,Ins1))))
-                      break;
-                    else if (selAND)  {
-                      if (selType==STYPE_ATOM)
-                        res->UnmaskAtoms ( Mask[k] );
-                      else if (selType==STYPE_RESIDUE)
-                        res->RemoveMask ( Mask[k] );
-                    }
-                  }
-                  i++;
-                }
-              while (i<chain->nResidues)  {
-                res = chain->Residue[i];
-                if (res)  {
-                  resSel = False; // will be True on 1st sel-n in the res-e
-                  if (MatchName(res_l,res->name))  {
-                    for (j=0;j<res->nAtoms;j++)  {
-                      atom = res->atom[j];
-                      if (atom)  {
-                        if ((!atom->Ter)                      &&
-                            MatchName(atom_l  ,atom->name   ) &&
-                            MatchName(elem_l  ,atom->element) &&
-                            MatchName(aloc_l  ,atom->altLoc ) &&
-                            MatchName(segm_l  ,atom->segID  ) &&
-                            MatchCharge(charge_l,atom       ) &&
-                            ((!altLocs1) || atom->Het))  {
-                          Sel = True;
-                          if (Occ)
-                            Sel = ((occ1<=atom->occupancy) &&
-                                   (atom->occupancy<=occ2));
-                          if (Dist)  {
-                            dx  = atom->x - x0;
-                            dy  = atom->y - y0;
-                            dz  = atom->z - z0;
-                            Sel = Sel && ((dx*dx+dy*dy+dz*dz)<=d02);
-                          }
-                        } else
-                          Sel = False;
-                        if (Sel)  {
-                          SelectObject ( selType,atom,k,sk,nsel );
-                          resSel   = True;
-                          chainSel = True;
-                          modelSel = True;
-                        } else if (selAND && (selType==STYPE_ATOM))
-                          atom->RemoveMask ( Mask[k] );
-                      }
-                      if (resSel && (selType!=STYPE_ATOM))  break;
-                    }
-                  } else if (selAND && (selType==STYPE_ATOM))
-                      res->UnmaskAtoms ( Mask[k] );
-                  if ((!resSel) && selAND && (selType==STYPE_RESIDUE))
-                    res->RemoveMask ( Mask[k] );
-                  if (chainSel && (selType>STYPE_RESIDUE))  break;
-                  if (!noRes)  {
-                    if ((res->seqNum==ResNo2) &&
-                        ((Ins2[0]=='*') || (!strcmp(res->insCode,Ins2)))
-                       )  break;
-                  }
-                }
-                i++;
-              }
-              if (selAND)  {
-                if (selType==STYPE_ATOM)
-                  while (i<chain->nResidues)  {
-                    res = chain->Residue[i];
-                    if (res)  res->UnmaskAtoms ( Mask[k] );
-                    i++;
-                  }
-                if (selType==STYPE_RESIDUE)
-                  while (i<chain->nResidues)  {
-                    res = chain->Residue[i];
-                    if (res)  res->RemoveMask ( Mask[k] );
-                    i++;
-                  }
-              }
-            } else if (selAND)
-              switch (selType)  {
-                case STYPE_ATOM    : chain->UnmaskAtoms    ( Mask[k] ); break;
-                case STYPE_RESIDUE : chain->UnmaskResidues ( Mask[k] ); break;
-                case STYPE_CHAIN   : chain->RemoveMask     ( Mask[k] ); break;
-                default            : ;
-              }
-            if ((!chainSel) && selAND && (selType==STYPE_CHAIN))
-              chain->RemoveMask ( Mask[k] );
-            if (modelSel && (selType>STYPE_CHAIN))  break;
-          }
-        }
-      } else if (selAND)
-        switch (selType)  {
-          case STYPE_ATOM    : model->UnmaskAtoms    ( Mask[k] ); break;
-          case STYPE_RESIDUE : model->UnmaskResidues ( Mask[k] ); break;
-          case STYPE_CHAIN   : model->UnmaskChains   ( Mask[k] ); break;
-          default            : ;
-        }
-      if ((!modelSel) && selAND && (selType==STYPE_MODEL))
-        model->RemoveMask ( Mask[k] );
-    }
-  }
-
-  // release dynamic memory
-  if (chain_l)  delete[] chain_l;
-  if (res_l)    delete[] res_l;
-  if (atom_l)   delete[] atom_l;
-  if (elem_l)   delete[] elem_l;
-  if (altLocs1) delete[] altLocs1;
-  if (aloc_l)   delete[] aloc_l;
-  if (segm_l)   delete[] segm_l;
-  if (charge_l) delete[] charge_l;
-
-  MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
-
-}
-
-
-void  CMMDBSelManager::SelectAtoms (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   iModel,   // model number; iModel=0 means
-                             // 'any models'
-             cpstr Chains,   // may be several chains "A,B,W";
-                             // "*" means 'any chain' (in model)
-             int   ResNo1,   // starting residue number
-             cpstr Ins1,     // starting residue insertion code;
-                             // "*" means 'any code'
-             int   ResNo2,   // ending residue number.
-                             // ResNo1=ResNo2=ANY_RES means 'any
-                             // residue number' (in chain)
-             cpstr Ins2,     // ending residue insertion code
-                             // "*" means 'any code'
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means 'any
-                             // residue name'
-             cpstr ANames,   // may be several names "CA,CB"; "*"
-                             // means 'any atom' (in residue)
-             cpstr Elements, // may be several element types like
-                             // "H,C,O,CU"; "*" means 'any
-                             // element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means 'any
-                             // alternative location'
-             int   selKey    // selection key
-                    )  {
-  Select ( selHnd,STYPE_ATOM,iModel,Chains,ResNo1,Ins1,ResNo2,Ins2,
-           RNames,ANames,Elements,altLocs,selKey );
-}
-
-
-int  CMMDBSelManager::Select (
-             int   selHnd,  // must be obtained from NewSelection()
-             int   selType, // selection type STYPE_XXXXX
-             cpstr CID,     // coordinate ID
-             int   selKey   // selection key
-                    )  {
-int     iModel,l,RC;
-pstr    Chains;
-int     seqNum1 ,seqNum2;
-InsCode insCode1,insCode2;
-pstr    RNames;
-pstr    ANames;
-pstr    Elements;
-pstr    altLocs;
-
-  l = IMax(10,strlen(CID))+1;
-  Chains   = new char[l];
-  RNames   = new char[l];
-  ANames   = new char[l];
-  Elements = new char[l];
-  altLocs  = new char[l];
-
-  if (strcmp(CID,"-all"))  {
-    RC = ParseSelectionPath ( CID,iModel,Chains,seqNum1,insCode1,
-                              seqNum2,insCode2,RNames,ANames,
-                              Elements,altLocs );
-  } else  {
-    iModel = 0;
-    strcpy ( Chains,"*" );
-    seqNum1 = ANY_RES;
-    seqNum2 = ANY_RES;
-    strcpy ( insCode1,"*" );
-    strcpy ( insCode2,"*" );
-    strcpy ( RNames  ,"*" );
-    strcpy ( ANames  ,"*" );
-    strcpy ( Elements,"*" );
-    strcpy ( altLocs ,""  ); // only main conformation by default
-    RC = 0;
-  }
-
-  if (!RC)  {
-    Select ( selHnd,selType,iModel,Chains,seqNum1,insCode1,
-             seqNum2,insCode2,RNames,ANames,Elements,altLocs,selKey );
-    RC = 0;
-  }
-
-  delete[] Chains;
-  delete[] RNames;
-  delete[] ANames;
-  delete[] Elements;
-  delete[] altLocs;
-
-  return RC;
-
-}
-
-void  CMMDBSelManager::Select (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   selType,  // selection type STYPE_XXXXX
-             int   iModel,   // model number; iModel=0 means
-                             // 'any model'
-             cpstr Chains,   // may be several chains "A,B,W";
-                             // "*" means 'any chain' (in model)
-             int   ResNo1,   // starting residue number
-             cpstr Ins1,     // starting residue insertion code;
-                             // "*" means 'any code'
-             int   ResNo2,   // ending residue number.
-                             // ResNo1=ResNo2=ANY_RES means 'any
-                             // residue number' (in chain)
-             cpstr Ins2,     // ending residue insertion code
-                             // "*" means 'any code'
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means 'any
-                             // residue name'
-             cpstr ANames,   // may be several names "CA,CB"; "*"
-                             // means 'any atom' (in residue)
-             cpstr Elements, // may be several element types like
-                             // "H,C,O,CU"; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means 'any
-                             // alternative location'
-             int   selKey    // selection key
-                    )  {
-int       i,j,k,n,m1,m2,c, sk,nsel;
-Boolean   noRes,modelSel,chainSel,resSel,selAND;
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-PCAtom    atom;
-pstr      chain_l;
-pstr      res_l;
-pstr      atom_l;
-pstr      elem_l;
-pstr      altLocs1;
-pstr      aloc_l;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
-
-  modelSel = False;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;             break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-  selAND  = (selKey==SKEY_AND);
-
-  altLocs1 = NULL;
-  if (altLocs)  {
-    if (strchr(altLocs,hetIndicator))  {
-      CreateCopy ( altLocs1,altLocs );
-      DelSpaces  ( altLocs1 );
-      aloc_l = strchr ( altLocs1,hetIndicator );
-      aloc_l[0] = ' ';
-      if (aloc_l[1])  aloc_l[1] = ' ';  // instead of comma
-      else if (aloc_l!=altLocs1)  {
-        aloc_l--;
-        aloc_l[0] = ' ';
-      }
-      DelSpaces  ( altLocs1 );
-      aloc_l = MakeList ( altLocs1 );
-    } else
-      aloc_l = MakeList ( altLocs );
-  } else
-    aloc_l = MakeList ( altLocs );
-
-  chain_l = MakeList ( Chains   );
-  res_l   = MakeList ( RNames   );
-  atom_l  = MakeList ( ANames   );
-  elem_l  = MakeList ( Elements );
-
-  //  noRes==True means no residue restrictions
-  noRes   = (ResNo1==ResNo2) && (ResNo1==ANY_RES) &&
-            (Ins1[0]=='*')   && (Ins2[0]=='*');
-
-  m1      = iModel-1;
-  if (m1>=0)
-    m2 = m1+1;     // will take only this model
-  else  {
-    m1 = 0;        // will take
-    m2 = nModels;  //   all models
-  }
-
-  if (m1>=nModels)  return;
-
-  for (n=0;n<nModels;n++)  {
-    model = Model[n];
-    if (model)  {  // check for safety
-      if ((m1<=n) && (n<m2))  {
-        modelSel = False; // will be True on any selection in the model
-        for (c=0;c<model->nChains;c++)  {
-          chain = model->Chain[c];
-          if (chain)  {  // again check for safety
-            chainSel = False; // will be True on 1st sel-n in the chain
-            if (MatchName(chain_l,chain->chainID))  {
-              // the chain is to be taken
-              i = 0;
-              if (!noRes)  // skip "leading" residues
-                while (i<chain->nResidues)  {
-                  res = chain->Residue[i];
-                  if (res)  {
-                    if ((res->seqNum==ResNo1) &&
-                        MatchName(res_l,res->name) &&
-                        ((Ins1[0]=='*') ||
-                         (!strcmp(res->insCode,Ins1))))
-                      break;
-                    else if (selAND)  {
-                      if (selType==STYPE_ATOM)
-                        res->UnmaskAtoms ( Mask[k] );
-                      else if (selType==STYPE_RESIDUE)
-                        res->RemoveMask ( Mask[k] );
-                    }
-                  }
-                  i++;
-                }
-              while (i<chain->nResidues)  {
-                res = chain->Residue[i];
-                i++;
-                if (res)  {
-                  resSel = False; // will be True on 1st selection
-                                  // in the residue
-                  if (MatchName(res_l,res->name))  {
-                    for (j=0;j<res->nAtoms;j++)  {
-                      atom = res->atom[j];
-                      if (atom)  {
-                        if ((!atom->Ter)                    &&
-                            MatchName(atom_l,atom->name   ) &&
-                            MatchName(elem_l,atom->element) &&
-                            MatchName(aloc_l,atom->altLoc ) &&
-                            ((!altLocs1) || atom->Het))  {
-                          SelectObject ( selType,atom,k,sk,nsel );
-                          resSel   = True;
-                          chainSel = True;
-                          modelSel = True;
-                        } else if (selAND && (selType==STYPE_ATOM))
-                          atom->RemoveMask ( Mask[k] );
-                      }
-                      if (resSel && (selType!=STYPE_ATOM))  break;
-                    }
-                  } else if (selAND && (selType==STYPE_ATOM))
-                      res->UnmaskAtoms ( Mask[k] );
-                  if ((!resSel) && selAND && (selType==STYPE_RESIDUE))
-                    res->RemoveMask ( Mask[k] );
-                  if (chainSel && (selType>STYPE_RESIDUE))  break;
-                  if (!noRes)  {
-                    if ((res->seqNum==ResNo2) &&
-                        ((Ins2[0]=='*') || (!strcmp(res->insCode,Ins2)))
-                       ) break;
-                  }
-                }
-              }
-              if (selAND)  {
-                if (selType==STYPE_ATOM)
-                  while (i<chain->nResidues)  {
-                    res = chain->Residue[i];
-                    if (res)  res->UnmaskAtoms ( Mask[k] );
-                    i++;
-                  }
-                if (selType==STYPE_RESIDUE)
-                  while (i<chain->nResidues)  {
-                    res = chain->Residue[i];
-                    if (res)  res->RemoveMask ( Mask[k] );
-                    i++;
-                  }
-              }
-            } else if (selAND)
-              switch (selType)  {
-                case STYPE_ATOM    : chain->UnmaskAtoms    ( Mask[k] ); break;
-                case STYPE_RESIDUE : chain->UnmaskResidues ( Mask[k] ); break;
-                default            : ;
-              }
-            if ((!chainSel) && selAND && (selType==STYPE_CHAIN))
-              chain->RemoveMask ( Mask[k] );
-            if (modelSel && (selType>STYPE_CHAIN))  break;
-          }
-        }
-      } else if (selAND)
-        switch (selType)  {
-          case STYPE_ATOM    : model->UnmaskAtoms    ( Mask[k] ); break;
-          case STYPE_RESIDUE : model->UnmaskResidues ( Mask[k] ); break;
-          case STYPE_CHAIN   : model->UnmaskChains   ( Mask[k] ); break;
-          default            : ;
-        }
-      if ((!modelSel) && selAND && (selType==STYPE_MODEL))
-        model->RemoveMask ( Mask[k] );
-    }
-  }
-
-  // release dynamic memory
-  if (chain_l)  delete[] chain_l;
-  if (res_l)    delete[] res_l;
-  if (atom_l)   delete[] atom_l;
-  if (elem_l)   delete[] elem_l;
-  if (altLocs1) delete[] altLocs1;
-  if (aloc_l)   delete[] aloc_l;
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-#define SKEY_XAND  100
-
-void CMMDBSelManager::Select (
-             int  selHnd1, // destination, must be obtained from
-                           //   NewSelection()
-             int  selType, // selection type STYPE_XXXXX
-             int  selHnd2, // source, must be obtained from
-                           // NewSelection() and have been used
-                           // for selection
-             int  selKey   // selection key
-                             )  {
-//  SKEY_XOR works only downward the hierarchy!
-int       k1,k2,sk,i,j,l,n,nsel;
-PCAtom    atom;
-PCResidue res;
-PCChain   chain;
-PCModel   model;
-
-  if ((selHnd1<=0) || (selHnd1>nSelections) ||
-      (selHnd2<=0) || (selHnd2>nSelections) || (nAtoms<=0))  return;
-
-  k1 = selHnd1-1;
-  k2 = selHnd2-1;
-  sk = selKey;
-
-  if ((SelType[k1]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))         SelType[k1] = selType;
-  else if (SelType[k1]!=selType)  return;
-
-  if (SelType[k2]==STYPE_UNDEFINED)  return;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k1];i++)
-                      if (Selection[k1][i])
-                          Selection[k1][i]->RemoveMask ( Mask[k1] );
-                    nSelItems[k1] = 0;
-                    sk   = SKEY_OR;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k1]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k1];
-                  break;
-    case SKEY_AND : if (nSelItems[k1]==0)  return;
-                    sk   = SKEY_XAND;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k1];  break;
-    case SKEY_CLR : nsel = nSelItems[k1];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-
-  switch (SelType[k2])  {
-
-    case STYPE_ATOM    :
-        for (i=0;i<nSelItems[k2];i++)  {
-          atom = (PCAtom)Selection[k2][i];
-          if (atom)  {
-            if (!atom->Ter)
-              SelectObject ( selType,atom,k1,sk,nsel );
-          }
-        }
-      break;
-
-    case STYPE_RESIDUE :
-        for (i=0;i<nSelItems[k2];i++)  {
-          res = (PCResidue)Selection[k2][i];
-          if (res)
-            switch (selType)  {
-              case STYPE_ATOM  : for (j=0;j<res->nAtoms;j++)  {
-                                   atom = res->atom[j];
-                                   if (atom)  {
-                                     if (!atom->Ter)
-                                       SelectObject (atom,k1,sk,nsel);
-                                   }
-                                 }
-                               break;
-              case STYPE_RESIDUE : //if (res->chain)
-                                   SelectObject ( res,k1,sk,nsel );
-                               break;
-              case STYPE_CHAIN : if (res->chain)
-                                   SelectObject ( res->chain,k1,
-                                                  sk,nsel );
-                               break;
-              case STYPE_MODEL : if (res->chain)  {
-                                   if (res->chain->model)
-                                     SelectObject ( res->chain->model,
-                                                    k1,sk,nsel );
-                                 }
-              default          : ;
-            }
-        }
-      break;
-
-    case STYPE_CHAIN   :
-        for (i=0;i<nSelItems[k2];i++)  {
-          chain = (PCChain)Selection[k2][i];
-          if (chain)
-            switch (selType)  {
-              case STYPE_ATOM    : for (j=0;j<chain->nResidues;j++)  {
-                                     res = chain->Residue[j];
-                                     if (res)
-                                       for (l=0;l<res->nAtoms;l++)  {
-                                         atom = res->atom[l];
-                                         if (atom)  {
-                                           if (!atom->Ter)
-                                             SelectObject ( atom,k1,
-                                                             sk,nsel );
-                                         }
-                                       }
-                                   }
-                               break;
-              case STYPE_RESIDUE : for (j=0;j<chain->nResidues;j++)  {
-                                     res = chain->Residue[j];
-                                     if (res)
-                                       SelectObject ( res,k1,sk,nsel );
-                                   }
-                               break;
-              case STYPE_CHAIN   : //if (chain->model)
-                                     SelectObject ( chain,k1,sk,nsel );
-                               break;
-              case STYPE_MODEL   : if (chain->model)
-                                     SelectObject ( chain->model,k1,
-                                                    sk,nsel );
-              default            : ;
-            }
-        }
-      break;
-
-    case STYPE_MODEL   :
-        for (i=0;i<nSelItems[k2];i++)  {
-          model = (PCModel)Selection[k2][i];
-          if (model)
-            switch (selType)  {
-              case STYPE_ATOM    :
-                        for (j=0;j<model->nChains;j++)  {
-                          chain = model->Chain[j];
-                          if (chain)
-                            for (l=0;l<chain->nResidues;l++) {
-                              res = chain->Residue[l];
-                              if (res)
-                                for (n=0;n<res->nAtoms;n++)  {
-                                  atom = res->atom[n];
-                                  if (atom)  {
-                                    if (!atom->Ter)
-                                      SelectObject ( atom,k1,sk,nsel );
-                                  }
-                                }
-                            }
-                        }
-                      break;
-              case STYPE_RESIDUE :
-                        for (j=0;j<model->nChains;j++)  {
-                          chain = model->Chain[j];
-                          if (chain)
-                            for (l=0;l<chain->nResidues;l++)  {
-                              res = chain->Residue[j];
-                              if (res)
-                                SelectObject ( res,k1,sk,nsel );
-                            }
-                        }
-                      break;
-              case STYPE_CHAIN   : for (j=0;j<model->nChains;j++)  {
-                                     chain = model->Chain[j];
-                                     if (chain)
-                                       SelectObject (chain,k1,sk,nsel);
-                                   }
-                               break;
-              case STYPE_MODEL   : SelectObject ( model,k1,sk,nsel );
-              default            : ;
-            }
-        }
-      break;
-
-    default : ;
-
-  }
-
-  if (selKey==SKEY_AND)
-    for (i=0;i<nSelItems[k1];i++)
-      if (Selection[k1][i])
-        Selection[k1][i]->XadMask ( Mask[k1] );
-
-  MakeSelIndex ( selHnd1,selType,nsel );
-
-}
-
-void  CMMDBSelManager::SelectProperty (
-                  int  selHnd, // must be obtained from NewSelection()
-                  int propKey, // property key: 0 Solvent 1 Aminoacid
-                  int selType, // selection type STYPE_XXXXX
-                  int  selKey  // selection key
-                )  {
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-int       i,k,selHnd1,sk,nsel, m,c,r;
-Boolean   doSelect;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
-
-  k  = selHnd-1;
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  if (selType!=STYPE_RESIDUE)  {
-    selHnd1 = NewSelection();
-    if ((selKey==SKEY_AND) || (selKey==SKEY_CLR))
-      Select ( selHnd1,STYPE_RESIDUE,selHnd,SKEY_NEW );
-  } else
-    selHnd1 = selHnd;
-
-  k          = selHnd1-1;
-  SelType[k] = STYPE_RESIDUE;
-  sk         = selKey;
-
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    sk   = SKEY_OR;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    sk   = SKEY_XAND;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-  if ((selKey==SKEY_AND) || (selKey==SKEY_CLR))  {
-
-    for (i=0;i<nSelItems[k];i++)  {
-      res = (PCResidue)Selection[k][i];
-      if (res)  {
-        switch (propKey)  {
-          case SELPROP_Solvent    : doSelect = res->isSolvent();
-                                  break;
-          case SELPROP_Aminoacid  : doSelect = res->isAminoacid();
-                                  break;
-          case SELPROP_Nucleotide : doSelect = res->isNucleotide();
-                                  break;
-          case SELPROP_Sugar      : doSelect = res->isSugar();
-                                  break;
-          case SELPROP_ModRes     : doSelect = res->isModRes();
-                                  break;
-          default : doSelect = False;
-        }
-        if (doSelect)  SelectObject ( res,k,sk,nsel );
-      }
-    }
-
-    if (selKey==SKEY_AND)
-      for (i=0;i<nSelItems[k];i++)
-        if (Selection[k][i])
-          Selection[k][i]->XadMask ( Mask[k] );
-
-  } else  {
-
-    for (m=0;m<nModels;m++)  {
-      model = Model[m];
-      if (model)  {
-        for (c=0;c<model->nChains;c++)  {
-          chain = model->Chain[c];
-          if (chain)  {
-            for (r=0;r<chain->nResidues;r++)  {
-              res = chain->Residue[r];
-              if (res)  {
-                switch (propKey)  {
-                  case SELPROP_Solvent    : doSelect = res->isSolvent();
-                                         break;
-                  case SELPROP_Aminoacid  : doSelect = res->isAminoacid();
-                                         break;
-                  case SELPROP_Nucleotide : doSelect = res->isNucleotide();
-                                         break;
-                  case SELPROP_Sugar      : doSelect = res->isSugar();
-                                         break;
-                  case SELPROP_ModRes     : doSelect = res->isModRes();
-                                         break;
-                  default : doSelect = False;
-                }
-                if (doSelect)  SelectObject ( res,k,sk,nsel );
-              }
-            }
-          }
-        }
-      }
-    }
-
-  }
-
-
-  MakeSelIndex ( selHnd1,STYPE_RESIDUE,nsel );
-
-  if (selType!=STYPE_RESIDUE)  {
-    Select ( selHnd,selType,selHnd1,SKEY_NEW );
-    DeleteSelection ( selHnd1 );
-  }
-
-}
-
-
-void CMMDBSelManager::SelectUDD (
-             int    selHnd, // must be obtained from NewSelection()
-             int   selType, // selection type STYPE_XXXXX
-             int UDDhandle, // UDD handle
-             int    selMin, // lower selection boundary
-             int    selMax, // upper selection boundary
-             int    selKey  // selection key
-           )  {
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-PCAtom    atom;
-int       i,k,sk,nsel,iudd, n,c,r,a;
-Boolean   selAND;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  switch (selType)  {
-    case STYPE_ATOM    : if ((UDDhandle & UDRF_ATOM)==0)    return;
-                      break;
-    case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
-                      break;
-    case STYPE_CHAIN   : if ((UDDhandle & UDRF_CHAIN)==0)   return;
-                      break;
-    case STYPE_MODEL   : if ((UDDhandle & UDRF_MODEL)==0)   return;
-                      break;
-    default            : return;
-  }
-
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-  selAND = (selKey==SKEY_AND);
-
-
-  for (n=0;n<nModels;n++)  {
-
-    model = Model[n];
-    if (model)  {  // check for safety
-
-      if (selType==STYPE_MODEL)  {
-
-        model->getUDData ( UDDhandle,iudd );
-        if ((selMin<=iudd) && (iudd<=selMax))
-          SelectObject ( model,k,sk,nsel );
-        else if (selAND)
-          model->RemoveMask ( Mask[k] );
-
-      } else  {
-
-        for (c=0;c<model->nChains;c++)  {
-
-          chain = model->Chain[c];
-          if (chain)  {   // again check for safety
-
-            if (selType==STYPE_CHAIN)  {
-              chain->getUDData ( UDDhandle,iudd );
-              if ((selMin<=iudd) && (iudd<=selMax))
-                SelectObject ( chain,k,sk,nsel );
-              else if (selAND)
-                chain->RemoveMask ( Mask[k] );
-
-            } else  {
-
-              for (r=0;r<chain->nResidues;r++)  {
-
-                res = chain->Residue[r];
-                if (res)  {
-
-                  if (selType==STYPE_RESIDUE)  {
-                    res->getUDData ( UDDhandle,iudd );
-                    if ((selMin<=iudd) && (iudd<=selMax))
-                      SelectObject ( res,k,sk,nsel );
-                    else if (selAND)
-                      res->RemoveMask ( Mask[k] );
-
-                  } else  {
-
-                    for (a=0;a<res->nAtoms;a++)  {
-                      atom = res->atom[a];
-                      if (atom)  {
-                        if (!atom->Ter)  {
-                          atom->getUDData ( UDDhandle,iudd );
-                          if ((selMin<=iudd) && (iudd<=selMax))
-                            SelectObject ( atom,k,sk,nsel );
-                          else if (selAND)
-                            atom->RemoveMask ( Mask[k] );
-                        }
-                      }
-
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectUDD (
-             int      selHnd, // must be obtained from NewSelection()
-             int     selType, // selection type STYPE_XXXXX
-             int   UDDhandle, // UDD handle
-             realtype selMin, // lower selection boundary
-             realtype selMax, // upper selection boundary
-             int      selKey  // selection key
-           )  {
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-PCAtom    atom;
-realtype  rudd;
-int       i,k,sk,nsel, n,c,r,a;
-Boolean   selAND;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  switch (selType)  {
-    case STYPE_ATOM    : if ((UDDhandle & UDRF_ATOM)==0)    return;
-                      break;
-    case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
-                      break;
-    case STYPE_CHAIN   : if ((UDDhandle & UDRF_CHAIN)==0)   return;
-                      break;
-    case STYPE_MODEL   : if ((UDDhandle & UDRF_MODEL)==0)   return;
-                      break;
-    default            : return;
-  }
-
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-  selAND = (selKey==SKEY_AND);
-
-
-  for (n=0;n<nModels;n++)  {
-
-    model = Model[n];
-    if (model)  {  // check for safety
-
-      if (selType==STYPE_MODEL)  {
-
-        model->getUDData ( UDDhandle,rudd );
-        if ((selMin<=rudd) && (rudd<=selMax))
-          SelectObject ( model,k,sk,nsel );
-        else if (selAND)
-          model->RemoveMask ( Mask[k] );
-
-      } else  {
-
-        for (c=0;c<model->nChains;c++)  {
-
-          chain = model->Chain[c];
-          if (chain)  {   // again check for safety
-
-            if (selType==STYPE_CHAIN)  {
-              chain->getUDData ( UDDhandle,rudd );
-              if ((selMin<=rudd) && (rudd<=selMax))
-                SelectObject ( chain,k,sk,nsel );
-              else if (selAND)
-                chain->RemoveMask ( Mask[k] );
-
-            } else  {
-
-              for (r=0;r<chain->nResidues;r++)  {
-
-                res = chain->Residue[r];
-                if (res)  {
-
-                  if (selType==STYPE_RESIDUE)  {
-                    res->getUDData ( UDDhandle,rudd );
-                    if ((selMin<=rudd) && (rudd<=selMax))
-                      SelectObject ( res,k,sk,nsel );
-                    else if (selAND)
-                      res->RemoveMask ( Mask[k] );
-
-                  } else  {
-
-                    for (a=0;a<res->nAtoms;a++)  {
-                      atom = res->atom[a];
-                      if (atom)  {
-                        if (!atom->Ter)  {
-                          atom->getUDData ( UDDhandle,rudd );
-                          if ((selMin<=rudd) && (rudd<=selMax))
-                            SelectObject ( atom,k,sk,nsel );
-                          else if (selAND)
-                            atom->RemoveMask ( Mask[k] );
-                        }
-                      }
-
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-Boolean selSUDD ( cpstr sudd, cpstr selStr, int cmpRule, int ssLen )  {
-  if (!sudd)  return False;
-  switch (cmpRule)  {
-    case UDSCR_LT        : return (strcmp(sudd,selStr)<0);
-    case UDSCR_LE        : return (strcmp(sudd,selStr)<=0);
-    case UDSCR_EQ        : return (strcmp(sudd,selStr)==0);
-    case UDSCR_NE        : return (strcmp(sudd,selStr)!=0);
-    case UDSCR_GE        : return (strcmp(sudd,selStr)>=0);
-    case UDSCR_GT        : return (strcmp(sudd,selStr)>=0);
-    case UDSCR_LTcase    : return (strcasecmp(sudd,selStr)<0);
-    case UDSCR_LEcase    : return (strcasecmp(sudd,selStr)<=0);
-    case UDSCR_EQcase    : return (strcasecmp(sudd,selStr)==0);
-    case UDSCR_NEcase    : return (strcasecmp(sudd,selStr)!=0);
-    case UDSCR_GEcase    : return (strcasecmp(sudd,selStr)>=0);
-    case UDSCR_GTcase    : return (strcasecmp(sudd,selStr)>=0);
-    case UDSCR_LTn       : return (strncmp(sudd,selStr,ssLen)<0);
-    case UDSCR_LEn       : return (strncmp(sudd,selStr,ssLen)<=0);
-    case UDSCR_EQn       : return (strncmp(sudd,selStr,ssLen)==0);
-    case UDSCR_NEn       : return (strncmp(sudd,selStr,ssLen)!=0);
-    case UDSCR_GEn       : return (strncmp(sudd,selStr,ssLen)>=0);
-    case UDSCR_GTn       : return (strncmp(sudd,selStr,ssLen)>=0);
-    case UDSCR_LTncase   : return (strncasecmp(sudd,selStr,ssLen)<0);
-    case UDSCR_LEncase   : return (strncasecmp(sudd,selStr,ssLen)<=0);
-    case UDSCR_EQncase   : return (strncasecmp(sudd,selStr,ssLen)==0);
-    case UDSCR_NEncase   : return (strncasecmp(sudd,selStr,ssLen)!=0);
-    case UDSCR_GEncase   : return (strncasecmp(sudd,selStr,ssLen)>=0);
-    case UDSCR_GTncase   : return (strncasecmp(sudd,selStr,ssLen)>=0);
-    case UDSCR_Substr    : return (strstr(sudd,selStr)!=NULL);
-    case UDSCR_NoSubstr  : return (strstr(sudd,selStr)==NULL);
-    case UDSCR_Substr1   : return (strstr(selStr,sudd)!=NULL);
-    case UDSCR_NoSubstr1 : return (strstr(selStr,sudd)==NULL);
-    default              : return False;
-  }
-}
-
-
-void CMMDBSelManager::SelectUDD (
-             int   selHnd,    // must be obtained from NewSelection()
-             int   selType,   // selection type STYPE_XXXXX
-             int   UDDhandle, // UDD handle
-             cpstr selStr,    // selection string
-             int   cmpRule,   // comparison rule
-             int   selKey     // selection key
-           )  {
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-PCAtom    atom;
-int       i,k,sk,nsel,ssLen, n,c,r,a;
-Boolean   selAND;
-
-  k  = selHnd-1;
-  sk = selKey;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return;
-
-  switch (selType)  {
-    case STYPE_ATOM    : if ((UDDhandle & UDRF_ATOM)==0)    return;
-                      break;
-    case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
-                      break;
-    case STYPE_CHAIN   : if ((UDDhandle & UDRF_CHAIN)==0)   return;
-                      break;
-    case STYPE_MODEL   : if ((UDDhandle & UDRF_MODEL)==0)   return;
-                      break;
-    default            : return;
-  }
-
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : if (nSelItems[k]==0)  return;
-                    nsel = 0;
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    if (nsel<=0)  return;
-                  break;
-    default       : return;
-  }
-
-  selAND = (selKey==SKEY_AND);
-  ssLen = strlen ( selStr );
-
-  for (n=0;n<nModels;n++)  {
-
-    model = Model[n];
-    if (model)  {  // check for safety
-
-      if (selType==STYPE_MODEL)  {
-
-        if (selSUDD(model->getUDData(UDDhandle),selStr,
-                                          cmpRule,ssLen))
-          SelectObject ( model,k,sk,nsel );
-        else if (selAND)
-          model->RemoveMask ( Mask[k] );
-
-      } else  {
-
-        for (c=0;c<model->nChains;c++)  {
-
-          chain = model->Chain[c];
-          if (chain)  {   // again check for safety
-
-            if (selType==STYPE_CHAIN)  {
-              if (selSUDD(chain->getUDData(UDDhandle),selStr,
-                                                cmpRule,ssLen))
-                SelectObject ( chain,k,sk,nsel );
-              else if (selAND)
-                chain->RemoveMask ( Mask[k] );
-
-            } else  {
-
-              for (r=0;r<chain->nResidues;r++)  {
-
-                res = chain->Residue[r];
-                if (res)  {
-
-                  if (selType==STYPE_RESIDUE)  {
-                    if (selSUDD(res->getUDData(UDDhandle),selStr,
-                                                    cmpRule,ssLen))
-                      SelectObject ( res,k,sk,nsel );
-                    else if (selAND)
-                      res->RemoveMask ( Mask[k] );
-
-                  } else  {
-
-                    for (a=0;a<res->nAtoms;a++)  {
-                      atom = res->atom[a];
-                      if (atom)  {
-                        if (!atom->Ter)  {
-                          if (selSUDD(atom->getUDData(UDDhandle),selStr,
-                                                           cmpRule,ssLen))
-                            SelectObject ( atom,k,sk,nsel );
-                          else if (selAND)
-                            atom->RemoveMask ( Mask[k] );
-                        }
-                      }
-
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectSphere (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             realtype  x, // x-coordinate of the sphere's center
-             realtype  y, // y-coordinate of the sphere's center
-             realtype  z, // z-coordinate of the sphere's center
-             realtype  r, // radius of the sphere
-             int  selKey  // selection key
-           )  {
-//  Selecting a sphere
-int       i,k, nat,sk,nsel, im,ic,ir;
-realtype  dx,dy,dz, r2;
-Boolean   ASel, resSel,chainSel,modelSel,selAND;
-PPCAtom   A;
-PCAtom    atom;
-PCResidue res;
-PCChain   chain;
-PCModel   model;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0))  return;
-
-  k   = selHnd-1;
-  sk  = selKey;
-  A   = Atom;
-  nat = nAtoms;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    default       : return;
-  }
-
-  selAND = selType==SKEY_AND;
-
-  if ((nat<=0) || (!A))  return;
-
-  r2 = r*r;
-
-  if (selType==STYPE_ATOM)  {
-
-    for (i=0;i<nat;i++)
-      if (A[i])  {
-        ASel = sk!=SKEY_AND;
-        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-          dx = fabs(A[i]->x-x);
-          if (dx<=r)  {
-            dy = fabs(A[i]->y-y);
-            if (dy<=r)  {
-              dz = fabs(A[i]->z-z);
-              if (dz<=r)  {
-                if (dx*dx+dy*dy+dz*dz<=r2)  {
-                  ASel = True;
-                  SelectAtom ( A[i],k,sk,nsel );
-                }
-              }
-            }
-          }
-        }
-        if (!ASel)  A[i]->RemoveMask ( Mask[k] );
-      }
-
-  } else  {
-
-    for (im=0;im<nModels;im++)  {
-      model = Model[im];
-      if (model)  {
-        modelSel = False;
-        for (ic=0;ic<model->nChains;ic++)  {
-          chain = model->Chain[ic];
-          if (chain)  {
-            chainSel = False;
-            for (ir=0;ir<chain->nResidues;ir++)  {
-              res = chain->Residue[ir];
-              if (res)  {
-                resSel = False;
-                for (i=0;i<res->nAtoms;i++)  {
-                  atom = res->atom[i];
-                  if (atom) {
-                    ASel = False;
-                    if ((!atom->Ter) &&
-                        (atom->WhatIsSet & ASET_Coordinates))  {
-                      dx = fabs(atom->x-x);
-                      if (dx<=r)  {
-                        dy = fabs(atom->y-y);
-                        if (dy<=r)  {
-                          dz = fabs(atom->z-z);
-                          if (dz<=r)  {
-                            if (dx*dx+dy*dy+dz*dz<=r2)  {
-                              SelectObject ( selType,atom,k,sk,nsel );
-                              ASel     = True;
-                              resSel   = True;
-                              chainSel = True;
-                              modelSel = True;
-                            }
-                          }
-                        }
-                      }
-                    }
-                    if (ASel)  break;  // selType>=STYPE_RESIDUE
-                  }
-                }
-                if ((!resSel) && selAND && (selType==STYPE_RESIDUE))
-                  res->RemoveMask ( Mask[k] );
-                if (chainSel && (selType>STYPE_RESIDUE))  break;
-              }
-            }
-            if ((!chainSel) && selAND && (selType==STYPE_CHAIN))
-              chain->RemoveMask ( Mask[k] );
-            if (modelSel && (selType>STYPE_CHAIN))  break;
-          }
-        }
-        if ((!modelSel) && selAND && (selType==STYPE_MODEL))
-          model->RemoveMask ( Mask[k] );
-      }
-    }
-
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectCylinder (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             realtype x1, // x-coordinate of the cylinder axis' 1st end
-             realtype y1, // y-coordinate of the cylinder axis' 1st end
-             realtype z1, // z-coordinate of the cylinder axis' 1st end
-             realtype x2, // x-coordinate of the cylinder axis' 2nd end
-             realtype y2, // y-coordinate of the cylinder axis' 2nd end
-             realtype z2, // z-coordinate of the cylinder axis' 2nd end
-             realtype  r, // radius of the cylinder
-             int  selKey  // selection key
-           )  {
-//
-//  Selecting a cylinder
-//
-//  Method : given a line running through (x1,y1,z1) to (x2,y2,z2) on,
-//  a point (x,y,z) is then projected on it at distance
-//
-//              c1 = (c^2-a^2+b^2)/(2c),
-//
-//  from (x1,y1,z1), where
-//      'a' is the distance between (x,y,z) and (x2,y2,z2)
-//      'b' is the distance between (x,y,z) and (x1,y1,z1)
-//      'c' is the distance between (x1,y1,z1) and (x2,y2,z2).
-//  The distance between point (x,y,z) and line is determined as
-//
-//              h^2 = b^2 - c1^2
-//
-//  If c1>=0 and c1<=c and h^2<=r^2  then point (x,y,z) is inside
-//  a cylinder of radius 'r' with axis running from point
-//  (x1,y1,z1) to (x2,y2,z2).
-//
-int       i,k, nat,sk,nsel, im,ic,ir;
-realtype  dx,dy,dz, c,dc,c1,c2, a2,b2, r2;
-Boolean   resSel,chainSel,modelSel,selAND;
-PPCAtom   A;
-PCAtom    atom;
-PCResidue res;
-PCChain   chain;
-PCModel   model;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0))  return;
-
-  dx = x1-x2;
-  dy = y1-y2;
-  dz = z1-z2;
-  c2 = dx*dx + dy*dy + dz*dz;
-  if (c2<=0.0)  return;
-  c  = sqrt(c2);
-  dc = 2.0*c;
-  r2 = r*r;
-
-  k   = selHnd-1;
-  sk  = selKey;
-  A   = Atom;
-  nat = nAtoms;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    default       : return;
-  }
-
-  selAND = selType==SKEY_AND;
-
-  if ((nat<=0) || (!A))  return;
-
-  if (selType==STYPE_ATOM)  {
-
-    for (i=0;i<nat;i++)
-      if (A[i])  {
-        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-          dx = fabs(A[i]->x-x1);
-          dy = fabs(A[i]->y-y1);
-          dz = fabs(A[i]->z-z1);
-          a2 = dx*dx + dy*dy + dz*dz;
-          dx = fabs(A[i]->x-x2);
-          dy = fabs(A[i]->y-y2);
-          dz = fabs(A[i]->z-z2);
-          b2 = dx*dx + dy*dy + dz*dz;
-          c1 = (c2-a2+b2)/dc;
-          if ((0.0<=c1) && (c1<=c) && (b2-c1*c1<=r2))
-            SelectAtom ( A[i],k,sk,nsel );
-          else if (sk==SKEY_AND)
-            A[i]->RemoveMask ( Mask[k] );
-        }
-      }
-
-  } else  {
-
-    for (im=0;im<nModels;im++)  {
-      model = Model[im];
-      if (model)  {
-        modelSel = False;
-        for (ic=0;ic<model->nChains;ic++)  {
-          chain = model->Chain[ic];
-          if (chain)  {
-            chainSel = False;
-            for (ir=0;ir<chain->nResidues;ir++)  {
-              res = chain->Residue[ir];
-              if (res)  {
-                resSel = False;
-                for (i=0;i<res->nAtoms;i++)  {
-                  atom = res->atom[i];
-                  if (atom) {
-                    if ((!atom->Ter) &&
-                        (atom->WhatIsSet & ASET_Coordinates))  {
-                      dx = fabs(atom->x-x1);
-                      dy = fabs(atom->y-y1);
-                      dz = fabs(atom->z-z1);
-                      a2 = dx*dx + dy*dy + dz*dz;
-                      dx = fabs(atom->x-x2);
-                      dy = fabs(atom->y-y2);
-                      dz = fabs(atom->z-z2);
-                      b2 = dx*dx + dy*dy + dz*dz;
-                      c1 = (c2-a2+b2)/dc;
-                      if ((0.0<=c1) && (c1<=c) && (b2-c1*c1<=r2))  {
-                        SelectObject ( selType,atom,k,sk,nsel );
-                        resSel   = True;
-                        chainSel = True;
-                        modelSel = True;
-                        break;  // selType>=STYPE_RESIDUE
-                      }
-                    }
-                  }
-                }
-                if ((!resSel) && selAND && (selType==STYPE_RESIDUE))
-                  res->RemoveMask ( Mask[k] );
-                if (chainSel && (selType>STYPE_RESIDUE))  break;
-              }
-            }
-            if ((!chainSel) && selAND && (selType==STYPE_CHAIN))
-              chain->RemoveMask ( Mask[k] );
-            if (modelSel && (selType>STYPE_CHAIN))  break;
-          }
-        }
-        if ((!modelSel) && selAND && (selType==STYPE_MODEL))
-          model->RemoveMask ( Mask[k] );
-      }
-    }
-
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectSlab (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             realtype  a, // a-parameter of the plane  ax+by+cz=d
-             realtype  b, // b-parameter of the plane  ax+by+cz=d
-             realtype  c, // c-parameter of the plane  ax+by+cz=d
-             realtype  d, // d-parameter of the plane  ax+by+cz=d
-             realtype  r, // distance to the plane
-             int  selKey  // selection key
-           )  {
-//
-//  Selecting all atoms on a given distance from a plane
-//
-//  Method : the distance between a point (x0,y0,z0) and a plane
-//  defined by equation
-//
-//              a*x + b*y + c*z = d
-//
-//  is found as
-//
-//              h = (d-a*x0-b*y0-c*z0)/sqrt(a^2+b^2+c^2)
-//
-//  If |h|<d then point (x0,y0,z0) belongs to the slab.
-//
-int       i,k, nat,sk,nsel, im,ic,ir;
-realtype  v,h;
-Boolean   resSel,chainSel,modelSel,selAND;
-PPCAtom   A;
-PCAtom    atom;
-PCResidue res;
-PCChain   chain;
-PCModel   model;
-
-  if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0))  return;
-
-  v   = sqrt(a*a + b*b + c*c);
-  if (v<=0.0)  return;
-
-  k   = selHnd-1;
-  sk  = selKey;
-  A   = Atom;
-  nat = nAtoms;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    default       : return;
-  }
-
-  selAND = selType==SKEY_AND;
-
-  if ((nat<=0) || (!A))  return;
-
-  if (selType==STYPE_ATOM)  {
-
-    for (i=0;i<nat;i++)
-      if (A[i])  {
-        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
-          h = fabs(d-a*A[i]->x-b*A[i]->y-c*A[i]->z)/v;
-          if (h<=r)
-            SelectAtom ( A[i],k,sk,nsel );
-          else if (sk==SKEY_AND)
-            A[i]->RemoveMask ( Mask[k] );
-        }
-      }
-
-  } else  {
-
-    for (im=0;im<nModels;im++)  {
-      model = Model[im];
-      if (model)  {
-        modelSel = False;
-        for (ic=0;ic<model->nChains;ic++)  {
-          chain = model->Chain[ic];
-          if (chain)  {
-            chainSel = False;
-            for (ir=0;ir<chain->nResidues;ir++)  {
-              res = chain->Residue[ir];
-              if (res)  {
-                resSel = False;
-                for (i=0;i<res->nAtoms;i++)  {
-                  atom = res->atom[i];
-                  if (atom) {
-                    if ((!atom->Ter) &&
-                        (atom->WhatIsSet & ASET_Coordinates))  {
-                      h = fabs(d-a*A[i]->x-b*A[i]->y-c*A[i]->z)/v;
-                      if (h<=r)  {
-                        SelectObject ( selType,atom,k,sk,nsel );
-                        resSel   = True;
-                        chainSel = True;
-                        modelSel = True;
-                        break;  // selType>=STYPE_RESIDUE
-                      }
-                    }
-                  }
-                }
-                if ((!resSel) && selAND && (selType==STYPE_RESIDUE))
-                  res->RemoveMask ( Mask[k] );
-                if (chainSel && (selType>STYPE_RESIDUE))  break;
-              }
-            }
-            if ((!chainSel) && selAND && (selType==STYPE_CHAIN))
-              chain->RemoveMask ( Mask[k] );
-            if (modelSel && (selType>STYPE_CHAIN))  break;
-          }
-        }
-        if ((!modelSel) && selAND && (selType==STYPE_MODEL))
-          model->RemoveMask ( Mask[k] );
-      }
-    }
-
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-void CMMDBSelManager::SelectNeighbours (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             PPCAtom  sA, // array of already selected atoms
-             int    alen, // length of A
-             realtype d1, // minimal distance to already selected atoms
-             realtype d2, // maximal distance to already selected atoms
-             int  selKey  // selection key
-                                       )  {
-// Selecting all atoms on a given distance from already selected
-int       i,j,k, dn, nx,ny,nz, nat,sk,nsel, im,ic,ir;
-int       ix1,ix2,ix, iy1,iy2,iy, iz1,iz2,iz;
-realtype  x,y,z, dx,dy,dz, dst, d12,d22;
-PPCAtom   A;
-PCBrick   B;
-PCAtom    atom;
-PCResidue res;
-PCChain   chain;
-PCModel   model;
-Boolean   ASel,resSel,chainSel,modelSel,selAND;
-
-  if ((selHnd<=0) || (selHnd>nSelections) ||
-      (d2<=0.0)   || (d2<d1))  return;
-
-  k   = selHnd-1;
-  sk  = selKey;
-  A   = Atom;
-  nat = nAtoms;
-  d12 = d1*d1;
-  d22 = d2*d2;
-
-  if ((SelType[k]==STYPE_UNDEFINED) ||
-      (selKey==SKEY_NEW))        SelType[k] = selType;
-  else if (SelType[k]!=selType)  return;
-
-  if ((alen<1) || (!sA))  {
-    if ((selKey==SKEY_NEW) || (selKey==SKEY_AND))  {
-      for (i=0;i<nSelItems[k];i++)
-        if (Selection[k][i])
-          Selection[k][i]->RemoveMask ( Mask[k] );
-      nSelItems[k] = 0;
-    }
-    return;
-  }
-
-  // if something goes wrong, sk should be assigned SKEY_OR if
-  // selKey is set to SKEY_NEW or SKEY_OR below
-  switch (selKey)  {
-    case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
-                      if (Selection[k][i])
-                          Selection[k][i]->RemoveMask ( Mask[k] );
-                    nSelItems[k] = 0;
-                    nsel = 0;
-                  break;
-    case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
-                    nsel = nSelItems[k];
-                  break;
-    case SKEY_AND : nsel = 0;
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    case SKEY_XOR : nsel = nSelItems[k];
-                  break;
-    case SKEY_CLR : nsel = nSelItems[k];
-                    nat  = nSelItems[k];
-                    A    = (PPCAtom)Selection[k];
-                  break;
-    default       : return;
-  }
-
-  selAND = (sk==SKEY_AND);
-
-  if ((nat<=0) || (!A))  return;
-
-  MakeBricks ( sA,alen,d2*1.5 );
-  dn = mround(d2/brick_size)+1;
-
-  if (Brick && (selType==STYPE_ATOM))  {
-
-    for (i=0;i<nat;i++)
-      if (A[i])  {
-        if (!A[i]->Ter)  {
-          ASel = False;
-          GetBrickCoor ( A[i],nx,ny,nz );
-          if (nx<0) nx++;
-          ix1 = IMax ( 0,nx-dn );
-          iy1 = IMax ( 0,ny-dn );
-          iz1 = IMax ( 0,nz-dn );
-          ix2 = IMin ( nbrick_x,nx+dn+1 );
-          iy2 = IMin ( nbrick_y,ny+dn+1 );
-          iz2 = IMin ( nbrick_z,nz+dn+1 );
-          x   = A[i]->x;
-          y   = A[i]->y;
-          z   = A[i]->z;
-          for (ix=ix1;(ix<ix2) && (!ASel);ix++)
-            if (Brick[ix])
-              for (iy=iy1;(iy<iy2) && (!ASel);iy++)
-                if (Brick[ix][iy])
-                  for (iz=iz1;(iz<iz2) && (!ASel);iz++)  {
-                    B = Brick[ix][iy][iz];
-                    if (B)
-                      for (j=0;(j<B->nAtoms) && (!ASel);j++)
-                        if (B->Atom[j]!=A[i])  {
-                          dx = fabs(x-B->Atom[j]->x);
-                          if (dx<=d2)  {
-                            dy = fabs(y-B->Atom[j]->y);
-                            if (dy<=d2)  {
-                              dz = fabs(z-B->Atom[j]->z);
-                              if (dz<=d2)  {
-                                dst = dx*dx+dy*dy+dz*dz;
-                                if ((dst>=d12) && (dst<=d22))  {
-                                  ASel = True;
-                                  SelectAtom ( A[i],k,sk,nsel );
-                                }
-                              }
-                            }
-                          }
-                        }
-                  }
-          if ((!ASel) && selAND)  A[i]->RemoveMask ( Mask[k] );
-        }
-      }
-
-  } else if (Brick)  {
-
-    for (im=0;im<nModels;im++)  {
-      model = Model[im];
-      if (model)  {
-        modelSel = False;
-        for (ic=0;ic<model->nChains;ic++)  {
-          chain = model->Chain[ic];
-          if (chain)  {
-            chainSel = False;
-            for (ir=0;ir<chain->nResidues;ir++)  {
-              res = chain->Residue[ir];
-              if (res)  {
-                resSel = False;
-                for (i=0;(i<res->nAtoms) && (!resSel);i++)  {
-                  atom = res->atom[i];
-                  if (atom) {
-                    if ((!atom->Ter) &&
-                        (atom->WhatIsSet & ASET_Coordinates))  {
-                      GetBrickCoor ( atom,nx,ny,nz );
-                      if (nx<0) nx++;
-                      ix1 = IMax ( 0,nx-dn );
-                      iy1 = IMax ( 0,ny-dn );
-                      iz1 = IMax ( 0,nz-dn );
-                      ix2 = IMin ( nbrick_x,nx+dn+1 );
-                      iy2 = IMin ( nbrick_y,ny+dn+1 );
-                      iz2 = IMin ( nbrick_z,nz+dn+1 );
-                      x   = atom->x;
-                      y   = atom->y;
-                      z   = atom->z;
-                      for (ix=ix1;(ix<ix2) && (!resSel);ix++)
-                        if (Brick[ix])
-                          for (iy=iy1;(iy<iy2) && (!resSel);iy++)
-                            if (Brick[ix][iy])
-                              for (iz=iz1;(iz<iz2) && (!resSel);iz++) {
-                                B = Brick[ix][iy][iz];
-                                if (B)
-                                  for (j=0;(j<B->nAtoms) &&
-                                           (!resSel);j++)
-                                    if (B->Atom[j]!=atom)  {
-                                      dx = fabs(x-B->Atom[j]->x);
-                                      if (dx<=d2)  {
-                                        dy = fabs(y-B->Atom[j]->y);
-                                        if (dy<=d2)  {
-                                          dz = fabs(z-B->Atom[j]->z);
-                                          if (dz<=d2)  {
-                                            dst = dx*dx+dy*dy+dz*dz;
-                                            if ((dst>=d12) &&
-                                                (dst<=d22))  {
-                                              SelectObject ( selType,
-                                                      atom,k,sk,nsel );
-                                              resSel   = True;
-                                              chainSel = True;
-                                              modelSel = True;
-                                            }
-                                          }
-                                        }
-                                      }
-                                    }
-                              }
-
-                    }
-                  }
-                }
-                if ((!resSel) && selAND && (selType==STYPE_RESIDUE))
-                  res->RemoveMask ( Mask[k] );
-                if (chainSel && (selType>STYPE_RESIDUE))  break;
-              }
-            }
-            if ((!chainSel) && selAND && (selType==STYPE_CHAIN))
-              chain->RemoveMask ( Mask[k] );
-            if (modelSel && (selType>STYPE_CHAIN))  break;
-          }
-        }
-        if ((!modelSel) && selAND && (selType==STYPE_MODEL))
-          model->RemoveMask ( Mask[k] );
-      }
-    }
-
-  }
-
-  MakeSelIndex ( selHnd,selType,nsel );
-
-}
-
-
-
-int TakeChainID ( pstr & p, pstr chainID )  {
-int RC,k;
-  chainID[0] = char(0);
-  if (*p)  {
-    RC = 0;
-    if (*p==':')  {
-      // starts with colon <=> empty chain ID
-      chainID[0] = char(0);
-      p++;  // advance to residue number
-    } else if (p[1]==':')  {
-      // second symbol is colon <=> regular chain ID
-      chainID[0] = *p;
-      chainID[1] = char(0);
-      p++;
-      p++;  // advance to residue number
-    } else if (*p=='\'')  {
-      // starts with a strip <=> assume empty chain ID
-      chainID[0] = char(0);
-      p++;
-      if (*p=='\'')  {
-        // closing strip must be followed by colon
-        p++;
-        if (*p!=':')  RC = -1;
-      } else  {
-        // no concluding strip <=> could be a strip chain ID,
-        // although this must be captured by 2nd "if"
-        chainID[0] = '\'';
-        chainID[1] = char(0);
-        // assume that residue number is following the strip
-      }
-    } else if ((int(*p)>=int('0')) && (int(*p)<=int('9')))  {
-      // a digit without following semicolon looks very much
-      // like residue number with unspecified empty chain ID
-      chainID[0] = char(0);
-      // assume that p already points on residue number
-    } else  {
-      // assume a long chain ID
-      k = 0;
-      while (*p && (*p!=':') && (k<(int)sizeof(ChainID)-1)) {
-        chainID[k++] = *p;
-        p++;
-      }
-      if (*p==':')  {
-        chainID[k] = char(0);
-      } else  {
-        // a mistake
-        chainID[0] = char(0);
-        RC = -1;
-      }
-    }
-    while (*p==' ')  p++;
-  } else
-    RC = 1;
-  return RC;
-}
-
-int TakeResID( pstr & p, int & seqNum, pstr inscode )  {
-char N[100];
-int  i,RC;
-pstr endptr;
-  RC = 1;
-  inscode[0] = '*';
-  inscode[1] = char(0);
-  seqNum     = ANY_RES;
-  if (((*p) &&
-       (int(*p)>=int('0')) && (int(*p)<=int('9'))) || (*p=='-'))  {
-    N[0] = *p;
-    p++;
-    i = 1;
-    while ((*p) && (int(*p)>=int('0')) && (int(*p)<=int('9')))  {
-      N[i++] = *p;
-      p++;
-    }
-    N[i] = char(0);
-    seqNum = mround(strtod(N,&endptr));
-    if ((seqNum==0) && (endptr==N))
-      RC = -1;
-    else  {
-      RC = 0;
-      if ((*p) && (*p!='-') && (*p!=',') && (*p!=' '))  {
-        inscode[0] = *p;
-        inscode[1] = char(0);
-        p++;
-      } else
-        inscode[0] = char(0);
-      if ((*p=='-') || (*p==','))  p++;
-    }
-    while (*p==' ')  p++;
-  }
-  return RC;
-}
-
-
-int  CMMDBSelManager::SelectDomain ( int selHnd , cpstr domainRange,
-                                     int selType, int   selKey,
-                                     int modelNo )  {
-// domainRange is of the following format:
-//    "*", "(all)"            - take all file
-//    "-"                     - take chain without chain ID
-//    "a:Ni-Mj,b:Kp-Lq,..."   - take chain a residue number N
-//                              insertion code i to residue number M
-//                              insertion code j plus chain b
-//                              residue number K insertion code p to
-//                              residue number L insertion code q and
-//                              so on.
-//    "a:,b:..."              - take whole chains a and b and so on
-//    "a:,b:Kp-Lq,..."        - any combination of the above.
-ChainID chainID;
-InsCode insCode1,insCode2;
-pstr    S,p;
-int     seqNum1,seqNum2,rc,selKey1;
-
-  if ((selHnd<=0) || (selHnd>nSelections))  return 1;
-
-  // leave only required residues
-
-  rc = 1;
-  if (!domainRange)  rc = 0;
-  else if ((!domainRange[0]) || (domainRange[0]=='*'))  rc = 0;
-  else if (!strcasecmp(domainRange,"(all)"))  rc = 0;
-  if (!rc)  {
-    // select all
-    Select ( selHnd,selType,modelNo,"*",ANY_RES,"*",ANY_RES,"*",
-                                    "*","*","*","*",selKey );
-    return 0;
-  }
-  if (!strcasecmp(domainRange,"-"))  {
-    // select chain without chain ID
-    Select ( selHnd,selType,modelNo,"",ANY_RES,"*",ANY_RES,"*",
-                                    "*","*","*","*",selKey );
-    return 0;
-  }
-
-  S = new char[strlen(domainRange)+10];
-  strcpy    ( S,domainRange );
-  DelSpaces ( S );
-//  UpperCase ( S );
-
-  p  = S;
-  rc = 0;
-
-  selKey1 = selKey;
-
-  while ((*p) && (!rc))  {
-
-    if (TakeChainID(p,chainID)<0)             rc = -1;
-    else if (TakeResID(p,seqNum1,insCode1)<0) rc = -2;
-    else if (TakeResID(p,seqNum2,insCode2)<0) rc = -3;
-    else  {
-      Select ( selHnd,selType,modelNo,chainID,
-               seqNum1,insCode1,seqNum2,insCode2,
-               "*","*","*","*",selKey1 );
-      if (*p==',')  p++;
-      if (selKey1==SKEY_NEW)  selKey1 = SKEY_OR;
-    }
-
-  }
-
-  delete[] S;
-
-  return rc;
-
-}
-
-
-int CMMDBSelManager::GetSelLength ( int selHnd )  {
-  if ((selHnd>0) && (selHnd<=nSelections))
-        return nSelItems[selHnd-1];
-  else  return 0;
-}
-
-
-void CMMDBSelManager::GetSelIndex ( int       selHnd,
-                                    PPCAtom & SelAtom,
-                                    int &     nSelAtoms )  {
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    if (SelType[selHnd-1]!=STYPE_ATOM)  {
-      SelAtom   = NULL;
-      nSelAtoms = 0;
-    } else  {
-      SelAtom   = (PPCAtom)Selection[selHnd-1];
-      nSelAtoms = nSelItems[selHnd-1];
-    }
-  } else  {
-    SelAtom   = NULL;
-    nSelAtoms = 0;
-  }
-}
-
-void CMMDBSelManager::GetSelIndex ( int          selHnd,
-                                    PPCResidue & SelResidue,
-                                    int &        nSelResidues )  {
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    if (SelType[selHnd-1]!=STYPE_RESIDUE)  {
-      SelResidue   = NULL;
-      nSelResidues = 0;
-    } else  {
-      SelResidue   = (PPCResidue)Selection[selHnd-1];
-      nSelResidues = nSelItems[selHnd-1];
-    }
-  } else  {
-    SelResidue   = NULL;
-    nSelResidues = 0;
-  }
-}
-
-void CMMDBSelManager::GetSelIndex ( int        selHnd,
-                                    PPCChain & SelChain,
-                                    int &      nSelChains )  {
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    if (SelType[selHnd-1]!=STYPE_CHAIN)  {
-      SelChain   = NULL;
-      nSelChains = 0;
-    } else  {
-      SelChain   = (PPCChain)Selection[selHnd-1];
-      nSelChains = nSelItems[selHnd-1];
-    }
-  } else  {
-    SelChain   = NULL;
-    nSelChains = 0;
-  }
-}
-
-void CMMDBSelManager::GetSelIndex ( int        selHnd,
-                                    PPCModel & SelModel,
-                                    int &      nSelModels )  {
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    if (SelType[selHnd-1]!=STYPE_MODEL)  {
-      SelModel   = NULL;
-      nSelModels = 0;
-    } else  {
-      SelModel   = (PPCModel)Selection[selHnd-1];
-      nSelModels = nSelItems[selHnd-1];
-    }
-  } else  {
-    SelModel   = NULL;
-    nSelModels = 0;
-  }
-}
-
-
-void CMMDBSelManager::GetAtomStatistics ( int selHnd, RSAtomStat AS )  {
-int  i,k;
-  AS.Init();
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    k = selHnd-1;
-    switch (SelType[k])  {
-      case STYPE_MODEL   : if (Selection[k])
-                             for (i=0;i<nSelItems[k];i++)
-                               ((PCModel)Selection[k][i])->
-                                 CalcAtomStatistics ( AS );
-                       break;
-      case STYPE_CHAIN   : if (Selection[k])
-                             for (i=0;i<nSelItems[k];i++)
-                               ((PCChain)Selection[k][i])->
-                                 CalcAtomStatistics ( AS );
-                       break;
-      case STYPE_RESIDUE : if (Selection[k])
-                             for (i=0;i<nSelItems[k];i++)
-                               ((PCResidue)Selection[k][i])->
-                                 CalcAtomStatistics ( AS );
-                       break;
-      case STYPE_ATOM    : if (Selection[k])
-                             for (i=0;i<nSelItems[k];i++)
-                               ((PCAtom)Selection[k][i])->
-                                 CalcAtomStatistics ( AS );
-                       break;
-      default            : break;
-    }
-  }
-  AS.Finish();
-}
-
-
-void CMMDBSelManager::SelectAtom ( PCAtom atom, int   maskNo,
-                                   int  selKey, int & nsel )  {
-Boolean ASel;
-  ASel = atom->CheckMask ( Mask[maskNo] );
-  switch (selKey)  {
-    default       :
-    case SKEY_NEW :
-    case SKEY_OR  : if (!ASel)  {
-                      atom->SetMask ( Mask[maskNo] );
-                      nsel++;
-                    }
-                  break;
-    case SKEY_AND : if (ASel)  nsel++;
-                  break;
-    case SKEY_XOR : if (ASel)  {
-                      atom->RemoveMask ( Mask[maskNo] );
-                      nsel--;
-                    } else  {
-                      atom->SetMask ( Mask[maskNo] );
-                      nsel++;
-                    }
-                  break;
-    case SKEY_CLR : if (ASel)  {
-                      atom->RemoveMask ( Mask[maskNo] );
-                      nsel--;
-                    }
-  }
-}
-
-
-void CMMDBSelManager::SelectObject ( int selType, PCAtom atom,
-                                     int maskNo,  int  selKey,
-                                     int & nsel )  {
-PCMask  object;
-  switch (selType)  {
-    default :
-    case STYPE_UNDEFINED : return;
-    case STYPE_ATOM      : object = atom;                break;
-    case STYPE_RESIDUE   : object = atom->GetResidue();  break;
-    case STYPE_CHAIN     : object = atom->GetChain  ();  break;
-    case STYPE_MODEL     : object = atom->GetModel  ();  break;
-  }
-  if (!object)  return;
-  SelectObject ( object,maskNo,selKey,nsel );
-}
-
-
-void CMMDBSelManager::SelectObject ( PCMask object, int maskNo,
-                                     int    selKey, int & nsel )  {
-Boolean ASel;
-  ASel = object->CheckMask ( Mask[maskNo] );
-  switch (selKey)  {
-    default        :
-    case SKEY_NEW  :
-    case SKEY_OR   : if (!ASel)  {
-                       object->SetMask ( Mask[maskNo] );
-                       nsel++;
-                     }
-                  break;
-    case SKEY_AND  : if (ASel)  nsel++;
-                  break;
-    case SKEY_XOR  : if (ASel)  {
-                       object->RemoveMask ( Mask[maskNo] );
-                       nsel--;
-                     } else  {
-                       object->SetMask ( Mask[maskNo] );
-                       nsel++;
-                     }
-                  break;
-    case SKEY_CLR  : if (ASel)  {
-                       object->RemoveMask ( Mask[maskNo] );
-                       nsel--;
-                     }
-                  break;
-    case SKEY_XAND : if (ASel)  {
-                       object->RemoveMask ( Mask[maskNo] );
-                       nsel++;
-                     }
-  }
-}
-
-
-void  CMMDBSelManager::DeleteSelObjects ( int selHnd )  {
-PPCModel   model;
-PPCChain   chain;
-PPCResidue res;
-PPCAtom    atom;
-int        i,k,nSel;
-
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-
-    k    = selHnd-1;
-    nSel = nSelItems[k];
-    switch (SelType[k])  {
-
-      case STYPE_MODEL   : model = (PPCModel)Selection[k];
-                           for (i=0;i<nSel;i++)
-                             delete model[i];
-                        break;
-
-      case STYPE_CHAIN   : chain = (PPCChain)Selection[k];
-                           for (i=0;i<nSel;i++)
-                             delete chain[i];
-                        break;
-
-      case STYPE_RESIDUE : res   = (PPCResidue)Selection[k];
-                           for (i=0;i<nSel;i++)
-                             delete res[i];
-                        break;
-
-      case STYPE_ATOM    : atom  = (PPCAtom)Selection[k];
-                           for (i=0;i<nSel;i++)
-                             delete atom[i];
-                        break;
-
-      default : ;
-
-    }
-
-    if (Selection[k])  delete[] Selection[k];
-    Selection[k] = NULL;
-    nSelItems[k] = 0;
-
-  }
-
-}
-
-// ------------------------------------------------------------------------
-
-void CMMDBSelManager::MakeSelIndex ( int selHnd, int selType, int nsel )  {
-// if nsel is less than 0, the number of selected atoms will
-// be calculated.
-int       k,i,j,n,ns,k1,k2, nns;
-PCModel   model;
-PCChain   chain;
-PCResidue res;
-
-  if ((selHnd>0) && (selHnd<=nSelections))  {
-    k1 = selHnd-1;
-    k2 = k1+1;
-  } else  {
-    k1 = 0;
-    k2 = nSelections;
-  }
-
-  for (k=k1;k<k2;k++)  {
-    if (nsel<0)  {
-      ns = 0;
-      switch (selType)  {
-        case STYPE_ATOM    : for (i=0;i<nAtoms;i++)
-                               if (Atom[i])
-                                 if (Atom[i]->CheckMask(Mask[k]))  ns++;
-                          break;
-        case STYPE_RESIDUE : for (n=0;n<nModels;n++)  {
-                               model = Model[n];
-                               if (model)
-                                 for (i=0;i<model->nChains;i++) {
-                                   chain = model->Chain[i];
-                                   if (chain)
-                                     for (j=0;j<chain->nResidues;j++) {
-                                       res = chain->Residue[j];
-                                       if (res)
-                                         if (res->CheckMask(Mask[k]))  ns++;
-                                     }
-                                 }
-                             }
-                          break;
-        case STYPE_CHAIN   : for (i=0;i<nModels;i++)  {
-                               model = Model[i];
-                               if (model)
-                                 for (j=0;j<model->nChains;j++) {
-                                   chain = model->Chain[j];
-                                   if (chain)
-                                     if (chain->CheckMask(Mask[k]))  ns++;
-                                 }
-                             }
-                          break;
-        case STYPE_MODEL   : for (i=0;i<nModels;i++)
-                               if (Model[i])
-                                 if (Model[i]->CheckMask(Mask[k]))  ns++;
-                          break;
-        default : ;
-      }
-    } else
-      ns = nsel;
-    if (Selection[k])  delete[] Selection[k];
-    if (ns>0)  {
-      Selection[k] = new PCMask[ns];
-      nns = 0;
-      switch (selType)  {
-        case STYPE_ATOM    : for (i=0;i<nAtoms;i++)
-                               if (Atom[i])  {
-                                 if (Atom[i]->CheckMask(Mask[k]))  {
-                                   Selection[k][nns++] = Atom[i];
-                                   if (nns>=ns)  nns = ns-1;
-                                 }
-                               }
-                          break;
-        case STYPE_RESIDUE : for (n=0;n<nModels;n++)  {
-                               model = Model[n];
-                               if (model)
-                                 for (i=0;i<model->nChains;i++) {
-                                   chain = model->Chain[i];
-                                   if (chain)
-                                     for (j=0;j<chain->nResidues;j++)  {
-                                       res = chain->Residue[j];
-                                       if (res)
-                                         if (res->CheckMask(Mask[k]))  {
-                                           Selection[k][nns++] = res;
-                                           if (nns>=ns)  nns = ns-1;
-                                         }
-                                     }
-                                 }
-                             }
-                          break;
-        case STYPE_CHAIN   : for (i=0;i<nModels;i++)  {
-                               model = Model[i];
-                               if (model)
-                                 for (j=0;j<model->nChains;j++) {
-                                   chain = model->Chain[j];
-                                   if (chain)
-                                     if (chain->CheckMask(Mask[k]))  {
-                                       Selection[k][nns++] = chain;
-                                       if (nns>=ns)  nns = ns-1;
-                                     }
-                                 }
-                             }
-                          break;
-        case STYPE_MODEL   : for (i=0;i<nModels;i++)
-                               if (Model[i])
-                                 if (Model[i]->CheckMask(Mask[k]))  {
-                                   Selection[k][nns++] = Model[i];
-                                   if (nns>=ns)  nns = ns-1;
-                                 }
-                          break;
-        default : ;
-      }
-
-    } else
-      Selection[k] = NULL;
-
-    nSelItems[k] = ns;
-  }
-
-}
-
-
-//  -------------------  Stream functions  ----------------------
-
-
-void  CMMDBSelManager::write ( RCFile f )  {
-int  i;
-byte Version=1;
-
-  f.WriteByte ( &Version );
-
-  CMMDBCoorManager::write ( f );
-
-  f.WriteInt ( &nSelections );
-  for (i=0;i<nSelections;i++)  {
-    StreamWrite ( f,Mask[i]       );
-    f.WriteInt  ( &(nSelItems[i]) );
-    f.WriteInt  ( &(SelType[i])   );
-  }
-
-}
-
-void  CMMDBSelManager::read ( RCFile f )  {
-int  i;
-byte Version;
-
-  f.ReadByte ( &Version );
-
-  DeleteAllSelections();
-
-  CMMDBCoorManager::read ( f );
-
-  f.ReadInt ( &nSelections );
-  if (nSelections>0)  {
-    Mask      = new PCMask [nSelections];
-    Selection = new PPCMask[nSelections];
-    nSelItems = new int    [nSelections];
-    SelType   = new int    [nSelections];
-    for (i=0;i<nSelections;i++)  {
-      Mask[i] = NULL;
-      StreamRead   ( f,Mask[i]         );
-      f.ReadInt    ( &(nSelItems[i])   );
-      f.ReadInt    ( &(SelType[i])     );
-      Selection[i] = NULL;
-      if (Mask[i])
-           MakeSelIndex ( i+1,SelType[i],-1 );
-      else nSelItems[i] = 0;
-    }
-  }
-
-}
-
-
-MakeStreamFunctions(CMMDBSelManager)
diff --git a/mmdb/mmdb_selmngr.h b/mmdb/mmdb_selmngr.h
deleted file mode 100755
index 9843bb0..0000000
--- a/mmdb/mmdb_selmngr.h
+++ /dev/null
@@ -1,624 +0,0 @@
-//  $Id: mmdb_selmngr.h,v 1.22 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  mmdb_selmngr <interface>
-//       ~~~~~~~~~
-//       Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CMMDBSelManager ( MMDB atom selection manager )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_SelMngr__
-#define __MMDB_SelMngr__
-
-#ifndef  __MMDB_CoorMngr__
-#include "mmdb_coormngr.h"
-#endif
-
-#ifndef  __MMDB_Mask__
-#include "mmdb_mask.h"
-#endif
-
-
-
-// ======================  CMMDBSelManager  =========================
-
-//   Selection keys. These specify how the requested selection
-// operation applies to the existing selection for the given mask:
-//    SKEY_NEW    previous selection is wiped out
-//    SKEY_OR     new selection is added to the already selected set;
-//                if no selection preexists, SKEY_NEW and SKEY_OR
-//                are equivalent. This key is the default one in
-//                all selection functions.
-//    SKEY_AND    new selection is made on the already selected set;
-//                this corresponds to logical 'and' of former and
-//                current selections. If no selection preexists,
-//                no selection will be made.
-//    SKEY_XOR    only those atoms will be left which are found
-//                in either former or newly selected sets, but not
-//                in both of them; this corresponds to logical
-//                'exclusive or' of previous and current selections.
-//                If no selection preexists, it is equivalent to
-//                SKEY_OR.
-#define SKEY_NEW   0
-#define SKEY_OR    1
-#define SKEY_AND   2
-#define SKEY_XOR   3
-#define SKEY_CLR   4
-
-
-//  Selection types
-#define STYPE_INVALID  (-1)
-#define STYPE_UNDEFINED  0
-#define STYPE_ATOM       1
-#define STYPE_RESIDUE    2
-#define STYPE_CHAIN      3
-#define STYPE_MODEL      4
-
-//  Residue properties for SelectProperties()
-#define SELPROP_Solvent    0
-#define SELPROP_Aminoacid  1
-#define SELPROP_Nucleotide 2
-#define SELPROP_Sugar      3
-#define SELPROP_ModRes     4
-
-//  comparison rules for SelectUDD function
-#define UDSCR_LT         1
-#define UDSCR_LE         2
-#define UDSCR_EQ         3
-#define UDSCR_NE         4
-#define UDSCR_GE         5
-#define UDSCR_GT         6
-#define UDSCR_LTcase     7
-#define UDSCR_LEcase     8
-#define UDSCR_EQcase     9
-#define UDSCR_NEcase     10
-#define UDSCR_GEcase     11
-#define UDSCR_GTcase     12
-#define UDSCR_LTn        13
-#define UDSCR_LEn        14
-#define UDSCR_EQn        15
-#define UDSCR_NEn        16
-#define UDSCR_GEn        17
-#define UDSCR_GTn        18
-#define UDSCR_LTncase    19
-#define UDSCR_LEncase    20
-#define UDSCR_EQncase    21
-#define UDSCR_NEncase    22
-#define UDSCR_GEncase    23
-#define UDSCR_GTncase    24
-#define UDSCR_Substr     25
-#define UDSCR_NoSubstr   26
-#define UDSCR_Substr1    27
-#define UDSCR_NoSubstr1  28
-
-
-
-DefineClass(CMMDBSelManager);
-DefineStreamFunctions(CMMDBSelManager);
-
-class CMMDBSelManager : public CMMDBCoorManager  {
-
-  public :
-
-    CMMDBSelManager ();
-    CMMDBSelManager ( RPCStream Object );
-    ~CMMDBSelManager();
-
-
-    // ====================  Selecting atoms  =======================
-
-    //    NewSelection() creates a new selection mask and returns its
-    // handle.  A handle is always a positive (non-zero) integer.
-    // Calling NewSelection() is the only way to create a new
-    // selection mask. Notice however that masks will be automatically
-    // copied from another MMDB (see Copy(..) in CMMDBManager) if
-    // coordinates are copied; if this is the case, the mask handles
-    // will be inherited from the source MMDB as well. The masks will
-    // also be automatically deleted (see Delete(..) in CMMDBManager())
-    // if coordinates are deleted.
-    int   NewSelection ();
-
-    int   GetSelType ( int selHnd );  // returns STYPE_XXXX
-
-    //    DeleteSelection(..) deletes the specified selection mask
-    // and removes the corresponding selection attributes from
-    // all atoms, which were selected with this mask. If an atom
-    // was selected also with other mask(s), the other selection(s)
-    // will remain, provided that the corresponding masks are valid.
-    // After DeleteSelection() returns, the corresponding mask
-    // becomes invalid.
-    void  DeleteSelection ( int selHnd );
-
-    //    DeleteAllSelections() deletes all selection masks and
-    // unselects all atoms in the file. All mask handles become
-    // invalid.
-    void  DeleteAllSelections();
-
-    //   SelectAtoms(..) selects atoms in the serial number range
-    // of iSer1 to iSer2 by adding them to the set of atoms
-    // marked by the given mask. If iSer1=iSer2=0 then all atoms
-    // are selected. Each atom may be selected by a number of masks
-    // simultaneously.
-    void  SelectAtoms ( int selHnd, int iSer1, int iSer2,
-                        int selKey=SKEY_OR // selection key
-                      );
-
-    //   SelectAtoms(..) selects atoms with serial numbers given in
-    // vector asn[0..nsn-1].
-    void  SelectAtoms ( int selHnd, ivector asn, int nsn,
-                        int selKey=SKEY_OR // selection key
-                      );
-
-    //   UnselectAtoms(..) clears the specified mask for atoms in
-    // the serial number range of iSer1 to iSer2. If iSer1=iSer2=0
-    // then all atoms are cleared of the specified mask. If selHnd
-    // is set to 0, then the atoms are cleared of any mask.
-    void  UnselectAtoms ( int selHnd, int iSer1, int iSer2 );
-
-    //   SelectAtom(..) selects a single atom according to the value
-    // of selection key. If makeIndex is False, then the routine
-    // does not update the selection index. This saves time, but
-    // prevents GetSelIndex(..) from accessing all selected atoms.
-    // In order to update the index after all single-atom selections
-    // are done, use MakeSelIndex(selHnd) found next.
-    void  SelectAtom    ( int selHnd, PCAtom A, int selKey=SKEY_OR,
-                          Boolean makeIndex=True );
-
-    //   SelectResidue(..), SelectChain(..) and SelectModel(..)
-    // select a single residue, chain or model, or all their
-    // hierarchical descendants depending on the value of selType
-    // (i.e. atoms, residues (in chain and model) and chains
-    // (in model only). Ascending hierarchical objects should be
-    // selected explicitely, e.g. atom->GetResidue()->SelectResidue(..)
-    void  SelectResidue ( int selHnd, PCResidue Res,
-                          int selType, int selKey,
-                          Boolean makeIndex );
-    void  SelectChain   ( int selHnd, PCChain Chain,
-                          int selType, int selKey,
-                          Boolean makeIndex );
-    void  SelectModel   ( int selHnd, PCModel model,
-                          int selType, int selKey,
-                          Boolean makeIndex );
-
-
-    //   MakeSelIndex(.) calculates selection index for selection
-    // adressed by selHnd.  All selection functions except the
-    // SelectAtom(..) above, update selection index automatically.
-    // This function is for use after a series of calls to
-    // SelectAtom(..) with makeIndex parameter set False. This
-    // combination of SelectAtom - MakeSelIndex considerably saves CPU
-    // at extensive selections.
-    //   MakeSelIndex(.) returns the number of selected objects.
-    int   MakeSelIndex  ( int selHnd );
-    void  MakeAllSelIndexes();
-
-    //   Selecting by atom ID, space condition (a sphere) and some
-    // other bits.
-    void  SelectAtoms (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   iModel,   // model number; iModel=0 means
-                             // 'any model'
-             cpstr Chains,   // may be several chains "A,B,W"; "*"
-                             // means 'any chain' (in selected
-                             // model(s))
-             int   ResNo1,   // starting residue sequence number
-             cpstr Ins1,     // starting residue insertion code; "*"
-                             // means 'any code'
-             int   ResNo2,   // ending residue sequence number.
-             cpstr Ins2,     // ending residue insertion code; "*"
-                             // means 'any code'. Combination of
-                             // ResNo1=ResNo2=ANY_RES and
-                             // Ins1=Ins2="*" means 'any residue'
-                             // (in selected chain(s))
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means 'any
-                             // residue name'
-             cpstr ANames,   // may be several names "CA,CB"; "*"
-                             // means 'any atom' (in selected
-                             // residue(s))
-             cpstr Elements, // may be several element types
-                             // 'H,C,O,CU'; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means
-                             // 'any alternative location'
-             cpstr Segments, // may be several segment IDs
-                             // like "S1,S2,A234"; "*" means
-                             // 'any segment'
-             cpstr Charges,  // may be several charges like
-                             // "+1,-2,  "; "*" means 'any charge'
-             realtype occ1,  // lowest occupancy
-             realtype occ2,  // highest occupancy; occ1=occ2<0.0
-                             // means "any occupancy"
-             realtype x0,    // reference x-point
-             realtype y0,    // reference y-point
-             realtype z0,    // reference z-point
-             realtype d0,    // selection distance from the
-                             // reference point; d0<=0.0
-                             // means "any distance" and values
-                             // of x0, y0 and z0 are ignored
-             int  selKey=SKEY_OR // selection key
-           );
-
-    //  Selecting by just atom ID, no other conditions
-    void  SelectAtoms (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   iModel,   // model number; iModel=0 means
-                             // 'any model'
-             cpstr Chains,   // may be several chains "A,B,W"; "*"
-                             // means 'any chain' (in selected
-                             // model(s))
-             int   ResNo1,   // starting residue sequence number
-             cpstr Ins1,     // starting residue insertion code; "*"
-                             // means 'any code'
-             int   ResNo2,   // ending residue sequence number.
-             cpstr Ins2,     // ending residue insertion code; "*"
-                             // means 'any code'. Combination of
-                             // ResNo1=ResNo2=ANY_RES and
-                             // Ins1=Ins2="*" means 'any residue
-                             // number' (in selected chain(s))
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means 'any
-                             // residue name'
-             cpstr ANames,   // may be several names "CA,CB"; "*"
-                             // means 'any atom' (in selected
-                             // residue(s))
-             cpstr Elements, // may be several element types
-                             // "H,C,O,CU"; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means
-                             // 'any alternative location'
-             int selKey=SKEY_OR // selection key
-           );
-
-
-    //  Selecting by integer User-Defined Data
-    void  SelectUDD ( 
-             int      selHnd, // must be obtained from NewSelection()
-             int     selType, // selection type STYPE_XXXXX
-             int   UDDhandle, // UDD handle
-             int      selMin, // lower selection boundary
-             int      selMax, // upper selection boundary
-             int      selKey  // selection key
-           );
-    void  SelectUDD ( 
-             int      selHnd, // must be obtained from NewSelection()
-             int     selType, // selection type STYPE_XXXXX
-             int   UDDhandle, // UDD handle
-             realtype selMin, // lower selection boundary
-             realtype selMax, // upper selection boundary
-             int      selKey  // selection key
-           );
-    void  SelectUDD ( 
-             int        selHnd, // must be obtained from NewSelection()
-             int       selType, // selection type STYPE_XXXXX
-             int     UDDhandle, // UDD handle
-             cpstr selStr, // selection string
-             int       cmpRule, // comparison rule
-             int        selKey  // selection key
-           );
-
-
-    //  Selecting a sphere
-    void  SelectSphere (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             realtype  x, // x-coordinate of the sphere's center
-             realtype  y, // y-coordinate of the sphere's center
-             realtype  z, // z-coordinate of the sphere's center
-             realtype  r, // radius of the sphere
-             int  selKey=SKEY_OR // selection key
-           );
-
-    //  Selecting a cylinder
-    void  SelectCylinder (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             realtype x1, // x-coordinate of the cylinder axis' 1st end
-             realtype y1, // y-coordinate of the cylinder axis' 1st end
-             realtype z1, // z-coordinate of the cylinder axis' 1st end
-             realtype x2, // x-coordinate of the cylinder axis' 2nd end
-             realtype y2, // y-coordinate of the cylinder axis' 2nd end
-             realtype z2, // z-coordinate of the cylinder axis' 2nd end
-             realtype  r, // radius of the cylinder
-             int  selKey=SKEY_OR // selection key
-           );
-
-    //  Selecting all atoms on a given distance from a plane
-    void  SelectSlab (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             realtype  a, // a-parameter of the plane  ax+by+cz=d
-             realtype  b, // b-parameter of the plane  ax+by+cz=d
-             realtype  c, // c-parameter of the plane  ax+by+cz=d
-             realtype  d, // d-parameter of the plane  ax+by+cz=d
-             realtype  r, // distance to the plane
-             int selKey=SKEY_OR  // selection key
-           );
-
-    //  Selecting all atoms on a given distance from already selected
-    void  SelectNeighbours (
-             int  selHnd, // must be obtained from NewSelection()
-             int selType, // selection type STYPE_XXXXX
-             PPCAtom  sA, // array of already selected atoms
-             int    alen, // length of A
-             realtype d1, // minimal distance to already selected atoms
-             realtype d2, // maximal distance to already selected atoms
-             int  selKey=SKEY_OR // selection key
-           );
-
-
-    int   GetSelLength ( int selHnd );
-
-    //  Getting an array of atoms selected for a certain mask
-    void  GetSelIndex (
-             int       selHnd,   // selection mask
-             PPCAtom & SelAtom,  // continuous index of selected
-                                 // atoms; application must not
-                                 // dispose either index or atoms
-             int &     nSelAtoms // length of index
-                                 // [0..nSelectedAtoms-1]
-           );
-
-    //  Getting an array of residues selected for a certain mask
-    void  GetSelIndex (
-             int          selHnd,      // selection mask
-             PPCResidue & SelResidues, // continuous index of selected
-                                       // residues; application must
-                                       // not dispose either index or
-                                       // residues
-             int &        nSelResidues // length of index
-                                       // [0..nSelResidues-1]
-           );
-
-    //  Getting an array of chains selected for a certain mask
-    void  GetSelIndex (
-             int        selHnd,    // selection mask
-             PPCChain & SelChains, // continuous index of selected
-                                   // chains; application must not
-                                   // dispose either index or chains
-             int &      nSelChains // length of index
-                                   // [0..nSelChains-1]
-           );
-
-    //  Getting an array of models selected for a certain mask
-    void  GetSelIndex (
-             int        selHnd,    // selection mask
-             PPCModel & SelModels, // continuous index of selected
-                                   // models; application must not
-                                   // dispose either index or models
-             int &      nSelModels // length of index
-                                   // [0..nSelModels-1]
-           );
-
-    void  GetAtomStatistics ( int selHnd, RSAtomStat AS );
-
-
-    // ===============  General selection functions  ================
-
-    //   Selecting by atom ID, space condition (a sphere) and some
-    // other bits.
-    void  Select (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   selType,  // selection type STYPE_XXXXX
-             int   iModel,   // model number; iModel=0 means
-                             // 'any model'
-             cpstr Chains,   // may be several chains "A,B,W"; "*"
-                             // means 'any chain' (in selected
-                             // model(s))
-             int   ResNo1,   // starting residue sequence number
-             cpstr Ins1,     // starting residue insertion code; "*"
-                             // means 'any code'
-             int   ResNo2,   // ending residue sequence number.
-             cpstr Ins2,     // ending residue insertion code; "*"
-                             // means 'any code'. Combination of
-                             // ResNo1=ResNo2=ANY_RES and
-                             // Ins1=Ins2="*" means 'any residue'
-                             // (in selected chain(s))
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means
-                             // 'any residue name'
-             cpstr ANames,   // may be several names "CA,CB"; "*"
-                             // means 'any atom' (in selected
-                             // residue(s))
-             cpstr Elements, // may be several element types
-                             // 'H,C,O,CU'; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means
-                             // 'any alternative location'
-             cpstr Segments, // may be several segment IDs like
-                             // "S1,S2,A234"; "*" means
-                             // 'any segment'
-             cpstr Charges,  // may be several charges like
-                             // "+1,-2,  "; "*" means 'any charge'
-             realtype occ1,  // lowest occupancy
-             realtype occ2,  // highest occupancy; occ1=occ2<0.0
-                             // means "any occupancy"
-             realtype x0,    // reference x-point
-             realtype y0,    // reference y-point
-             realtype z0,    // reference z-point
-             realtype d0,    // selection distance from the
-                             // reference point; d0<=0.0
-                             // means "any distance" and values
-                             // of x0, y0 and z0 are ignored
-             int selKey=SKEY_OR // selection key
-           );
-
-
-    //  Selecting by just atom ID, no other conditions
-    void  Select (
-             int   selHnd,   // must be obtained from NewSelection()
-             int   selType,  // selection type STYPE_XXXXX
-             int   iModel,   // model number; iModel=0 means
-                             // 'any model'
-             cpstr Chains,   // may be several chains "A,B,W"; "*"
-                             // means 'any chain' (in selected
-                             // model(s))
-             int   ResNo1,   // starting residue sequence number
-             cpstr Ins1,     // starting residue insertion code; "*"
-                             // means 'any code'
-             int   ResNo2,   // ending residue sequence number.
-             cpstr Ins2,     // ending residue insertion code; "*"
-                             // means 'any code'. Combination of
-                             // ResNo1=ResNo2=ANY_RES and
-                             // Ins1=Ins2="*" means 'any residue
-                             // number' (in selected chain(s))
-             cpstr RNames,   // may be several residue names
-                             // "ALA,GLU,CIS"; "*" means
-                             // 'any residue name'
-             cpstr ANames,   // may be several names "CA,CB"; "*"
-                             // means 'any atom' (in selected
-                             // residue(s))
-             cpstr Elements, // may be several element types
-                             // "H,C,O,CU"; "*" means 'any element'
-             cpstr altLocs,  // may be several alternative
-                             // locations 'A,B'; "*" means
-                             // 'any alternative location'
-             int selKey=SKEY_OR // selection key
-           );
-
-
-    //  Selecting by coordinate ID.
-    //  Examples:
-    //
-    //  1.  /mdl/chn/s1.i1-s2.i2/at[el]:aloc
-    //  2.  /mdl/chn/*(res).ic  /at[el]:aloc
-    //  3.       chn/*(res).ic  /at[el]:aloc
-    //  4.           s1.i1-s2.i2/at[el]:aloc
-    //  5.           s1.i1      /at[el]:aloc
-    //  6.  /mdl
-    //  7.       chn
-    //  8.           s1.i1-s2.i2
-    //  9.           (res)
-    //  10.                      at[el]:aloc
-    //  11.      chn//[el]
-    //
-    //  mdl   - the model's serial number or 0 or '*' for any model
-    //          (default).
-    //  chn   - the chain ID or list of chains 'A,B,C' or '*' for
-    //          any chain (default).
-    //  s1,s2 - the starting and ending residue sequence numbers
-    //          or '*' for any sequence number (default).
-    //  i1,i2 - the residues insertion codes or '*' for any
-    //          insertion code. If the sequence number other than  
-    //          '*' is specified, then insertion code defaults to ""
-    //          (no insertion code), otherwise the default is '*'.
-    //  at    - atom name or list of atom names 'CA,N1,O' or '*'
-    //          for any atom name (default)
-    //  el    - chemical element name or list of chemical element
-    //          names 'C,N,O' or '*' for any chemical element name
-    //          (default)
-    //  aloc  - the alternative location indicator or '*' for any
-    //          alternate location. If the atom name and chemical
-    //          element name is specified (both may be '*'), then
-    //          the alternative location indicator defaults to ""
-    //          (no alternate location), otherwise the default is
-    //           '*'.
-    //
-    //  All spaces are ignored.
-    //
-    //  Returns -1 if numerical format of model is wrong, -2 if
-    //  numerical format for sequence number is wrong, and 0
-    //  otherwise.
-
-    int   Select (
-             int   selHnd,    // must be obtained from NewSelection()
-             int   selType,   // selection type STYPE_XXXXX
-             cpstr CID,       // coordinate ID
-             int   selKey     // selection key
-           );
-
-    //  Propagating the selection up and down coordinate hierarchy
-    void  Select (
-             int  selHnd1,  // must be obtained from NewSelection()
-             int  selType,  // selection type STYPE_XXXXX
-             int  selHnd2,  // must be obtained from NewSelection()
-                            // and have been used for selection
-             int  selKey=SKEY_OR // selection key
-           );
-
-    void  SelectProperty (
-             int  selHnd,   // must be obtained from NewSelection()
-             int propKey,   // property key SELPROP_XXXXXXX
-             int selType,   // selection type STYPE_XXXXX
-             int  selKey    // selection key
-           );
-
-    // In SelectDomain, domainRange is of the following format:
-    //    "*", "(all)"            - take all file
-    //    "-"                     - take chain without chain ID
-    //    "a:Ni-Mj,b:Kp-Lq,..."   - take chain a residue number N
-    //                             insertion code i to residue numberM
-    //                             insertion code j plus chain b
-    //                             residue number K insertion code p to
-    //                             residue number L insertion code q
-    //                             and so on.
-    //    "a:,b:..."              - take whole chains a and b and so on
-    //    "a:,b:Kp-Lq,..."        - any combination of the above.
-    int  SelectDomain ( int selHnd , cpstr domainRange,
-                        int selType, int selKey, int modelNo=1 );
-
-    void  DeleteSelObjects ( int selHnd );
-
-
-  protected :
-
-    // --- SELECTION DATA NOT FOR PUBLIC ACCESS
-    int       nSelections;   // number of selections
-    PPCMask   Mask;          // vector of selections
-    ivector   SelType;       // vector of selection types
-    ivector   nSelItems;     // numbers of selected items
-    PPCMask * Selection;     // vector of selected items
-
-    //  ---------------  Stream I/O  -----------------------------
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-    void  InitMMDBSelManager();
-    void  SelectAtom        ( PCAtom   atom,  int    maskNo,
-                              int    selKey,  int &  nsel );
-    void  SelectObject      ( int    selType, PCAtom atom,  int maskNo,
-                              int    selKey,  int &  nsel );
-    void  SelectObject      ( PCMask object,  int    maskNo,
-                              int    selKey,  int &  nsel );
-    void  MakeSelIndex      ( int    selHnd,  int    selType,
-                              int    nsel );
-
-    void  ResetManager();
-
-    PCMask GetSelMask ( int selHnd );
-
-};
-
-#endif
-
diff --git a/mmdb/mmdb_symop.cpp b/mmdb/mmdb_symop.cpp
deleted file mode 100755
index fa869e3..0000000
--- a/mmdb/mmdb_symop.cpp
+++ /dev/null
@@ -1,1009 +0,0 @@
-//  $Id: mmdb_symop.cpp,v 1.24 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDB_SymOp <implementation>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CSymOp  ( symmetry operator )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __MMDB_SymOp__
-#include "mmdb_symop.h"
-#endif
-
-
-
-//  ====================  CSymOp  ========================
-
-CSymOp::CSymOp() : CStream()  {
-  InitSymOp();
-}
-
-CSymOp::CSymOp ( RPCStream Object ) : CStream(Object)  {
-  InitSymOp();
-}
-
-CSymOp::~CSymOp()  {
-  FreeMemory();
-}
-
-void CSymOp::InitSymOp()  {
-int i,j;
-  XYZOp = NULL;
-  for (i=0;i<4;i++)  {
-    for (j=0;j<4;j++)
-      T[i][j] = 0.0;
-    T[i][i] = 1.0;
-  }
-}
-
-void CSymOp::FreeMemory()  {
-  if (XYZOp)  delete[] XYZOp;
-  XYZOp = NULL;
-}
-
-int  CSymOp::SetSymOp ( cpstr XYZOperation )  {
-int  i,j;
-
-  CreateCopy ( XYZOp,XYZOperation );
-  DelSpaces  ( XYZOp );
-
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      T[i][j] = 0.0;
-
-  i = GetOperation ( 0 );
-  if (!i) i = GetOperation ( 1 );
-  if (!i) i = GetOperation ( 2 );
-  T[3][3] = 1.0;
-
-  return i;
-
-}
-
-pstr CSymOp::GetSymOp()  {
-  if (XYZOp)  return XYZOp;
-        else  return pstr("");
-}
-
-
-int  CSymOp::GetOperation ( int n )  {
-char     L[100];
-pstr     p1,p2;
-int      len;
-realtype V;
-
-  p1 = XYZOp;
-  p2 = strchr ( p1,',' );
-  if (!p2)  return SYMOP_WrongSyntax;
-  if (n>0)  {
-    p1 = p2+1;
-    p2 = strchr ( p1,',' );
-    if (!p2)  return SYMOP_WrongSyntax;
-  }
-  if (n>1)  {
-    p1 = p2+1;
-    p2 = NULL;
-  }
-
-  if (p2)  *p2 = char(0);
-  strcpy ( L,p1 );
-  if (p2)  *p2 = ',';
-
-  DelSpaces ( L );
-  if (!L[0])  return SYMOP_WrongSyntax;
-  UpperCase ( L );
-
-  len = strlen ( L );
-  T[n][0] = 0.0;
-  if (L[0]=='X')  {
-    T[n][0] += 1.0;
-    L[0] = ' ';
-  }
-  do  {
-    p1 = strstr ( L,"+X" );
-    if (p1)  {
-      T[n][0] += 1.0;
-      strncpy ( p1,"  ",2 );
-    }
-  } while (p1);
-  do  {
-    p1 = strstr ( L,"-X" );
-    if (p1)  {
-      T[n][0] -= 1.0;
-      strncpy ( p1,"  ",2 );
-    }
-  } while (p1);
-
-  T[n][1] = 0.0;
-  if (L[0]=='Y')  {
-    T[n][1] += 1.0;
-    L[0] = ' ';
-  }
-  do  {
-    p1 = strstr ( L,"+Y" );
-    if (p1)  {
-      T[n][1] += 1.0;
-      strncpy ( p1,"  ",2 );
-    }
-  } while (p1);
-  do  {
-    p1 = strstr ( L,"-Y" );
-    if (p1)  {
-      T[n][1] -= 1.0;
-      strncpy ( p1,"  ",2 );
-    }
-  } while (p1);
-
-  T[n][2] = 0.0;
-  if (L[0]=='Z')  {
-    T[n][2] += 1.0;
-    L[0] = ' ';
-  }
-  do  {
-    p1 = strstr ( L,"+Z" );
-    if (p1)  {
-      T[n][2] += 1.0;
-      strncpy ( p1,"  ",2 );
-    }
-  } while (p1);
-  do  {
-    p1 = strstr ( L,"-Z" );
-    if (p1)  {
-      T[n][2] -= 1.0;
-      strncpy ( p1,"  ",2 );
-    }
-  } while (p1);
-
-  DelSpaces ( L );
-  if ((int)strlen(L)>=len)  return SYMOP_NotAnOperation;
-
-  // translational part
-  p1 = L;
-  T[n][3] = strtod ( p1,&p2 );
-  if (*p2=='/')  {
-    p1 = p2+1;
-    V  = strtod ( p1,&p2 );
-    if (V==0.0)  return SYMOP_ZeroDenominator;
-    T[n][3] /= V;
-  }
-
-  return SYMOP_Ok;
-
-}
-
-void  MakeSign ( pstr S, realtype V, realtype & AV )  {
-int      l;
-  if (V>0.0)  {
-    l = strlen ( S );
-    if (l>0)  {
-      if (S[l-1]!=',')  {
-        strcat ( S,"+" );
-      }
-    }
-    AV = V;
-  } else if (V<0.0)  {
-    strcat ( S,"-" );
-    AV = -V;
-  } else  {
-    AV = V;
-    return;
-  }
-}
-
-
-#define  __eps  1.0e-5
-
-void  GenTranslation ( pstr S, realtype V )  {
-realtype AV,nAV;
-char     N[50];
-int      n,d;
-
-  if (fabs(V)<=__eps)  return;
-  MakeSign ( S,V,AV );
-
-  d = 0;
-  n = -1;
-  while ((d<=20) && (n<0))  {
-    d++;
-    nAV = AV*d;
-    n   = mround(nAV);
-    if (fabs(nAV-n)>__eps)  n = -1;
-  }
-
-  if (d<=1)      sprintf ( N,"%i"    ,n   );
-  else if (n>=0) sprintf ( N,"%i/%i" ,n,d );
-            else sprintf ( N,"%-.10g",AV  );
-  strcat ( S,N );
-
-}
-
-void  GenTransformation ( pstr S, realtype V, pstr Axis ) {
-realtype AV,nAV;
-char     N[50];
-int      n,d;
-
-  if (fabs(V)<=__eps)  return;
-  MakeSign ( S,V,AV );
-
-  if (fabs(AV-1.0)>__eps)  {
-
-    d = 0;
-    n = -1;
-    while ((d<=20) && (n<0))  {
-      d++;
-      nAV = AV*d;
-      n   = mround(nAV);
-      if (fabs(nAV-n)>__eps)  n = -1;
-    }
-
-    if (n>=0)  sprintf ( N,"%i/%i*",n,d );
-         else  sprintf ( N,"%-.10g*",AV );
-    strcat ( S,N );
-
-  }
-
-  strcat ( S,Axis );
-
-}
-
-
-/*
-void  GenTranslation ( pstr S, realtype V )  {
-realtype AV,fAV;
-int      n,d;
-char     N[50];
-
-  if (V==0.0)  return;
-  MakeSign ( S,V,AV );
-
-  n = mround(floor(AV+0.00000001));
-  fAV = AV-n;
-
-  if (fabs(fAV-0.5)<=__eps)                 { n += 1;  d = 2; }
-  else if (fabs(fAV-0.25)<=__eps)           { n += 1;  d = 4; }
-  else if (fabs(fAV-0.75)<=__eps)           { n += 3;  d = 4; }
-  else if (fabs(fAV-0.33333333333)<=__eps)  { n += 1;  d = 3; }
-  else if (fabs(fAV-0.66666666666)<=__eps)  { n += 2;  d = 3; }
-  else if (fabs(fAV-0.16666666666)<=__eps)  { n += 1;  d = 6; }
-  else if (fabs(fAV-0.83333333333)<=__eps)  { n += 5;  d = 6; }
-                                      else  d = 1;
-
-  N[0] = char(0);
-  if (d>1)       sprintf  ( N,"%i/%i",n,d );
-  else if (n>0)  sprintf  ( N,"%i",n );
-           else  ParamStr ( N,pstr(""),AV );
-  strcat ( S,N );
-
-}
-
-void  GenTransformation ( pstr S, realtype V, pstr Axis ) {
-realtype AV;
-
-  if (V==0.0)  return;
-  MakeSign ( S,V,AV );
-
-  if (fabs(AV-0.5)<=__eps)                 strcat   ( S,"1/2*" );
-  else if (fabs(AV-0.25)<=__eps)           strcat   ( S,"1/4*" );
-  else if (fabs(AV-0.75)<=__eps)           strcat   ( S,"3/4*" );
-  else if (fabs(AV-0.33333333333)<=__eps)  strcat   ( S,"1/3*" );
-  else if (fabs(AV-0.66666666666)<=__eps)  strcat   ( S,"2/3*" );
-  else if (fabs(AV-0.16666666666)<=__eps)  strcat   ( S,"1/6*" );
-  else if (fabs(AV-0.83333333333)<=__eps)  strcat   ( S,"5/6*" );
-  else if (fabs(AV-1.0)>__eps)             ParamStr ( S,pstr(""),AV,
-                                                      10,pstr("*") );
-
-  strcat ( S,Axis );
-
-}
-
-*/
-
-Boolean  CSymOp::CompileOpTitle ( pstr S )  {
-  return CompileOpTitle ( S,T,True );
-}
-
-Boolean  CSymOp::CompileOpTitle ( pstr S, mat44 symMat,
-                                  Boolean compare )  {
-  S[0] = char(0);
-  GenTransformation ( S,symMat[0][0],pstr("X") );
-  GenTransformation ( S,symMat[0][1],pstr("Y") );
-  GenTransformation ( S,symMat[0][2],pstr("Z") );
-  GenTranslation    ( S,symMat[0][3]           );
-  strcat ( S,"," );
-  GenTransformation ( S,symMat[1][0],pstr("X") );
-  GenTransformation ( S,symMat[1][1],pstr("Y") );
-  GenTransformation ( S,symMat[1][2],pstr("Z") );
-  GenTranslation    ( S,symMat[1][3]           );
-  strcat ( S,"," );
-  GenTransformation ( S,symMat[2][0],pstr("X") );
-  GenTransformation ( S,symMat[2][1],pstr("Y") );
-  GenTransformation ( S,symMat[2][2],pstr("Z") );
-  GenTranslation    ( S,symMat[2][3]           );
-  DelSpaces ( S );
-  if ((!compare) || (!strcmp(S,XYZOp)))  return True;
-  else  {
-    S[0] = char(0);
-    GenTranslation    ( S,symMat[0][3]           );
-    GenTransformation ( S,symMat[0][0],pstr("X") );
-    GenTransformation ( S,symMat[0][1],pstr("Y") );
-    GenTransformation ( S,symMat[0][2],pstr("Z") );
-    strcat ( S,"," );
-    GenTranslation    ( S,symMat[1][3]           );
-    GenTransformation ( S,symMat[1][0],pstr("X") );
-    GenTransformation ( S,symMat[1][1],pstr("Y") );
-    GenTransformation ( S,symMat[1][2],pstr("Z") );
-    strcat ( S,"," );
-    GenTranslation    ( S,symMat[2][3]           );
-    GenTransformation ( S,symMat[2][0],pstr("X") );
-    GenTransformation ( S,symMat[2][1],pstr("Y") );
-    GenTransformation ( S,symMat[2][2],pstr("Z") );
-    DelSpaces ( S );
-    if (!strcmp(S,XYZOp))  return True;
-  }
-  return False;
-}
-
-void  CSymOp::Transform ( realtype & x, realtype & y, realtype & z )  {
-realtype x1,y1,z1;
-  x1 = T[0][0]*x + T[0][1]*y + T[0][2]*z + T[0][3];
-  y1 = T[1][0]*x + T[1][1]*y + T[1][2]*z + T[1][3];
-  z1 = T[2][0]*x + T[2][1]*y + T[2][2]*z + T[2][3];
-  x = x1;
-  y = y1;
-  z = z1;
-}
-
-void  CSymOp::GetTMatrix ( mat44 & TMatrix )  {
-// copies T to TMatrix
-int i,j;
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      TMatrix[i][j] = T[i][j];
-}
-
-void  CSymOp::SetTMatrix ( mat44 & TMatrix )  {
-// copies TMatrix to T
-int i,j;
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      T[i][j] = TMatrix[i][j];
-}
-
-
-void  CSymOp::Print()  {
-int i;
-  printf ( "  operation '%s'\n",XYZOp );
-  for (i=0;i<4;i++)
-    printf ( "               %10.3g %10.3g %10.3g  %10.3g\n",
-             T[i][0],T[i][1],T[i][2],T[i][3] );
-}
-
-void  CSymOp::Copy ( PCSymOp SymOp )  {
-int i,j;
-  CreateCopy ( XYZOp,SymOp->XYZOp );
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      T[i][j] = SymOp->T[i][j];
-}
-
-void  CSymOp::write ( RCFile f )  {
-int  i,j;
-byte Version=1;
-  f.WriteByte   ( &Version );
-  f.CreateWrite ( XYZOp    );
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      f.WriteReal ( &(T[i][j]) );
-}
-
-void  CSymOp::read ( RCFile f )  {
-int  i,j;
-byte Version;
-  f.ReadByte   ( &Version );
-  f.CreateRead ( XYZOp    );
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      f.ReadReal ( &(T[i][j]) );
-}
-
-MakeStreamFunctions(CSymOp);
-
-
-
-//  ====================  CSymOps  ========================
-
-CSymOps::CSymOps() : CStream()  {
-  InitSymOps();
-}
-
-CSymOps::CSymOps ( RPCStream Object ) : CStream(Object)  {
-  InitSymOps();
-}
-
-CSymOps::~CSymOps()  {
-  FreeMemory();
-}
-
-void CSymOps::InitSymOps()  {
-  SpGroup = NULL;
-  Nops    = 0;
-  SymOp   = NULL;
-}
-
-void CSymOps::FreeMemory()  {
-int i;
-  if (SpGroup)  delete[] SpGroup;
-  SpGroup = NULL;
-  if (SymOp)  {
-    for (i=0;i<Nops;i++)
-      if (SymOp[i])  delete SymOp[i];
-    delete[] SymOp;
-    SymOp = NULL;
-  }
-  Nops = 0;
-}
-
-#define  symop_file  cpstr("symop.lib")
-
-int  CSymOps::SetGroupSymopLib ( cpstr SpaceGroup,
-                                 cpstr symop_lib )  {
-char  S[500];
-char  G[100];
-pstr  p;
-CFile f;
-int   i,RC;
-
-  FreeMemory();
-
-  CreateCopy ( SpGroup,SpaceGroup );
-
-  if (!symop_lib)          p = pstr(symop_file);
-  else if (!symop_lib[0])  p = pstr(symop_file);
-                     else  p = pstr(symop_lib);
-  f.assign ( p,True );
-  if (!f.reset(True))  {
-    p = getenv ( "SYMOP" );
-    if (p)
-      strcpy ( S,p );
-    else  {
-      p = getenv ( "CLIBD" );
-      if (p)  {
-        strcpy ( S,p );
-        if (S[strlen(S)-1]!='/')  strcat ( S,"/" );
-        strcat ( S,"symop.lib" );
-      } else
-        strcpy ( S,"symop.lib" );
-    }
-    f.assign ( S,True );
-    if (!f.reset(True))  return SYMOP_NoLibFile;
-  }
-
-  strcpy ( G," '"    );
-  strcat ( G,SpGroup );
-  strcat ( G,"'"     );
-  S[0] = char(0);
-  while (!f.FileEnd() && (!strstr(S,G)))
-    f.ReadLine ( S,sizeof(S) );
-  if (f.FileEnd())  {
-    f.shut();
-    return SYMOP_UnknownSpaceGroup;
-  }
-
-  p = S;
-  while (*p==' ')  p++;
-  p = strchr ( p,' ' );
-  if (p)  Nops = mround(strtod(p,NULL));
-  if (Nops<=0)  return SYMOP_NoSymOps;
-
-  SymOp = new PCSymOp[Nops];
-  RC    = SYMOP_Ok;
-  for (i=0;(i<Nops) && (!RC);i++)  {
-    f.ReadLine ( S,sizeof(S) );
-    SymOp[i] = new CSymOp();
-    RC = SymOp[i]->SetSymOp ( S );
-  }
-
-  f.shut();
-
-  return RC;
-
-}
-
-
-#define  syminfo_file  cpstr("syminfo.lib")
-
-int  CSymOps::SetGroup ( cpstr SpaceGroup,
-                         cpstr syminfo_lib )  {
-CFile    f;
-pstr     p;
-psvector lines,lines1;
-char     S[500];
-char     G[100];
-char     O[100];
-mat44    T1,T2,T3;
-int      i,j,k,l,m,n,RC;
-int      nlines,npops,ncops;
-
-  FreeMemory();
-
-  npops = 0;
-  ncops = 0;
-
-  CreateCopy ( SpGroup,SpaceGroup );
-
-  if (!syminfo_lib)          p = pstr(syminfo_file);
-  else if (!syminfo_lib[0])  p = pstr(syminfo_file);
-                       else  p = pstr(syminfo_lib);
-  f.assign ( p,True );
-  if (!f.reset(True))  {
-    p = getenv ( "SYMINFO" );
-    if (p)
-      strcpy ( S,p );
-    else  {
-      p = getenv ( "CLIBD" );
-      if (p)  {
-        strcpy ( S,p );
-        if (S[strlen(S)-1]!='/')  strcat ( S,"/" );
-        strcat ( S,"syminfo.lib" );
-      } else
-        strcpy ( S,"syminfo.lib" );
-    }
-    f.assign ( S,True );
-    if (!f.reset(True))  return SYMOP_NoLibFile;
-  }
-
-
-  if (strncasecmp(SpGroup,"Hall:",5))  {
-    // normal space group symbol on input
-    strcpy ( G," '"    );
-    strcat ( G,SpGroup );
-    strcat ( G,"'"     );
-    S[0] = char(0);
-    while (!f.FileEnd() && !(strstr(S,G) && (strstr(S,"symbol xHM") ||
-            strstr(S,"symbol old"))))
-      f.ReadLine ( S,sizeof(S) );
-  } else  {
-    // hall descriptor on input
-    strcpy ( G," ' " );
-    p = &(SpGroup[5]);
-    while (*p==' ')  p++;
-    strcat ( G,p     );
-    strcat ( G,"'"   );
-    S[0] = char(0);
-    while (!f.FileEnd() && !(strstr(S,G) && strstr(S,"symbol Hall")))
-      f.ReadLine ( S,sizeof(S) );
-  }
-  if (f.FileEnd())  {
-    f.shut();
-    return SYMOP_UnknownSpaceGroup;
-  }
-
-  // found spacegroup, move to symop lines
-  while (!f.FileEnd() && (!strstr(S,"symop")))
-    f.ReadLine ( S,sizeof(S) );
-
-  nlines = 256;
-  GetVectorMemory ( lines,nlines,0 );
-  for (i=0;i<nlines;i++)
-    lines[i] = NULL;
-  n = 0;
-  CreateCopy ( lines[n++],S );
-
-  // count primitive operators
-  while (!f.FileEnd() && (strstr(S,"symop"))) {
-    npops++;
-    f.ReadLine ( S,sizeof(S) );
-    if (n>=nlines)  {
-      nlines += + 256;
-      GetVectorMemory ( lines1,nlines,0 );
-      for (i=0;i<n;i++)
-        lines1[i] = lines[i];
-      for (i=n;i<nlines;i++)
-        lines1[i] = NULL;
-      FreeVectorMemory ( lines,0 );
-      lines = lines1;
-    }
-    CreateCopy ( lines[n++],S );
-  }
-
-  // count centering operators
-  while (!f.FileEnd() && (strstr(S,"cenop"))) {
-    ncops++;
-    f.ReadLine ( S,sizeof(S) );
-    if (n>=nlines)  {
-      nlines += + 256;
-      GetVectorMemory ( lines1,nlines,0 );
-      for (i=0;i<n;i++)
-        lines1[i] = lines[i];
-      for (i=n;i<nlines;i++)
-        lines1[i] = NULL;
-      FreeVectorMemory ( lines,0 );
-      lines = lines1;
-    }
-    CreateCopy ( lines[n++],S );
-  }
-
-  Nops = npops*ncops;
-  SymOp = new PCSymOp[Nops];
-  RC    = SYMOP_Ok;
-
-  n = 0;  // start second pass here
-
-  // read primitive operators
-  for (i=0;(i<npops) && (!RC);i++)  {
-    SymOp[i] = new CSymOp();
-    RC = SymOp[i]->SetSymOp ( lines[n++]+6 );
-  }
-
-  // loop over non-trivial centering operators, and for each loop
-  // over primtive operators
-  for (i=1;(i<ncops) && (!RC);i++)  {
-    n++;  // this also skips the identity operator
-    for (j=0;(j<npops) && (!RC);j++)  {
-      SymOp[i*npops+j] = new CSymOp();
-      RC = SymOp[i*npops+j]->SetSymOp ( lines[n]+6 );
-      SymOp[i*npops+j]->GetTMatrix(T1);
-      SymOp[j]->GetTMatrix(T2);
-      for (k=0;k<4;k++)
-        for (l=0;l<4;l++) {
-          T3[k][l] = 0.0;
-          for (m=0;m<4;m++)
-            T3[k][l] += T1[k][m]*T2[m][l];
-        }
-      for (k=0;k<3;k++)                  // kdc fix
-        T3[k][3] -= floor ( T3[k][3] );  // kdc fix
-      SymOp[i*npops+j]->CompileOpTitle ( O,T3,False );
-      SymOp[i*npops+j]->SetSymOp ( O );
-    }
-  }
-
-  f.shut();
-
-  for (i=0;i<nlines;i++)
-    if (lines[i])  delete[] lines[i];
-  FreeVectorMemory ( lines,0 );
-
-  return RC;
-
-}
-
-/*
-int  CSymOps::SetGroup ( cpstr SpaceGroup,
-                         cpstr syminfo_lib )  {
-CFile  f;
-pstr   p;
-char   S[500];
-char   G[100];
-char   O[100];
-mat44  T1,T2,T3;
-int    i,j,k,l,m,RC;
-int    npops,ncops;
-long   symop_start;
-//fpos_t symop_start;
-
-  FreeMemory();
-
-  npops = 0;
-  ncops = 0;
-
-  CreateCopy ( SpGroup,SpaceGroup );
-
-  if (!syminfo_lib)          p = pstr(syminfo_file);
-  else if (!syminfo_lib[0])  p = pstr(syminfo_file);
-                       else  p = pstr(syminfo_lib);
-  f.assign ( p,True );
-  if (!f.reset(True))  {
-    p = getenv ( "SYMINFO" );
-    if (p)
-      strcpy ( S,p );
-    else  {
-      p = getenv ( "CLIBD" );
-      if (p)  {
-        strcpy ( S,p );
-        if (S[strlen(S)-1]!='/')  strcat ( S,"/" );
-        strcat ( S,"syminfo.lib" );
-      } else
-        strcpy ( S,"syminfo.lib" );
-    }
-    f.assign ( S,True );
-    if (!f.reset(True))  return SYMOP_NoLibFile;
-  }
-
-  if (strncasecmp(SpGroup,"Hall:",5))  {
-    // normal space group symbol on input
-    strcpy ( G," '"    );
-    strcat ( G,SpGroup );
-    strcat ( G,"'"     );
-    S[0] = char(0);
-    while (!f.FileEnd() && !(strstr(S,G) && (strstr(S,"symbol xHM") ||
-            strstr(S,"symbol old"))))
-      f.ReadLine ( S,sizeof(S) );
-  } else  {
-    // hall descriptor on input
-    strcpy ( G," ' " );
-    p = &(SpGroup[5]);
-    while (*p==' ')  p++;
-    strcat ( G,p     );
-    strcat ( G,"'"   );
-    S[0] = char(0);
-    while (!f.FileEnd() && !(strstr(S,G) && strstr(S,"symbol Hall")))
-      f.ReadLine ( S,sizeof(S) );
-  }
-  if (f.FileEnd())  {
-    f.shut();
-    return SYMOP_UnknownSpaceGroup;
-  }
-
-  // found spacegroup, move to symop lines
-  while (!f.FileEnd() && (!strstr(S,"symop"))) {
-    symop_start = f.Position();
-//#    fgetpos ( f.GetHandle(),&symop_start );
-    f.ReadLine ( S,sizeof(S) );
-  }
-  // count primitive operators
-  while (!f.FileEnd() && (strstr(S,"symop"))) {
-    npops++;
-    f.ReadLine ( S,sizeof(S) );
-  }
-  // count centering operators
-  while (!f.FileEnd() && (strstr(S,"cenop"))) {
-    ncops++;
-    f.ReadLine ( S,sizeof(S) );
-  }
-  Nops = npops*ncops;
-  f.seek(symop_start);
-//#  fsetpos ( f.GetHandle(),&symop_start );
-  SymOp = new PCSymOp[Nops];
-  RC    = SYMOP_Ok;
-
-  // read primitive operators
-  for (i=0;(i<npops) && (!RC);i++)  {
-    f.ReadLine ( S,sizeof(S) );
-    SymOp[i] = new CSymOp();
-    RC = SymOp[i]->SetSymOp ( S+6 );
-  }
-
-  // skip identity centering operator
-  f.ReadLine ( S,sizeof(S) );
-  // loop over non-trivial centering operators, and for each loop
-  // over primtive operators
-  for (i=1;(i<ncops) && (!RC);i++)  {
-    f.ReadLine ( S,sizeof(S) );
-    for (j=0;(j<npops) && (!RC);j++)  {
-      SymOp[i*npops+j] = new CSymOp();
-      RC = SymOp[i*npops+j]->SetSymOp ( S+6 );
-
-      SymOp[i*npops+j]->GetTMatrix(T1);
-      SymOp[j]->GetTMatrix(T2);
-      for (k=0;k<4;k++)
-        for (l=0;l<4;l++) {
-          T3[k][l] = 0.0;
-          for (m=0;m<4;m++)
-            T3[k][l] += T1[k][m]*T2[m][l];
-        }
-      for (k=0;k<3;k++)                  // kdc fix
-        T3[k][3] -= floor ( T3[k][3] );  // kdc fix
-      SymOp[i*npops+j]->CompileOpTitle(O,T3,False);
-      SymOp[i*npops+j]->SetSymOp (O);
-    }
-  }
-
-  f.shut();
-
-  return RC;
-
-}
-*/
-
-void CSymOps::Reset()  {
-// removes all symmetry operations
-  FreeMemory();
-}
-
-int  CSymOps::AddSymOp ( cpstr XYZOperation )  {
-// adds a symmetry operation
-PPCSymOp SymOp1;
-int      i;
-  SymOp1 = new PCSymOp[Nops+1];
-  for (i=0;i<Nops;i++)
-    SymOp1[i] = SymOp[i];
-  if (SymOp) delete[] SymOp;
-  SymOp = SymOp1;
-  i = Nops;
-  SymOp[i] = new CSymOp();
-  Nops++;
-  return SymOp[i]->SetSymOp ( XYZOperation );
-}
-
-void CSymOps::PutGroupName ( cpstr SpGroupName )  {
-  CreateCopy ( SpGroup,SpGroupName );
-}
-
-
-int  CSymOps::GetNofSymOps()  {
-//  GetNofSymOps()  returns Nops -- the number of symmetry operations
-  return Nops;
-}
-
-pstr CSymOps::GetSymOp ( int Nop )  {
-  if ((0<=Nop) && (Nop<Nops))  return SymOp[Nop]->GetSymOp();
-                         else  return pstr("");
-}
-
-int  CSymOps::Transform ( realtype & x, realtype & y, realtype & z,
-                          int Nop )  {
-//  Transform(..) transforms the coordinates according to the
-// symmetry operation Nop. The return code is non-zero if
-// Nop is a wrong operation number (must range from 0 to Nops-1).
-  if ((Nop<0) || (Nop>=Nops))  return 1;
-  if (SymOp[Nop])  {
-    SymOp[Nop]->Transform ( x,y,z );
-    return 0;
-  } else
-    return 2;
-}
-
-int  CSymOps::GetTMatrix ( mat44 & TMatrix, int Nop )  {
-//  GetTMatrix(..) returns the coordinate transformation matrix
-// for the symmetry operation Nop. The return code is non-zero if
-// Nop is a wrong operation number (must range from 0 to Nops-1).
-  if ((Nop<0) || (Nop>=Nops))  return 1;
-  if (SymOp[Nop])  {
-    SymOp[Nop]->GetTMatrix ( TMatrix );
-    return 0;
-  } else
-    return 2;
-}
-
-void  CSymOps::Print()  {
-int  i;
-char S[200];
-  printf ( "  SPACE GROUP  '%s'\n",SpGroup );
-  for (i=0;i<Nops;i++)  {
-    SymOp[i]->Print();
-    if (SymOp[i]->CompileOpTitle(S))
-          printf ( " CHECK STATUS: Ok\n" );
-    else  printf ( " CHECK STATUS: Generated '%s'\n",S );
-  }
-}
-
-
-void  CSymOps::Copy ( PCSymOps SymOps )  {
-int i;
-  FreeMemory();
-  CreateCopy ( SpGroup,SymOps->SpGroup );
-  Nops = SymOps->Nops;
-  if (Nops>0)  {
-    SymOp = new PCSymOp[Nops];
-    for (i=0;i<Nops;i++) {
-      SymOp[i] = new CSymOp();
-      SymOp[i]->Copy ( SymOps->SymOp[i] );
-    }
-  }
-}
-
-
-void  CSymOps::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte   ( &Version );
-  f.CreateWrite ( SpGroup  );
-  f.WriteInt    ( &Nops    );
-  for (i=0;i<Nops;i++)
-    StreamWrite ( f,SymOp[i] );
-}
-
-void  CSymOps::read ( RCFile f )  {
-int  i;
-byte Version;
-  FreeMemory();
-  f.ReadByte   ( &Version );
-  f.CreateRead ( SpGroup  );
-  f.ReadInt    ( &Nops    );
-  if (Nops>0)  {
-    SymOp = new PCSymOp[Nops];
-    for (i=0;i<Nops;i++) {
-      SymOp[i] = NULL;
-      StreamRead ( f,SymOp[i] );
-    }
-  }
-}
-
-
-MakeStreamFunctions(CSymOps)
-
-
-/*
-
-void TestSymOps()  {
-pstr     p,p1;
-int      RC;
-char     S[500];
-CSymOps  SymOps;
-CFile    f;
-
-  p = getenv ( "PDB_ROOT" );
-  if (p)  {
-    strcpy ( S,p );
-    strcat ( S,"/lib/" );
-  } else
-    S[0] = char(0);
-  strcat   ( S,"symop.lib" );
-  f.assign ( S,True );
-  if (!f.reset())  {
-    printf ( " +++++ No symop.lib file found.\n" );
-    return;
-  }
-
-  while (!f.FileEnd())  {
-    f.ReadLine ( S,sizeof(S) );
-    if (S[0] && (S[0]!=' '))  {
-      p = strchr ( S,'\'' );
-      if (p)  {
-        p++;
-        p1 = strchr ( p,'\'' );
-        if (!p1)  p = NULL;
-      }
-      if (!p)  {
-        printf ( " +++++ Strange line in symop.lib:\n"
-                 "%s\n",S );
-        return;
-      }
-      *p1 = char(0);
-      RC = SymOps.SetGroup ( p );
-      printf ( " =========================================================\n"
-               "  RC=%i\n",RC );
-      SymOps.Print();
-    }
-  }
-
-  return;
-
-}
-
-*/
diff --git a/mmdb/mmdb_symop.h b/mmdb/mmdb_symop.h
deleted file mode 100755
index 21aa34c..0000000
--- a/mmdb/mmdb_symop.h
+++ /dev/null
@@ -1,173 +0,0 @@
-//  $Id: mmdb_symop.h,v 1.21 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDB_SymOp <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CSymOp  ( symmetry operators )
-//       ~~~~~~~~~   CSymOps ( container of symmetry operators )
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_SymOp__
-#define __MMDB_SymOp__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-
-
-//  ====================  CSymOp  ========================
-
-DefineClass(CSymOp);
-DefineStreamFunctions(CSymOp);
-
-class CSymOp : public CStream  {
-
-  public :
-
-    CSymOp ();
-    CSymOp ( RPCStream Object );
-    ~CSymOp();
-
-    int     SetSymOp  ( cpstr XYZOperation );
-    pstr    GetSymOp  ();
-
-    void    Transform ( realtype & x, realtype & y, realtype & z );
-
-    void    GetTMatrix ( mat44 & TMatrix );  // copies T to TMatrix
-    void    SetTMatrix ( mat44 & TMatrix );  // copies TMatrix to T
-
-    Boolean CompileOpTitle ( pstr S );  // makes XYZOp from matrix T
-    Boolean CompileOpTitle ( pstr S, mat44 symMat, Boolean compare );
-    void    Print          ();          // prints operation and matrix
-
-    void Copy  ( PCSymOp SymOp );
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected :
-
-    pstr  XYZOp;
-    mat44 T;
-
-    void InitSymOp    ();
-    void FreeMemory   ();
-    int  GetOperation ( int n );
-
-};
-
-
-//  ====================  CSymOps  ========================
-
-#define SYMOP_Ok                   0
-#define SYMOP_NoLibFile           -1
-#define SYMOP_UnknownSpaceGroup   -2
-#define SYMOP_NoSymOps            -3
-#define SYMOP_WrongSyntax         -4
-#define SYMOP_NotAnOperation      -5
-#define SYMOP_ZeroDenominator     -6
-
-
-DefineClass(CSymOps);
-DefineStreamFunctions(CSymOps);
-
-class CSymOps : public CStream  {
-
-  public :
-
-    CSymOps ();
-    CSymOps ( RPCStream Object );
-    ~CSymOps();
-
-    virtual void FreeMemory();
-
-    int  SetGroupSymopLib ( cpstr SpaceGroup,
-                            cpstr symop_lib=NULL );
-      // Space Group is taken from symop.lib. Return Code:
-      // SYMOP_Ok <=> success
-
-    int  SetGroup ( cpstr SpaceGroup,
-                    cpstr syminfo_lib=NULL );
-      // Space Group is taken from syminfo.lib. Return Code:
-      // SYMOP_Ok <=> success
-
-    void Reset           ();        // removes all symmetry operations
-    virtual int AddSymOp ( cpstr XYZOperation ); // adds a sym.
-                                                      // operation
-    void PutGroupName    ( cpstr SpGroupName  );
-
-    //  GetNofSymOps()  returns Nops -- the number of sym. operations
-    int  GetNofSymOps ();
-    pstr GetSymOp     ( int Nop );
-
-    //  Transform(..) transforms the coordinates according to the
-    // symmetry operation Nop. The return code is non-zero if
-    // Nop is a wrong operation number (must range from 0 to Nops-1).
-    int  Transform ( realtype & x, realtype & y, realtype & z,
-                     int Nop );
-
-    //  GetTMatrix(..) returns the coordinate transformation matrix
-    // for the symmetry operation Nop. The return code is non-zero if
-    // Nop is a wrong operation number (must range from 0 to Nops-1).
-    int  GetTMatrix ( mat44 & TMatrix, int Nop );
-
-    void Print ();
-
-    virtual void Copy ( PCSymOps SymOps );
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected :
-
-    pstr     SpGroup;
-    int      Nops;
-    PPCSymOp SymOp;
-
-    void InitSymOps();
-
-};
-
-
-// extern void TestSymOps();
-
-#endif
-
diff --git a/mmdb/mmdb_tables.cpp b/mmdb/mmdb_tables.cpp
deleted file mode 100755
index 18a178f..0000000
--- a/mmdb/mmdb_tables.cpp
+++ /dev/null
@@ -1,750 +0,0 @@
-//  $Id: mmdb_tables.cpp,v 1.26 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_Tables <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Functions : 
-//       ~~~~~~~~~~~ 
-//
-//  **** Constants : AName  ( array of 2-character atom names       )
-//       ~~~~~~~~~~~ HAName ( array of 2=character heteroatom names )
-//                   RName  ( 3-characters amino acid names         )
-//                   RName1 ( 1-characters amino acid names         )
-//
-//
-//  (C) E. Krissinel  2000-2010
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MMDB_Tables__
-#include "mmdb_tables.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-
-//  =================================================================
-
-cpstr const ElementName[nElementNames] = {
-  " H", "HE",
-  "LI", "BE", " B", " C", " N", " O", " F", "NE",
-  "NA", "MG", "AL", "SI", " P", " S", "CL", "AR",
-  " K", "CA",
-        "SC", "TI", " V", "CR", "MN", "FE",
-        "CO", "NI", "CU", "ZN",
-              "GA", "GE", "AS", "SE", "BR", "KR",
-  "RB", "SR",
-        " Y", "ZR", "NB", "MO", "TC", "RU",
-        "RH", "PD", "AG", "CD",
-              "IN", "SN", "SB", "TE", " I", "XE",
-  "CS", "BA",
-        "LA", "CE", "PR", "ND", "PM", "SM", "EU",
-        "GD", "TB", "DY", "HO", "ER", "TM", "YB",
-              "LU", "HF", "TA", " W", "RE", "OS",
-              "IR", "PT", "AU", "HG",
-                    "TL", "PB", "BI", "PO", "AT", "RN",
-  "FR", "RA",
-        "AC", "TH", "PA", " U", "NP", "PU", "AM",
-        "CM", "BK", "CF", "ES", "FM", "MD", "NO",
-              "LR", "RF", "DB", "SG", "BH", "HS",
-              "MT", "UN", "UU", "UB",
-                          "UQ",       "UH",       "UO",
-  " D", "AN"
-};
-
-realtype const MolecWeight[nElementNames] = {
-  1.0079, 4.0026,
-  6.9410, 9.0122, 10.811, 12.011, 14.007, 15.999, 18.998, 20.180,
-  22.990, 24.305, 26.982, 28.086, 30.974, 32.066, 35.453, 39.948,
-  39.098, 40.078,
-          44.956, 47.867, 50.942, 51.996, 54.938, 55.845,
-          58.993, 58.693, 63.546, 65.390,
-                  69.723, 72.610, 74.922, 78.960, 79.904, 83.800,
-  85.468, 87.620,
-          88.906, 91.224, 92.906, 95.940, 97.907, 101.07,
-          102.91, 106.42, 107.87, 112.41,
-                  114.82, 118.71, 121.76, 127.60, 126.90, 131.29,
-  132.91, 137.33,
-          138.91, 140.12, 140.91, 144.24, 144.91, 150.36, 151.96,
-          157.25, 158.93, 162.50, 164.93, 167.26, 168.93, 173.04,
-                  174.97, 178.49, 180.95, 183.84, 186.21, 190.23,
-                  192.22, 195.08, 196.97, 200.59,
-                          204.38, 207.20, 208.98, 208.98, 209.99, 222.02,
-  232.02, 226.03,
-          227.03, 232.04, 231.04, 238.03, 237.05, 244.06, 243.06,
-          247.07, 247.07, 251.08, 252.08, 257.10, 258.10, 259.10,
-                  262.11, 263.11, 262.11, 266.12, 264.12, 269.13,
-                  268.14, 272.15, 272.15, 277.00,
-                          289.00, 289.00, 293.00,
-  2.0200, 3.0300
-};
-
-
-realtype const CovalentRadius[nElementNames] = {
-  0.32, 0.93,
-  1.23, 0.90, 0.82, 0.77, 0.75, 0.73, 0.72, 0.71, 
-  1.54, 1.36, 1.18, 1.11, 1.06, 1.02, 0.99, 0.98,
-  2.03, 1.91,
-        1.62, 1.45, 1.34, 1.18, 1.17, 1.17,
-        1.16, 1.15, 1.17, 1.25,
-              1.26, 1.22, 1.20, 1.16, 1.14, 1.12,
-  2.16, 1.91,
-        1.62, 1.45, 1.34, 1.30, 1.27, 1.25,
-        1.25, 1.28, 1.34, 1.48,
-              1.44, 1.41, 1.40, 1.36, 1.33, 1.31,
-  2.35, 1.98,
-        1.69, 1.44, 1.34, 1.30, 1.28, 1.26, 1.27,
-        1.30, 1.34, 1.49, 1.48, 1.47, 1.46, 1.46,
-              1.45, 1.43, 2.50, 2.40, 2.20, 1.65,
-              1.65, 1.64, 1.63, 1.62, 
-                    1.85, 1.61, 1.59, 1.59, 1.58, 1.57,
-  1.56, 1.74,
-        1.56, 1.65, 1.65, 1.42, 1.65, 1.65, 1.65,
-        1.65, 1.65, 1.65, 1.65, 1.65, 1.65, 1.65,
-              1.65, 0.32, 0.10, /**/
-                                0.20, 0.20, 0.20,
-              0.20, 0.20, 0.20, 0.20,
-                    0.20, 0.20, 0.20,
-  0.32, 0.32
-};
-
-
-realtype const VdWaalsRadius[nElementNames] = {
-  1.20, 1.40,
-  1.82, 1.78, 1.74, 1.70, 1.55, 1.52, 1.47, 1.54,
-//      ^^^^  ^^^^   <- only a guess
-  2.27, 1.73, 1.80, 2.10, 1.80, 1.80, 1.75, 1.88,
-//            ^^^^
-  2.75, 2.65,
-//      ^^^^
-        2.55, 2.45, 2.35, 2.20, 1.73, 1.90,
-//      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-        1.75, 1.63, 1.40, 1.39,
-//      ^^^^
-              1.87, 1.86, 1.85, 1.90, 1.85, 2.02,
-//                  ^^^^
-  2.75, 2.65,
-//^^^^  ^^^^
-        2.55, 2.45, 2.35, 2.20, 2.05, 1.90,
-//      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-        1.75, 1.63, 1.72, 1.58,
-//      ^^^^  
-              1.93, 2.17, 2.10, 2.06, 1.98, 2.16,
-//                        ^^^^
-  2.75, 2.75,
-//^^^^  ^^^^
-        2.75, 2.75, 2.75, 2.75, 2.75, 2.75, 2.75,
-//      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-        2.75, 2.75, 2.75, 2.75, 2.75, 2.65, 2.55,
-//      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-              2.45, 2.35, 2.25, 2.15, 2.05, 1.95,
-//            ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-              1.85, 1.75, 1.66, 1.55,
-//            ^^^^
-                    1.96, 2.02, 2.00, 2.00, 2.00, 2.00,
-//                              ^^^^  ^^^^  ^^^^  ^^^^ 
-  2.75, 2.75,
-//^^^^  ^^^^
-        2.50, 2.25, 1.95, 1.86, 1.80, 1.80, 1.80,
-//      ^^^^  ^^^^  ^^^^        ^^^^  ^^^^  ^^^^
-        1.80, 1.80, 1.80, 1.80, 1.80, 1.80, 1.80,
-//      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-              1.80, 1.80, 1.80, 1.80, 1.80, 1.80,
-//            ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
-              1.80, 1.80, 1.80, 1.80,
-//            ^^^^  ^^^^  ^^^^  ^^^^ 
-                          1.80,       1.80,       1.80,
-//                        ^^^^        ^^^^        ^^^^
-  1.30, 1.50
-//^^^^  ^^^^
-};
-
-realtype const IonicRadius[nElementNames] = {
-     0.79, 0.49, 2.05, 1.40, 1.17, 0.91, 0.75, 0.65, 0.57, 0.51, 
-     2.23, 1.72, 1.82, 1.46, 1.23, 1.09, 0.97, 0.88, 2.77, 2.23, 
-     2.09, 2.00, 1.92, 1.85, 1.79, 1.72, 1.67, 1.62, 1.57, 1.53, 
-     1.81, 1.52, 1.33, 1.22, 1.12, 1.03, 2.98, 2.45, 2.27, 2.16, 
-     2.09, 2.01, 1.95, 1.89, 1.83, 1.79, 1.75, 1.71, 2.00, 1.72, 
-     1.53, 1.42, 1.32, 1.24, 3.34, 2.78, 2.74, 2.16, 2.09, 2.02, 
-     1.97, 1.92, 1.87, 1.83, 1.79, 1.76, 2.08, 1.81, 1.63, 1.53, 
-     1.43, 1.34, 3.50, 3.00, 3.20, 2.70, 2.67, 2.64, 2.62, 2.59, 
-     2.56, 2.54, 2.51, 2.49, 2.47, 2.45, 2.42, 2.40, 2.25, 3.16, 
-     3.14, 3.11, 3.08, 3.05, 3.02, 2.99, 2.97, 2.95, 2.92, 2.90, 
-     2.87, 2.85
-};
-
-cpstr const ElementMetal[nElementMetals] = {
-  "LI", "BE", "NA", "MG", "AL", " K", "CA", "SC", "TI", " V",
-  "MN", "FE", "CO", "NI", "CU", "ZN", "GA", "RB", "SR", " Y",
-  "ZR", "NB", "MO", "TC", "RU", "RH", "PD", "AG", "CD", "IN",
-  "SN", "SB", "CS", "BA", "LA", "CE", "PR", "ND", "PM", "SM",
-  "EU", "GD", "TB", "DY", "HO", "ER", "TM", "YB", "LU", "HF",
-  "TA", " W", "RE", "OS", "IR", "PT", "AU", "HG", "TL", "PB",
-  "BI", "PO", "FR", "RA", "AC", "TH", "PA", " U", "NP", "PU",
-  "AM", "CM", "BK", "CF", "ES", "FM", "MD", "NO", "LR", "RF",
-  "DB", "SG", "BH", "HS", "MT", "UN", "UU", "UB", "UQ", "UH",
-  "UO"
-};
-
-
-cpstr const HydAtomName[nHydAtomNames] = {
-  "0H", "1H", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H",
-  "HH", "*H", "'H", """H"
-};
-
-
-
-Boolean isMetal ( cpstr element )  {
-char    name[3];
-Boolean isThere;
-int     i;
-  if (!element[1])  {
-    name[0] = ' ';
-    name[1] = element[0];
-  } else
-    strncpy ( name,element,2 );
-  name[2] = char(0);
-  isThere = False;
-  for (i=0;(i<nElementMetals) && (!isThere);i++)
-    isThere = (!strcmp(ElementMetal[i],name));
-  return isThere;
-}
-
-int  getElementNo ( cpstr element )  {
-int  type=0;
-char El[3];
-  if ((!element[1]) || (element[1]==' '))  {
-    El[0] = ' ';
-    El[1] = element[0];
-  } else  {
-    El[0] = element[0];
-    El[1] = element[1];
-  }
-  El[2] = char(0);
-  UpperCase ( El );
-  while (type<nElementNames)
-    if (!strcmp(El,ElementName[type]))  break;
-                                  else  type++;
-  if (type>=nElementNames)  return ELEMENT_UNKNOWN;
-  return type+1;  // so that hydrogen is 1
-}
-
-realtype  getMolecWeight ( cpstr element )  {
-int  type=0;
-char El[3];
-  if ((!element[1]) || (element[1]==' '))  {
-    El[0] = ' ';
-    El[1] = element[0];
-  } else  {
-    El[0] = element[0];
-    El[1] = element[1];
-  }
-  El[2] = char(0);
-  UpperCase ( El );
-  while (type<nElementNames)
-    if (!strcmp(El,ElementName[type]))  break;
-                                  else  type++;
-  if (type>=nElementNames)  return 1.0;
-  return MolecWeight[type];
-}
-
-realtype  getCovalentRadius ( cpstr element )  {
-int  type=0;
-char El[3];
-  if ((!element[1]) || (element[1]==' '))  {
-    El[0] = ' ';
-    El[1] = element[0];
-  } else  {
-    El[0] = element[0];
-    El[1] = element[1];
-  }
-  El[2] = char(0);
-  UpperCase ( El );
-  while (type<nElementNames)
-    if (!strcmp(El,ElementName[type]))  break;
-                                  else  type++;
-  if (type>=nElementNames)  return 2.2*CovalentRadius[0];
-  return CovalentRadius[type];
-}
-
-realtype  getVdWaalsRadius ( cpstr element )  {
-int  type=0;
-char El[3];
-  if ((!element[1]) || (element[1]==' '))  {
-    El[0] = ' ';
-    El[1] = element[0];
-  } else  {
-    El[0] = element[0];
-    El[1] = element[1];
-  }
-  El[2] = char(0);
-  UpperCase ( El );
-  while (type<nElementNames)
-    if (!strcmp(El,ElementName[type]))  break;
-                                  else  type++;
-  if (type>=nElementNames)  return 1.8;
-  return VdWaalsRadius[type];
-}
-
-cpstr const ResidueName[nResNames] = {
-  "ALA", "ARG", "ASN", "ASP", "CYS", "CYH", "GLN",
-  "GLU", "GLY", "HIS", "ILE", "LEU", "LYS", "MET",
-  "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL",
-  "HEM", "WAT", "SUL", "END", "DUM"
-};
-
-int getResidueNo ( cpstr resName )  {
-int i,m;
-  m = -1;
-  for (i=0;(i<nResNames) && (m<0);i++)
-    if (!strcmp(resName,ResidueName[i]))
-      m = i;
-  return m;
-}
-
-char const ResidueName1[nResNames] = {
-  'A', 'R', 'N', 'D', 'C', 'C', 'Q',
-  'E', 'G', 'H', 'I', 'L', 'K', 'M',
-  'F', 'P', 'S', 'T', 'W', 'Y', 'V',
-  'X', 'O', 'U', 'Z', 'Z'
-};
-
-
-cpstr const StdSolventName[nSolventNames] = {
-  "ADE", "CYT", "GUA", "INO", "THY", "URA",
-  "WAT", "HOH", "TIP", "H2O", "DOD", "MOH"
-};
-
-
-SAAProperty const AAProperty[nAminoacidNames] = {
-  { "ALA",  1.8,  0.0,  0.42 },
-  { "ARG", -4.5,  1.0, -1.37 },
-  { "ASN", -3.5,  0.0, -0.82 },
-  { "ASP", -3.5, -1.0, -1.05 },
-  { "ASX", -3.5, -0.5, -1.05 },  // by analogy
-  { "CYS",  2.5,  0.0,  1.34 },
-  { "CYH",  2.5,  0.0,  1.34 },  // by analogy
-  { "GLN", -3.5,  0.0, -0.30 },
-  { "GLU", -3.5, -1.0, -0.87 },
-  { "GLX", -3.5, -0.5,  0.0  },  // by analogy
-  { "GLY", -0.4,  0.0,  0.0  },
-  { "HIS", -3.2,  0.0,  0.18 },
-  { "ILE",  4.5,  0.0,  2.46 },
-  { "LEU",  3.8,  0.0,  2.32 },
-  { "LYS", -3.9,  1.0, -1.35 },
-  { "MET",  1.9,  0.0,  1.68 },
-  { "PHE",  2.8,  0.0,  2.44 },
-  { "PRO", -1.6,  0.0,  0.98 },
-  { "SER", -0.8,  0.0, -0.05 },
-  { "THR", -0.7,  0.0,  0.35 },
-  { "TRP", -0.9,  0.0,  3.07 },
-  { "TYR", -1.3,  0.0,  1.31 },
-  { "VAL",  4.2,  0.0,  1.66 }
-};
-
-realtype GetAAHydropathy ( cpstr resName )  {
-int  i1,j;
-  i1 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName,AAProperty[j].name))  {
-      i1 = j;
-      break;
-    } else
-      j++;
-  if (i1<0)  return -MaxReal;
-  return AAProperty[i1].hydropathy;
-}
-
-realtype GetAACharge ( cpstr resName )  {
-int  i1,j;
-  i1 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName,AAProperty[j].name))  {
-      i1 = j;
-      break;
-    } else
-      j++;
-  if (i1<0)  return 0.0;
-  return AAProperty[i1].charge;
-}
-
-realtype GetAASolvationEnergy ( cpstr resName )  {
-int  i1,j;
-  i1 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName,AAProperty[j].name))  {
-      i1 = j;
-      break;
-    } else
-      j++;
-  if (i1<0)  return 0.0;
-  return AAProperty[i1].relSolvEnergy;
-}
-
-
-int const AASimilarity[nAminoacidNames][nAminoacidNames] = {
-/*  A A A A A C C G G G G H I L L M P P S T T T V            */
-/*  L R S S S Y Y L L L L I L E Y E H R E H R Y A            */
-/*  A G N P X S H N U X Y S E U S T E O R R P R L            */
-  { 5,0,0,0,0,0,0,0,0,2,2,0,2,2,0,2,2,2,1,1,2,2,2 },  /* ALA */
-  { 0,5,2,2,2,0,0,2,2,0,0,2,0,0,4,0,0,0,0,0,0,0,0 },  /* ARG */
-  { 0,2,5,3,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* ASN */
-  { 0,2,3,5,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* ASP */
-  { 0,2,5,5,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* ASX */
-  { 0,0,0,0,0,5,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },  /* CYS */
-  { 0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },  /* CYH */
-  { 0,2,3,3,3,0,0,5,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* GLN */
-  { 0,2,3,3,3,0,0,3,5,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* GLU */
-  { 2,0,0,0,0,0,0,0,0,5,5,0,1,1,0,1,1,2,0,0,1,1,1 },  /* GLX */
-  { 2,0,0,0,0,0,0,0,0,5,5,0,1,1,0,1,1,2,0,0,1,1,1 },  /* GLY */
-  { 0,2,0,0,0,0,0,0,0,0,0,5,1,1,2,2,2,0,1,1,2,2,1 },  /* HIS */
-  { 2,0,0,0,0,0,0,0,0,1,1,1,5,4,0,4,4,0,0,0,4,4,4 },  /* ILE */
-  { 2,0,0,0,0,0,0,0,0,1,1,1,4,5,0,4,4,0,0,0,4,4,4 },  /* LEU */
-  { 0,4,2,2,2,0,0,2,2,0,0,2,0,0,5,0,0,0,0,0,0,0,0 },  /* LYS */
-  { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,5,4,0,0,0,4,4,4 },  /* MET */
-  { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 },  /* PHE */
-  { 2,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,5,0,0,0,0,0 },  /* PRO */
-  { 1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,5,3,0,0,0 },  /* SER */
-  { 1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,3,5,0,0,0 },  /* THR */
-  { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 },  /* TRP */
-  { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 },  /* TYR */
-  { 2,0,0,0,0,0,0,0,0,1,1,1,4,4,0,4,4,0,0,0,4,4,5 },  /* VAL */
-};
-
-int  GetAAPIndex ( cpstr resName )  {
-// 0..nAminoacidNames-1
-int i,k;
-  k = -1;
-  for (i=0;(i<nAminoacidNames) && (k<0);i++)
-    if (!strcasecmp(resName,AAProperty[i].name))
-      k = i;
-  return k;
-}
-
-
-int  GetAASimilarity ( cpstr resName1, cpstr resName2 )  {
-int  i1,i2,j;
-
-  i1 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName1,AAProperty[j].name))  {
-      i1 = j;
-      break;
-    } else
-      j++;
-  if (i1<0)  return -1;
-
-  i2 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName2,AAProperty[j].name))  {
-      i2 = j;
-      break;
-    } else
-      j++;
-  if (i2<0)  return -2;
-
-  return AASimilarity[i1][i2];
-  
-}
-
-
-
-
-
-/*
-
-
-pstr const AminoacidName[nAminoacidNames] = {
-  "ALA", "ARG", "ASN", "ASP", "ASX", "CYS", "CYH", "GLN",
-  "GLU", "GLX", "GLY", "HIS", "ILE", "LEU", "LYS", "MET",
-  "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL"
-};
-
-
-//    The higher is the hydropathy scale value, the more
-//  hydrophobic the residue is.
-//    Some sources suggest that sure hydrophilic residues
-//  are those with hydropathy scale value less than -1.5,
-//  while sure hydropoobic residues have hydropathy scale
-//  value greater than 0.0.
-//    The scale is after J. Kyte and R. F. Doolittle,
-//  A simple method for displaying the hydropathic character
-//  of a protein, J. Mol. Biol. (1982) 157, 105-132
-realtype const AAHydropathyScale[nAminoacidNames] = {
-    1.8,  -4.5,  -3.5,  -3.5,  -3.5,   2.5,   2.5,  -3.5,
-   -3.5,  -3.5,  -0.4,  -3.2,   4.5,   3.8,  -3.9,   1.9,
-    2.8,  -1.6,  -0.8,  -0.7,  -0.9,  -1.3,   4.2
-};
-
-realtype GetAAHydropathy ( cpstr resName )  {
-int  i1,j;
-  i1 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName,AminoacidName[j]))  {
-      i1 = j;
-      break;
-    } else
-      j++;
-  if (i1<0)  return -MaxReal;
-  return AAHydropathyScale[i1];
-}
-
-//  Acid residues are those with negative charge
-//  Base residues are those with positive charge
-realtype const AACharge[nAminoacidNames] = {
-    0.0,   1.0,   0.0,  -1.0,  -0.5,   0.0,   0.0,   0.0,
-   -1.0,  -0.5,   0.0,   0.0,   0.0,   0.0,   1.0,   0.0,
-    0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0
-};
-
-int  GetAASimilarity ( cpstr resName1, cpstr resName2 )  {
-int  i1,i2,j;
-
-  i1 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName1,AminoacidName[j]))  {
-      i1 = j;
-      break;
-    } else
-      j++;
-  if (i1<0)  return -1;
-
-  i2 = -1;
-  j  = 0;
-  while (j<nAminoacidNames)
-    if (!strcasecmp(resName2,AminoacidName[j]))  {
-      i2 = j;
-      break;
-    } else
-      j++;
-  if (i2<0)  return -2;
-
-  return AASimilarity[i1][i2];
-  
-}
-
-Boolean isAminoacid ( cpstr resName )  {
-Boolean isThere;
-int     i;
-  isThere = False;
-  for (i=0;(i<nAminoacidNames) && (!isThere);i++)
-    isThere = (!strcmp(AminoacidName[i],resName));
-  return isThere;
-}
-
-*/
-
-
-cpstr const NucleotideName[nNucleotideNames] = {
-   "A",  "C",  "G",  "I",   "T",   "U",
-  "+A", "+C", "+G", "+I",  "+T",  "+U",
-  "DA", "DC", "DG", "DI",  "DT",  "DU",
-  "RA", "RC", "RG", "RU", "5NC", "TYD"
-};
-
-
-Boolean isSolvent ( cpstr resName )  {
-Boolean isThere;
-int     i;
-  isThere = False;
-  for (i=0;(i<nSolventNames) && (!isThere);i++)
-    isThere = (!strcmp(StdSolventName[i],resName));
-  return isThere;
-}
-
-Boolean isAminoacid ( cpstr resName )  {
-Boolean isThere;
-int     i;
-  isThere = False;
-  for (i=0;(i<nAminoacidNames) && (!isThere);i++)
-    isThere = (!strcmp(AAProperty[i].name,resName));
-  return isThere;
-}
-
-Boolean isNucleotide ( cpstr resName )  {
-Boolean isThere;
-int     i;
-  isThere = False;
-  for (i=0;(i<nNucleotideNames) && (!isThere);i++)
-    isThere = (!strcmp(NucleotideName[i],resName));
-  return isThere;
-}
-
-int isDNARNA ( cpstr resName )  {
-Boolean isThere;
-int     i;
-  isThere = False;
-  for (i=0;(i<nNucleotideNames) && (!isThere);i++)
-    isThere = (!strcmp(NucleotideName[i],resName));
-  if (!isThere)         return 0;  // neither
-  if (resName[0]=='D')  return 1;  // DNA
-  return 2;                        // RNA
-}
-
-Boolean isSugar ( cpstr resName )  {
-UNUSED_ARGUMENT(resName);
-  return False;
-}
-
-
-cpstr const Res1Code[] = {
-
-  // standard aminoacids
-
-  "ALA A",  // Alanine
-  "ARG R",  // Arginine
-  "ASN N",  // Asparagine
-  "ASP D",  // Aspartic acid (Aspartate)
-  "CYS C",  // Cysteine
-  "GLN Q",  // Glutamine
-  "GLU E",  // Glutamic acid (Glutamate)
-  "GLY G",  // Glycine
-  "HIS H",  // Histidine
-  "ILE I",  // Isoleucine
-  "LEU L",  // Leucine
-  "LYS K",  // Lysine
-  "MET M",  // Methionine
-  "PHE F",  // Phenylalanine
-  "PRO P",  // Proline
-  "SER S",  // Serine
-  "THR T",  // Threonine
-  "TRP W",  // Tryptophan
-  "TYR Y",  // Tyrosine
-  "VAL V",  // Valine
-  "ASX B",  // Aspartic acid or Asparagine
-  "GLX Z",  // Glutamine or Glutamic acid.
-  //  ???     X       Any amino acid.
-
-  // other
-
-  "1PA A",   "1PI A",   "2AS D",   "2ML L",   "2MR R",   "3GA A",
-  "5HP E",   "ACB D",   "ACL R",   "AGM R",   "AHB D",   "ALM A",
-  "ALN A",   "ALO T",   "ALT A",   "ALY K",   "APH A",   "APM A",
-  "AR2 R",   "ARM R",   "ARO R",   "ASA D",   "ASB D",   "ASI D",
-  "ASK D",   "ASL D",   "ASQ D",   "AYA A",   "B1F A",   "B2A A",
-  "B2F A",   "B2I I",   "B2V V",   "BAL A",   "BCS C",   "BFD D",
-  "BHD D",   "BLE L",   "BLY K",   "BNN F",   "BNO L",   "BTA L",
-  "BTC C",   "BTR W",   "BUC C",   "BUG L",   "C5C C",   "C6C C",
-  "CAF C",   "CAS C",   "CAY C",   "CCS C",   "CEA C",   "CGU E",
-  "CHG G",   "CHP G",   "CLB A",   "CLD A",   "CLE L",   "CME C",
-  "CMT C",   "CSB C",   "CSD A",   "CSE C",   "CSO C",   "CSP C",
-  "CSR C",   "CSS C",   "CSW C",   "CSX C",   "CSY C",   "CSZ C",
-  "CTH T",   "CXM M",   "CY1 C",   "CYM C",   "CZZ C",   "DAH F",
-  "DAL A",   "DAM A",   "DAR R",   "DAS D",   "DBY Y",   "DCY C",
-  "DGL E",   "DGN Q",   "DHI H",   "DHN V",   "DIL I",   "DIV V",
-  "DLE L",   "DLY K",   "DNP A",   "DOH D",   "DPH F",   "DPN F",
-  "DPR P",   "DSE S",   "DSN S",   "DSP D",   "DTH T",   "DTR W",
-  "DTY Y",   "DVA V",   "EFC C",   "EHP F",   "EYS C",   "FLA A",
-  "FLE L",   "FME M",   "FTY Y",   "GGL E",   "GHP G",   "GSC G",
-  "GT9 C",   "H5M P",   "HAC A",   "HAR R",   "HIC H",   "HIP H",
-  "HMR R",   "HPH F",   "HPQ F",   "HTR W",   "HV5 A",   "HYP P",
-  "IAS N",   "IIL I",   "ILG Q",   "IML I",   "IN2 K",   "ISO A",
-  "IVA V",   "IYR Y",   "KCX K",   "KPH K",   "LLY K",   "LOL L",
-  "LPL L",   "LTR W",   "LYM K",   "LYZ K",   "M3L K",   "MAA A",
-  "MAI R",   "MEN N",   "MGN Q",   "MGY G",   "MHL L",   "MHO M",
-  "MHS H",   "MIS S",   "MLE L",   "MLY K",   "MLZ K",   "MME M",
-  "MNL L",   "MNV V",   "MPQ G",   "MSE M",   "MSO M",   "MTY Y",
-  "MVA V",   "NAL A",   "NAM A",   "NCY C",   "NEM H",   "NEP H",
-  "NFA F",   "NIT A",   "NLE L",   "NLN L",   "NNH R",   "NPH C",
-  "NVA V",   "OAS S",   "OCS C",   "OCY C",   "OMT M",   "OPR R",
-  "PAQ F",   "PBB C",   "PCA E",   "PEC C",   "PGY G",   "PHA F",
-  "PHD N",   "PHI F",   "PHL F",   "PHM F",   "PLE L",   "POM P",
-  "PPH F",   "PPN F",   "PR3 C",   "PRR A",   "PRS P",   "PTH Y",
-  "PTR Y",   "PYA A",   "RON V",   "S1H S",   "SAC S",   "SAH C",
-  "SAM M",   "SBD A",   "SBL A",   "SCH C",   "SCS C",   "SCY C",
-  "SEB S",   "SEG A",   "SEP S",   "SET S",   "SHC C",   "SHP G",
-  "SLZ K",   "SMC C",   "SME M",   "SNC C",   "SOC C",   "STY Y",
-  "SVA S",   "TBG G",   "TCR W",   "THC T",   "THO T",   "TIH A",
-  "TNB C",   "TPL W",   "TPO T",   "TPQ F",   "TRF W",   "TRG K",
-  "TRN W",   "TRO W",   "TYB Y",   "TYI Y",   "TYN Y",   "TYQ Y",
-  "TYS Y",   "TYY A",   "VAD V",   "VAF V",   "YOF Y",   ""
-
-};
-
-
-void Get1LetterCode ( cpstr res3name, pstr res1code )  {
-char r[4];
-int  i;
-
-  strncpy ( r,res3name,3 );
-  r[3] = char(0);
-  UpperCase ( r );
-  i = 0;
-  res1code[0] = char(1);
-  while (Res1Code[i][0])  {
-    if (Res1Code[i][0]==r[0])  {
-      if (Res1Code[i][1]==r[1])  {
-        if (Res1Code[i][2]==r[2])  {
-          res1code[0] = Res1Code[i][4];
-          break;
-        }
-      }
-    }
-    i++;
-  }
-
-  if (res1code[0]!=char(1))  res1code[1] = char(0);
-  else if (isNucleotide(r))  strcpy ( res1code,r   );
-                       else  strcpy ( res1code,"X" );
-
-}
-
-
-void Get3LetterCode ( cpstr res1name, pstr res3code )  {
-int  i;
-
-  strcpy ( res3code,"XXX" );
-  i = 0;
-  while (Res1Code[i][0])  {
-    if (Res1Code[i][4]==res1name[0])  {
-      res3code[0] = Res1Code[i][0];
-      res3code[1] = Res1Code[i][1];
-      res3code[2] = Res1Code[i][2];
-      break;
-    }
-    i++;
-  }
-
-}
diff --git a/mmdb/mmdb_tables.h b/mmdb/mmdb_tables.h
deleted file mode 100755
index dbc59ab..0000000
--- a/mmdb/mmdb_tables.h
+++ /dev/null
@@ -1,129 +0,0 @@
-//  $Id: mmdb_tables.h,v 1.26 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    04.02.09   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_Tables <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Functions : 
-//       ~~~~~~~~~~~ 
-//
-//  **** Constants : AName  ( array of 2-character atom names       )
-//       ~~~~~~~~~~~ HAName ( array of 2=character heteroatom names )
-//                   RName  ( 3-characters amino acid names         )
-//                   RName1 ( 1-characters amino acid names         )
-//
-//
-//  (C) E. Krissinel  2000-2009
-//
-//  =================================================================
-//
-
-
-#ifndef __MMDB_Tables__
-#define __MMDB_Tables__
-
-
-#ifndef __MatType__
-#include "mattype_.h"
-#endif
-
-
-
-//  =================================================================
-
-
-#define nElementNames  117
-#define nElementMetals 91
-#define nHydAtomNames  14
-
-extern cpstr    const ElementName   [nElementNames];
-extern cpstr    const ElementMetal  [nElementMetals];
-extern cpstr    const HydAtomName   [nHydAtomNames];
-extern realtype const MolecWeight   [nElementNames];
-extern realtype const CovalentRadius[nElementNames];
-extern realtype const VdWaalsRadius [nElementNames];
-extern realtype const IonicRadius   [nElementNames];
-
-extern Boolean isMetal ( cpstr element );
-
-#define  ELEMENT_UNKNOWN    -1
-
-extern int      getElementNo      ( cpstr element );
-extern realtype getMolecWeight    ( cpstr element );
-extern realtype getCovalentRadius ( cpstr element );
-extern realtype getVdWaalsRadius  ( cpstr element );
-
-#define nResNames  26
-
-extern cpstr const ResidueName [nResNames];
-extern char  const ResidueName1[nResNames];
-
-extern int getResidueNo ( cpstr resName );
-
-#define nSolventNames     12
-#define nAminoacidNames   23
-#define nNucleotideNames  24
-
-
-DefineStructure(SAAProperty)
-
-struct SAAProperty  {
-  char     name[4];
-  realtype hydropathy;
-  realtype charge;
-  realtype relSolvEnergy;
-};
-
-extern SAAProperty const AAProperty[nAminoacidNames];
-extern int const AASimilarity[nAminoacidNames][nAminoacidNames];
-
-extern int      GetAAPIndex     ( cpstr resName );  // 0..nAminoacidNames-1
-extern realtype GetAAHydropathy ( cpstr resName );  // -4.5...+4.5
-extern realtype GetAACharge     ( cpstr resName );
-extern realtype GetAASolvationEnergy ( cpstr resName );
-extern int      GetAASimilarity ( cpstr resName1,
-                                  cpstr resName2 );  // 0..5
-
-extern cpstr const StdSolventName[nSolventNames];
-//extern pstr const AminoacidName [nAminoacidNames];
-extern cpstr const NucleotideName[nNucleotideNames];
-
-extern Boolean isSolvent    ( cpstr resName );
-extern Boolean isAminoacid  ( cpstr resName );
-extern Boolean isNucleotide ( cpstr resName );
-extern int     isDNARNA     ( cpstr resName ); // 0,1(DNA),2(RNA)
-extern Boolean isSugar      ( cpstr resName );
-
-extern void  Get1LetterCode ( cpstr res3name, pstr res1code );
-extern void  Get3LetterCode ( cpstr res1name, pstr res3code );
-
-
-#endif
-
diff --git a/mmdb/mmdb_title.cpp b/mmdb/mmdb_title.cpp
deleted file mode 100755
index 1d83f80..0000000
--- a/mmdb/mmdb_title.cpp
+++ /dev/null
@@ -1,2653 +0,0 @@
-//  $Id: mmdb_title.cpp,v 1.26 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    23.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Title  <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CTitleContainer  (container for title classes)
-//       ~~~~~~~~~  CObsLine
-//                  CTitleLine
-//                  CCaveat
-//                  CCompound
-//                  CSource
-//                  CKeyWords
-//                  CExpData
-//                  CMdlType
-//                  CAuthor
-//                  CRevData
-//                  CSupersede
-//                  CJournal
-//                  CRemark
-//                  CBiomolecule
-//                  CMMDBTitle  ( MMDB title section )
-//
-//  (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MMDB_Title__
-#include "mmdb_title.h"
-#endif
-
-#ifndef  __MMDB_CIFDefs__
-#include "mmdb_cifdefs.h"
-#endif
-
-
-//  ==============  CTitleContainer  ====================
-
-PCContainerClass CTitleContainer::MakeContainerClass ( int ClassID )  {
-  switch (ClassID)  {
-    default :
-    case ClassID_Template  : return
-                         CClassContainer::MakeContainerClass(ClassID);
-    case ClassID_ObsLine   : return new CObsLine  ();
-    case ClassID_CAVEAT    : return new CCaveat   ();
-    case ClassID_TitleLine : return new CTitleLine();
-    case ClassID_Compound  : return new CCompound ();
-    case ClassID_Source    : return new CSource   ();
-    case ClassID_ExpData   : return new CExpData  ();
-    case ClassID_Author    : return new CAuthor   ();
-    case ClassID_RevData   : return new CRevData  ();
-    case ClassID_Supersede : return new CSupersede();
-    case ClassID_Journal   : return new CJournal  ();
-    case ClassID_Remark    : return new CRemark   ();
-  }
-}
-
-MakeStreamFunctions(CTitleContainer)
-
-
-//  ================  CObsLine  ===================
-
-CObsLine::CObsLine() : CContainerClass()  {
-  InitObsLine();
-}
-
-CObsLine::CObsLine ( cpstr S ) : CContainerClass()  {
-  InitObsLine();
-  ConvertPDBASCII ( S );
-}
-
-CObsLine::CObsLine ( RPCStream Object ) : CContainerClass(Object)  {
-  InitObsLine();
-}
-
-CObsLine::~CObsLine() {}
-
-void  CObsLine::InitObsLine()  {
-int i;
-  strcpy ( repDate,"DD-MMM-YYYY" );
-  strcpy ( idCode, "----" );
-  for (i=0;i<8;i++)
-    strcpy ( rIdCode[i],"    " );
-}
-
-void  CObsLine::PDBASCIIDump ( pstr S, int N )  {
-//  makes the ASCII PDB OBSLTE line number N
-//  from the class' data
-int i;
-  if (N==0)  strcpy  ( S,"OBSLTE    " );
-       else  sprintf ( S,"OBSLTE  %2i",N+1 );
-  PadSpaces ( S,80 );
-  Date11to9 ( repDate,&(S[11]) );
-  strncpy   ( &(S[21]),idCode,4 );
-  for (i=0;i<8;i++)
-    strncpy ( &(S[31+5*i]),rIdCode[i],4 );
-}
-
-void  CObsLine::MakeCIF ( PCMMCIFData CIF, int )  {
-PCMMCIFLoop Loop;
-int         RC,i,j;
-char        DateCIF[20];
-  RC = CIF->AddLoop ( CIFCAT_OBSLTE,Loop );
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, provide tags
-    Loop->AddLoopTag ( CIFTAG_ID             );
-    Loop->AddLoopTag ( CIFTAG_DATE           );
-    Loop->AddLoopTag ( CIFTAG_REPLACE_PDB_ID );
-    Loop->AddLoopTag ( CIFTAG_PDB_ID         );
-  }
-  Date11toCIF ( repDate,DateCIF );
-  for (i=0;i<8;i++)  {
-    j = 0;
-    while (rIdCode[i][j] && (rIdCode[i][j]==' '))  j++;
-    if (rIdCode[i][j])  {
-      Loop->AddString ( pstr("OBSLTE") );
-      Loop->AddString ( DateCIF    );
-      Loop->AddString ( idCode     );
-      Loop->AddString ( rIdCode[i] );
-    }
-  }
-}
-
-int CObsLine::ConvertPDBASCII ( cpstr S )  {
-int i;
-  Date9to11 ( &(S[11]),repDate );
-  strncpy   ( idCode,&(S[21]),4 );
-  idCode[4] = char(0);
-  for (i=0;i<8;i++)  {
-    strncpy ( rIdCode[i],&(S[31+i*5]),4 );
-    rIdCode[i][4] = char(0);
-  }
-  return 0;
-}
-
-void  CObsLine::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-int         i,RC;
-pstr        F,FDate,FID;
-char        DateCIF [20];
-char        DateCIF0[20];
-IDCode      idCode1;
-  Loop = CIF->GetLoop ( CIFCAT_OBSLTE );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-  i = 0;
-  do  {
-    F = Loop->GetString ( CIFTAG_ID,Signal,RC );
-    if (RC)  {
-      if (i==0)  Signal = -1;
-      return;
-    }
-    if (F)  {
-      if (!strcmp(F,"OBSLTE"))  {
-        FDate = Loop->GetString ( CIFTAG_DATE,Signal,RC );
-        if ((!RC) && FDate)
-              strncpy ( DateCIF,FDate,15 );
-        else  strcpy  ( DateCIF,"YYYY-MMM-DD" );
-        FID = Loop->GetString ( CIFTAG_REPLACE_PDB_ID,Signal,RC );
-        if ((!RC) && FID)
-              strncpy ( idCode1,FID,sizeof(IDCode)-1 );
-        else  idCode1[0] = char(0);
-        if (i==0)  {
-          DateCIFto11 ( DateCIF,repDate );
-          DateCIF[11] = char(0);
-          strcpy ( idCode  ,idCode1 );
-          strcpy ( DateCIF0,DateCIF );
-        } else if ((strcmp(DateCIF0,DateCIF)) ||
-                   (strcmp(idCode,idCode1)))
-          return;
-        FID = Loop->GetString ( CIFTAG_PDB_ID,Signal,RC );
-        if ((!RC) && FID)
-             strncpy ( rIdCode[i],FID,sizeof(IDCode)-1 );
-        else rIdCode[i][0] = char(0);
-        Loop->DeleteField ( CIFTAG_ID            ,Signal );
-        Loop->DeleteField ( CIFTAG_DATE          ,Signal );
-        Loop->DeleteField ( CIFTAG_REPLACE_PDB_ID,Signal );
-        Loop->DeleteField ( CIFTAG_PDB_ID        ,Signal );
-        i++;
-      }
-    }
-    Signal++;
-  } while (i<8);
-}
-
-void  CObsLine::Copy ( PCContainerClass ObsLine )  {
-int i;
-  strcpy ( repDate,PCObsLine(ObsLine)->repDate );
-  strcpy ( idCode ,PCObsLine(ObsLine)->idCode  );
-  for (i=0;i<8;i++)
-    strcpy ( rIdCode[i],PCObsLine(ObsLine)->rIdCode[i] );
-}
-
-void  CObsLine::write ( RCFile f )  {
-int  i;
-byte Version=1;
- f.WriteByte    ( &Version      );
- f.WriteTerLine ( repDate,False );
- f.WriteTerLine ( idCode ,False );
- for (i=0;i<8;i++)
-   f.WriteTerLine ( rIdCode[i],False );
-}
-
-void  CObsLine::read  ( RCFile f ) {
-int  i;
-byte Version;
- f.ReadByte    ( &Version      );
- f.ReadTerLine ( repDate,False );
- f.ReadTerLine ( idCode ,False );
- for (i=0;i<8;i++)
-   f.ReadTerLine ( rIdCode[i],False );
-}
-
-MakeStreamFunctions(CObsLine)
-
-
-//  ===================  CTitleLine  ======================
-
-CTitleLine::CTitleLine() : CContString()  {
-  InitTitleLine();
-}
-
-CTitleLine::CTitleLine ( cpstr S ) : CContString()  {
-  InitTitleLine();
-  ConvertPDBASCII ( S );
-}
-
-CTitleLine::CTitleLine ( RPCStream Object ) : CContString(Object)  {
-  InitTitleLine();
-}
-
-CTitleLine::~CTitleLine() {
-}
-
-void  CTitleLine::InitTitleLine()  {
-  CreateCopy ( CIFCategory,CIFCAT_STRUCT );
-  CreateCopy ( CIFTag,     CIFTAG_TITLE  );
-}
-
-int  CTitleLine::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10]) );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CTitleLine::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"TITLE     " );
-       else  sprintf ( S,"TITLE   %2i",N+1 );
-  strcat ( S,Line );
-}
-
-void  CTitleLine::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CTitleLine::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CTitleLine)
-
-
-
-//  ===================  CCaveat  ======================
-
-CCaveat::CCaveat() : CContString()  {
-  InitCaveat();
-}
-
-CCaveat::CCaveat ( cpstr S ) : CContString()  {
-  InitCaveat();
-  ConvertPDBASCII ( S );
-}
-
-CCaveat::CCaveat ( RPCStream Object ) : CContString(Object)  {
-  InitCaveat();
-}
-
-CCaveat::~CCaveat() {}
-
-void  CCaveat::InitCaveat()  {
-  strcpy ( idCode,"----" );
-  CreateCopy ( CIFCategory,CIFCAT_DATABASE_PDB_CAVEAT );
-  CreateCopy ( CIFTag     ,CIFTAG_TEXT                );
-}
-
-int  CCaveat::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>12)  {
-    strncpy ( idCode,&(S[11]),4 );
-    idCode[4] = char(0);
-    if (strlen(S)>19)
-          CreateCopy ( Line,&(S[19])  );
-    else  CreateCopy ( Line,pstr(" ") );
-  } else
-    CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CCaveat::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"CAVEAT     " );
-       else  sprintf ( S,"CAVEAT  %2i ",N+1 );
-  strcat ( S,idCode );
-  strcat ( S,"    " );
-  strcat ( S,Line   );
-}
-
-void  CCaveat::MakeCIF ( PCMMCIFData CIF, int N )  {
-char S[500];
-  CIF->PutString ( idCode,CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID,False );
-  strcpy  ( S,"\n" );
-  strncat ( S,Line,sizeof(S)-2 );
-  S[sizeof(S)-1] = char(0);
-  CIF->PutString ( S,CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_TEXT,(N!=0) );
-}
-
-void  CCaveat::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-pstr F;
-int RC;
-  F = CIF->GetString ( CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID,RC );
-  if ((!RC) && F)  {
-    strncpy ( idCode,F,sizeof(IDCode) );
-    idCode[sizeof(IDCode)-1] = char(0);
-  }
-  CContString::GetCIF ( CIF,Signal );
-  if (Signal<0)
-    CIF->DeleteField ( CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID );
-}
-
-void  CCaveat::Copy ( PCContainerClass Caveat )  {
-  strcpy ( idCode,PCCaveat(Caveat)->idCode );
-  CContString::Copy ( Caveat );
-}
-
-void  CCaveat::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte    ( &Version     );
-  f.WriteTerLine ( idCode,False );
-  CContString::write ( f );
-}
-
-void  CCaveat::read ( RCFile f )  {
-byte Version;
-  f.ReadByte    ( &Version     );
-  f.ReadTerLine ( idCode,False );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CCaveat)
-
-
-
-//  ===================  CCompound  ======================
-
-CCompound::CCompound() : CContString()  {
-  InitCompound();
-}
-
-CCompound::CCompound ( cpstr S ) : CContString()  {
-  InitCompound();
-  ConvertPDBASCII ( S );
-}
-
-CCompound::CCompound ( RPCStream Object ) : CContString(Object)  {
-  InitCompound();
-}
-
-CCompound::~CCompound() {}
-
-void  CCompound::InitCompound()  {
-  CreateCopy ( CIFCategory,CIFCAT_STRUCT         );
-  CreateCopy ( CIFTag     ,CIFTAG_NDB_DESCRIPTOR );
-}
-
-int  CCompound::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10])  );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CCompound::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"COMPND    " );
-       else  sprintf ( S,"COMPND  %2i",N+1 );
-  strcat ( S,Line );
-}
-
-void  CCompound::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CCompound::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CCompound)
-
-
-
-//  ===================  CSource  ======================
-
-CSource::CSource() : CContString()  {
-  InitSource();
-}
-
-CSource::CSource ( cpstr S ) : CContString()  {
-  InitSource();
-  ConvertPDBASCII ( S );
-}
-
-CSource::CSource ( RPCStream Object ) : CContString(Object)  {
-  InitSource();
-}
-
-CSource::~CSource() {}
-
-void  CSource::InitSource()  {
-  CreateCopy ( CIFCategory,CIFCAT_STRUCT );
-  CreateCopy ( CIFTag     ,CIFTAG_SOURCE );
-}
-
-int  CSource::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10])  );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CSource::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"SOURCE    " );
-       else  sprintf ( S,"SOURCE  %2i",N+1 );
-  strcat ( S,Line );
-}
-
-void  CSource::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CSource::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CSource)
-
-
-//  ===================  CKeyWords  ======================
-
-CKeyWords::CKeyWords() : CStream()  {
-  Init();
-}
-
-CKeyWords::CKeyWords ( cpstr S ) : CStream()  {
-  Init();
-  ConvertPDBASCII ( S );
-}
-
-CKeyWords::CKeyWords ( RPCStream Object ) : CStream(Object)  {
-  Init();
-}
-
-CKeyWords::~CKeyWords()  {
-  Delete();
-}
-
-void  CKeyWords::Init()  {
-  nKeyWords = 0;
-  KeyWord   = NULL;
-  Cont      = False;
-}
-
-void  CKeyWords::Delete()  {
-int i;
-  if (KeyWord)  {
-    for (i=0;i<nKeyWords;i++)
-      if (KeyWord[i])
-        delete[] KeyWord[i];
-    delete[] KeyWord;
-  }
-  nKeyWords = 0;
-  KeyWord   = NULL;
-  Cont      = False;
-}
-
-int  CKeyWords::ConvertPDBASCII ( cpstr S )  {
-//  we anticipate that length of S is 80 characters
-//  -- pad with spaces if necessary
-char   L[85];
-int    i,k,m;
-pstr * KW;
-
-  i = 10;  // scan PDB line from ith character
-
-  k = nKeyWords;
-  if (!Cont)  k++;  // 1st keyword does not continue from previous line
-  m = 0;
-  while (S[i] && (i<70))  {
-    if (S[i]==',')  k++;  // count keywords
-    if (S[i]!=' ')  m++;  // count non-spaces to see if the line is empty
-    i++;
-  }
-
-  if (m==0)  return 0;    //  empty line
-
-  KW = new pstr[k];
-  if (KeyWord)  {
-    for (i=0;i<nKeyWords;i++)
-      KW[i] = KeyWord[i];
-    delete[] KeyWord;
-  }
-  for (i=nKeyWords;i<k;i++)
-    KW[i] = NULL;       // null new pointers
-  KeyWord = KW;
-
-  i = 10;
-  if (Cont)  nKeyWords--;
-  while (S[i] && (i<70))  {
-    while ((S[i]==' ') && (i<70))  i++;  // skip leading spaces
-    if (Cont)  {
-      strcpy ( L," " );
-      m = 1;
-    } else
-      m = 0;
-    while (S[i] && (S[i]!=',') && (i<70))
-      L[m++] = S[i++];
-    m--;
-    while ((m>0) && (L[m]==' '))  m--;  // remove padding spaces
-    m++;
-    L[m] = char(0);
-    if (Cont)  CreateConcat ( KeyWord[nKeyWords],L );
-         else  CreateCopy   ( KeyWord[nKeyWords],L );
-    if (S[i]==',')  {
-      i++;
-      Cont = False;
-    } else
-      Cont = True;
-    nKeyWords++;
-  }
-
-  return 0;
-
-}
-
-void  CKeyWords::PDBASCIIDump ( RCFile f )  {
-int  N,i,k,m1,m2,ms;
-char S[85];
-char c;
-  if (KeyWord)  {
-    N = 0;
-    i = 0;
-    while (i<nKeyWords)  {
-      if (N==0)  strcpy  ( S,"KEYWDS    " );
-           else  sprintf ( S,"KEYWDS  %2i ",N+1 );
-      do  {
-        while ((i<nKeyWords) && (!KeyWord[i]))  i++;
-        if (i<nKeyWords) {
-          m1 = 0;
-          while (KeyWord[i][m1])  {
-            while (KeyWord[i][m1]==' ')  m1++;
-            m2 = m1;
-            ms = -1;
-            while ((KeyWord[i][m2]) && ((m2-m1)<58))  {
-              if (KeyWord[i][m2]==' ')  ms = m2;
-              m2++;
-            }
-            if ((ms<0) || ((m2-m1)<58))  ms = m2;
-            c = KeyWord[i][ms];
-            KeyWord[i][ms] = char(0);
-            strcat ( S,&(KeyWord[i][m1]) );
-            KeyWord[i][ms] = c;
-            m1 = ms;
-            if (c)  {
-              PadSpaces   ( S,80 );
-              f.WriteLine ( S );
-              N++;
-              sprintf ( S,"KEYWDS  %2i ",N+1 );
-            }
-          }
-          i++;
-          if (i<nKeyWords)  {
-            k = strlen(S) + strlen(KeyWord[i]) + 2;
-            if (i<nKeyWords)
-              strcat ( S,", " );
-          } else
-            k = 80;
-        } else
-          k = 80;
-      } while (k<70);
-      PadSpaces   ( S,80 );
-      f.WriteLine ( S );
-      N++;
-    }
-  }
-}
-
-void  CKeyWords::MakeCIF ( PCMMCIFData CIF )  {
-int  i,k;
-char S[500];
-  strcpy ( S,"\n" );
-  for (i=0;i<nKeyWords;i++)
-    if (KeyWord[i])  {
-      k = strlen(KeyWord[i]);
-      if (strlen(S)+k>70)  {
-        CIF->PutString ( S,CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,True );
-        if (k>(int)sizeof(S))  {
-          CIF->PutString ( KeyWord[i],CIFCAT_STRUCT_KEYWORDS,
-                           CIFTAG_TEXT,True );
-          k = 0;
-        }
-        strcpy ( S,"\n" );
-      }
-      if (k>0) {
-        strcat ( S,KeyWord[i] );
-        if (i<nKeyWords-1)  strcat ( S,", " );
-      }
-    }
-  if (strlen(S)>1)
-    CIF->PutString ( S,CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,True );
-}
-
-void  CKeyWords::GetCIF ( PCMMCIFData CIF )  {
-pstr    F;
-int     i,j,k;
-Boolean NB;
-char    c;
-  Delete();
-  F = CIF->GetString ( CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,i );
-  k = 0;
-  if ((!i) && F)  {
-    i  = 0;
-    NB = False;
-    while (F[i])  {
-      if (F[i]==',')  {
-        nKeyWords++;
-        NB = False;
-      } else if (F[i]!=' ')
-        NB = True;
-      i++;
-    }
-    if (NB)  nKeyWords++;
-    KeyWord = new pstr[nKeyWords];
-    i = 0;
-    while (F[i] && (k<nKeyWords))  {
-      while ((F[i]==' ') || (F[i]=='\n') || (F[i]=='\r'))  i++;
-      j = i;
-      while (F[i] && (F[i]!=','))  i++;
-      c    = F[i];
-      F[i] = char(0);
-      KeyWord[k] = NULL;
-      CreateCopy ( KeyWord[k],&(F[j]) );
-      j = 0;
-      while (KeyWord[k][j])  {
-        if ((KeyWord[k][j]=='\n') || (KeyWord[k][j]=='\r'))
-          KeyWord[k][j] = ' ';
-        j++;
-      }
-      F[i] = c;
-      k++;
-      if (F[i])  i++;
-    }
-  }
-  while (k<nKeyWords)  KeyWord[k++] = NULL;
-  CIF->DeleteField ( CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT );
-}
-
-
-void  CKeyWords::Copy ( PCKeyWords KeyWords )  {
-int i;
-  Delete();
-  nKeyWords = KeyWords->nKeyWords;
-  if (nKeyWords>0)  {
-    KeyWord = new pstr[nKeyWords];
-    for (i=0;i<nKeyWords;i++)  {
-      KeyWord[i] = NULL;
-      CreateCopy ( KeyWord[i],KeyWords->KeyWord[i] );
-    }
-  }
-}
-
-void  CKeyWords::write ( RCFile f )  {
-int i;
-byte Version=1;
-  f.WriteByte ( &Version   );
-  f.WriteInt  ( &nKeyWords );
-  for (i=0;i<nKeyWords;i++)
-    f.CreateWrite ( KeyWord[i] );
-}
-
-void  CKeyWords::read ( RCFile f )  {
-int  i;
-byte Version;
-  Delete();
-  f.ReadByte ( &Version   );
-  f.ReadInt  ( &nKeyWords );
-  if (nKeyWords>0)  {
-    KeyWord = new pstr[nKeyWords];
-    for (i=0;i<nKeyWords;i++)  {
-      KeyWord[i] = NULL;
-      f.CreateRead ( KeyWord[i] );
-    }
-  }
-}
-
-MakeStreamFunctions(CKeyWords)
-
-
-//  ===================  CExpData  ======================
-
-CExpData::CExpData() : CContString()  {
-  InitExpData();
-}
-
-CExpData::CExpData ( cpstr S ) : CContString()  {
-  InitExpData();
-  ConvertPDBASCII ( S );
-}
-
-CExpData::CExpData ( RPCStream Object ) : CContString(Object)  {
-  InitExpData();
-}
-
-CExpData::~CExpData() {}
-
-void  CExpData::InitExpData()  {
-  CreateCopy ( CIFCategory,CIFCAT_EXPTL  );
-  CreateCopy ( CIFTag     ,CIFTAG_METHOD );
-}
-
-int  CExpData::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10])  );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CExpData::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"EXPDTA    " );
-       else  sprintf ( S,"EXPDTA  %2i",N+1 );
-  strcat ( S,Line );
-}
-
-void  CExpData::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CExpData::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CExpData)
-
-
-
-
-//  ===================  CMdlType  ======================
-
-CMdlType::CMdlType() : CContString()  {
-  InitMdlType();
-}
-
-CMdlType::CMdlType ( cpstr S ) : CContString()  {
-  InitMdlType();
-  ConvertPDBASCII ( S );
-}
-
-CMdlType::CMdlType ( RPCStream Object ) : CContString(Object)  {
-  InitMdlType();
-}
-
-CMdlType::~CMdlType() {}
-
-void  CMdlType::InitMdlType()  {
-  CreateCopy ( CIFCategory,CIFCAT_EXPTL  );
-  CreateCopy ( CIFTag     ,CIFTAG_METHOD );
-}
-
-int  CMdlType::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10])  );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CMdlType::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"MDLTYP    " );
-       else  sprintf ( S,"MDLTYP  %2i",N+1 );
-  strcat ( S,Line );
-}
-
-void  CMdlType::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CMdlType::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CMdlType)
-
-
-//  ===================  CAuthor  ======================
-
-CAuthor::CAuthor() : CContString()  {
-  InitAuthor();
-}
-
-CAuthor::CAuthor ( cpstr S ) : CContString()  {
-  InitAuthor();
-  ConvertPDBASCII ( S );
-}
-
-CAuthor::CAuthor ( RPCStream Object ) : CContString(Object)  {
-  InitAuthor();
-}
-
-CAuthor::~CAuthor() {}
-
-void  CAuthor::InitAuthor()  {
-  CreateCopy ( CIFCategory,CIFCAT_AUDIT_AUTHOR );
-  CreateCopy ( CIFTag     ,CIFTAG_NAME         );
-}
-
-int  CAuthor::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10])  );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CAuthor::PDBASCIIDump ( pstr S, int N )  {
-  if (N==0)  strcpy  ( S,"AUTHOR    " );
-       else  sprintf ( S,"AUTHOR  %2i",N+1 );
-  strcat ( S,Line );
-}
-
-void  CAuthor::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CAuthor::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CAuthor)
-
-
-
-//  ================  CRevData  ===================
-
-CRevData::CRevData() : CContainerClass()  {
-  InitRevData();
-}
-
-CRevData::CRevData ( cpstr S ) : CContainerClass()  {
-  InitRevData();
-  ConvertPDBASCII ( S );
-}
-
-CRevData::CRevData ( RPCStream Object ) : CContainerClass(Object)  {
-  InitRevData();
-}
-
-CRevData::~CRevData() {}
-
-void  CRevData::InitRevData()  {
-int i;
-  modNum  = 0;
-  strcpy ( modDate,"DD-MMM-YYYY" );
-  strcpy ( modId  , "----" );
-  modType = -1;
-  for (i=0;i<4;i++)
-    strcpy ( record[i],"      " );
-  Warning = 0;
-}
-
-void  CRevData::PDBASCIIDump ( pstr S, int N )  {
-//  makes the ASCII PDB REVDATA line number N
-//  from the class' data
-int i;
-  if (N==0)  sprintf ( S,"REVDAT %3i  " ,modNum     );
-       else  sprintf ( S,"REVDAT %3i%2i",modNum,N+1 );
-  i = strlen(S);
-  while (i<80)
-    S[i++] = ' ';
-  S[i] = char(0);
-  Date11to9 ( modDate,&(S[13]) );
-  strncpy   ( &(S[23]),modId,5 );
-  S[31] = char(modType+int('0'));
-  for (i=0;i<4;i++)
-    strncpy ( &(S[39+i*7]),record[i],6 );
-}
-
-void CRevData::MakeCIF ( PCMMCIFData CIF, int N )  {
-PCMMCIFLoop Loop;
-int         RC,i,j;
-char        DateCIF[20];
-  RC = CIF->AddLoop ( CIFCAT_DATABASE_PDB_REV,Loop );
-  if ((RC!=CIFRC_Ok) || (N==0))  {
-    // the category was (re)created, privide tags
-    Loop->AddLoopTag ( CIFTAG_NUM                   );
-    Loop->AddLoopTag ( CIFTAG_DATE                  );
-    Loop->AddLoopTag ( CIFTAG_REPLACES              );
-    Loop->AddLoopTag ( CIFTAG_MOD_TYPE              );
-    Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_1 );
-    Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_2 );
-    Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_3 );
-    Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_4 );
-  }
-  Date11toCIF ( modDate,DateCIF );
-  Loop->AddInteger ( modNum  );
-  Loop->AddString  ( DateCIF );
-  Loop->AddString  ( modId   );
-  Loop->AddInteger ( modType );
-  for (i=0;i<4;i++)  {
-    j = 0;
-    while (record[i][j] && (record[i][j]==' '))  j++;
-    if (record[i][j])  Loop->AddString ( record[i] );
-                 else  Loop->AddString ( NULL      );
-  }
-
-}
-
-void CRevData::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-int         RC;
-pstr        F;
-
-  Loop = CIF->GetLoop ( CIFCAT_DATABASE_PDB_REV );
-  if (!Loop)  {
-    Signal = -1;
-    return;
-  }
-
-  RC = Loop->GetInteger ( modNum,CIFTAG_NUM,Signal,True );
-  if (RC==CIFRC_WrongIndex)  {
-    Signal = -1;
-    return;
-  }
-  if (RC==CIFRC_WrongFormat)  {
-    sprintf ( CIFErrorLocation,"loop %s.%s row %i",
-              CIFCAT_DATABASE_PDB_REV,CIFTAG_NUM,Signal );
-    Signal = -Error_UnrecognizedInteger-1;
-    return;
-  }
-
-  F = Loop->GetString ( CIFTAG_DATE,Signal,RC );
-  if ((!RC) && F)  DateCIFto11 ( F,modDate );
-  F = Loop->GetString ( CIFTAG_REPLACES,Signal,RC );
-  if ((!RC) && F)  strcpy ( modId,F );
-  RC = Loop->GetInteger ( modType,CIFTAG_MOD_TYPE,Signal,True );
-  if (RC==CIFRC_WrongFormat)  {
-    sprintf ( CIFErrorLocation,"loop %s.%s row %i",
-              CIFCAT_DATABASE_PDB_REV,CIFTAG_MOD_TYPE,Signal );
-    Signal = -Error_UnrecognizedInteger-1;
-    return;
-  }
-
-  F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_1,Signal,RC );
-  if ((!RC) && F)  strcpy ( record[0],F );
-  F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_2,Signal,RC );
-  if ((!RC) && F)  strcpy ( record[1],F );
-  F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_3,Signal,RC );
-  if ((!RC) && F)  strcpy ( record[2],F );
-  F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_4,Signal,RC );
-  if ((!RC) && F)  strcpy ( record[3],F );
-
-  Loop->DeleteField ( CIFTAG_DATE                 ,Signal );
-  Loop->DeleteField ( CIFTAG_REPLACES             ,Signal );
-  Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_1,Signal );
-  Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_2,Signal );
-  Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_3,Signal );
-  Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_4,Signal );
-
-  Signal++;
-
-}
-
-int CRevData::ConvertPDBASCII ( cpstr S )  {
-int  i;
-pstr endptr;
-char N[20];
-  Warning = 0;
-  strncpy   ( N,&(S[7]),3 );
-  N[3]    = char(0);
-  modNum  = mround(strtod(N,&endptr));
-  if (endptr==N)  Warning |= REVDAT_WARN_MODNUM;
-  Date9to11 ( &(S[13]),modDate );
-  strncpy   ( modId,&(S[23]),5 );
-  modId[5] = char(0);
-  modType  = int(S[31]) - int('0');
-  if (modType>9)  Warning |= REVDAT_WARN_MODTYPE;
-  for (i=0;i<4;i++)  {
-    strncpy ( record[i],&(S[39+i*7]),6 );
-    record[i][6] = char(0);
-  }
-  return 0;
-}
-
-void  CRevData::Copy ( PCContainerClass RevData )  {
-int i;
-  modNum  = PCRevData(RevData)->modNum;
-  modType = PCRevData(RevData)->modType;
-  strcpy ( modDate,PCRevData(RevData)->modDate );
-  strcpy ( modId  ,PCRevData(RevData)->modId   );
-  for (i=0;i<4;i++)
-    strcpy ( record[i],PCRevData(RevData)->record[i] );
-}
-
-void  CRevData::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte  ( &Version );
-  f.WriteInt   ( &modNum  );
-  f.WriteInt   ( &modType );
-  f.WriteWord  ( &Warning );
-  f.WriteTerLine ( modDate,False );
-  f.WriteTerLine ( modId  ,False );
-  for (i=0;i<4;i++)
-    f.WriteTerLine ( record[i],False );
-}
-
-void  CRevData::read  ( RCFile f ) {
-int  i;
-byte Version;
-  f.ReadByte  ( &Version );
-  f.ReadInt   ( &modNum  );
-  f.ReadInt   ( &modType );
-  f.ReadWord  ( &Warning );
-  f.ReadTerLine ( modDate,False );
-  f.ReadTerLine ( modId  ,False );
-  for (i=0;i<4;i++)
-    f.ReadTerLine ( record[i],False );
-}
-
-MakeStreamFunctions(CRevData)
-
-
-
-//  ================  CSupersede  ===================
-
-CSupersede::CSupersede() : CContainerClass()  {
-  InitSupersede();
-}
-
-CSupersede::CSupersede ( cpstr S ) : CContainerClass()  {
-  InitSupersede();
-  ConvertPDBASCII ( S );
-}
-
-CSupersede::CSupersede ( RPCStream Object ) : CContainerClass(Object)  {
-  InitSupersede();
-}
-
-CSupersede::~CSupersede() {}
-
-void  CSupersede::InitSupersede()  {
-int i;
-  strcpy ( sprsdeDate,"DD-MMM-YYYY" );
-  strcpy ( idCode, "----" );
-  for (i=0;i<8;i++)
-    strcpy ( sIdCode[i],"    " );
-}
-
-void  CSupersede::PDBASCIIDump ( pstr S, int N )  {
-//  makes the ASCII PDB OBSLTE line number N
-//  from the class' data
-int i;
-  if (N==0)  strcpy  ( S,"SPRSDE    " );
-       else  sprintf ( S,"SPRSDE  %2i",N+1 );
-  i = strlen(S);
-  while (i<80)
-    S[i++] = ' ';
-  S[i] = char(0);
-  if (N==0)  {
-    Date11to9 ( sprsdeDate,&(S[11]) );
-    strncpy   ( &(S[21]),idCode,4 );
-  }
-  for (i=0;i<8;i++)
-    strncpy ( &(S[31+5*i]),sIdCode[i],4 );
-}
-
-void  CSupersede::MakeCIF ( PCMMCIFData CIF, int )  {
-PCMMCIFLoop Loop;
-int         RC,i,j;
-char        DateCIF[20];
-  RC = CIF->AddLoop ( CIFCAT_SPRSDE,Loop );
-  if (RC!=CIFRC_Ok)  {
-    // the category was (re)created, privide tags
-    Loop->AddLoopTag ( CIFTAG_ID             );
-    Loop->AddLoopTag ( CIFTAG_DATE           );
-    Loop->AddLoopTag ( CIFTAG_REPLACE_PDB_ID );
-    Loop->AddLoopTag ( CIFTAG_PDB_ID         );
-  }
-  Date11toCIF ( sprsdeDate,DateCIF );
-  for (i=0;i<8;i++)  {
-    j = 0;
-    while (sIdCode[i][j] && (sIdCode[i][j]==' '))  j++;
-    if (sIdCode[i][j])  {
-      Loop->AddString ( pstr("SPRSDE") );
-      Loop->AddString ( DateCIF    );
-      Loop->AddString ( idCode     );
-      Loop->AddString ( sIdCode[i] );
-    }
-  }
-}
-
-int CSupersede::ConvertPDBASCII ( cpstr S )  {
-int i;
-  if (S[9]==' ')  {
-    Date9to11 ( &(S[11]),sprsdeDate );
-    strncpy   ( idCode,&(S[21]),4 );
-    idCode[4] = char(0);
-  }
-  for (i=0;i<8;i++)  {
-    strncpy ( sIdCode[i],&(S[31+i*5]),4 );
-    sIdCode[i][4] = char(0);
-  }
-  return 0;
-}
-
-void  CSupersede::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-int         i,RC;
-pstr        F,FDate,FID;
-char        DateCIF [20];
-char        DateCIF0[20];
-IDCode      idCode1;
-  Loop = CIF->GetLoop ( CIFCAT_SPRSDE );
-  if (!Loop)  {
-    Signal = -1;  // signal to finish processing of this structure
-    return;
-  }
-  i = 0;
-  do  {
-    F = Loop->GetString ( CIFTAG_ID,Signal,RC );
-    if (RC)  {
-      if (i==0)
-        Signal = -1;
-      return;
-    }
-    if (F)  {
-      if (!strcmp(F,"SPRSDE"))  {
-        FDate = Loop->GetString ( CIFTAG_DATE,Signal,RC );
-        if ((!RC) && FDate)
-              strncpy ( DateCIF,FDate,15 );
-        else  strcpy  ( DateCIF,"YYYY-MMM-DD" );
-        FID = Loop->GetString ( CIFTAG_REPLACE_PDB_ID,Signal,RC );
-        if ((!RC) && FID)
-              strncpy ( idCode1,FID,sizeof(IDCode)-1 );
-        else  idCode1[0] = char(0);
-        if (i==0)  {
-          DateCIFto11 ( DateCIF,sprsdeDate );
-          DateCIF[11] = char(0);
-          strcpy ( idCode  ,idCode1 );
-          strcpy ( DateCIF0,DateCIF );
-        } else if ((strcmp(DateCIF0,DateCIF)) ||
-                   (strcmp(idCode,idCode1)))
-          return;
-        FID = Loop->GetString ( CIFTAG_PDB_ID,Signal,RC );
-        if ((!RC) && FID)
-             strncpy ( sIdCode[i],FID,sizeof(IDCode)-1 );
-        else sIdCode[i][0] = char(0);
-        Loop->DeleteField ( CIFTAG_ID            ,Signal );
-        Loop->DeleteField ( CIFTAG_DATE          ,Signal );
-        Loop->DeleteField ( CIFTAG_REPLACE_PDB_ID,Signal );
-        Loop->DeleteField ( CIFTAG_PDB_ID        ,Signal );
-        i++;
-      }
-    }
-    Signal++;
-  } while (i<8);
-}
-
-void  CSupersede::Copy ( PCContainerClass Supersede )  {
-int i;
-  strcpy ( sprsdeDate,PCSupersede(Supersede)->sprsdeDate );
-  strcpy ( idCode    ,PCSupersede(Supersede)->idCode     );
-  for (i=0;i<8;i++)
-    strcpy ( sIdCode[i],PCSupersede(Supersede)->sIdCode[i] );
-}
-
-void  CSupersede::write ( RCFile f )  {
-int  i;
-byte Version=1;
-  f.WriteByte  ( &Version );
-  f.WriteTerLine ( sprsdeDate,False );
-  f.WriteTerLine ( idCode    ,False );
-  for (i=0;i<8;i++)
-    f.WriteTerLine ( sIdCode[i],False );
-}
-
-void  CSupersede::read  ( RCFile f ) {
-int  i;
-byte Version;
-  f.ReadByte  ( &Version );
-  f.ReadTerLine ( sprsdeDate,False );
-  f.ReadTerLine ( idCode    ,False );
-  for (i=0;i<8;i++)
-    f.ReadTerLine ( sIdCode[i],False );
-}
-
-MakeStreamFunctions(CSupersede)
-
-
-//  ===================  CJournal  ======================
-
-CJournal::CJournal() : CContString()  {
-  InitJournal();
-}
-
-CJournal::CJournal ( cpstr S ) : CContString()  {
-  InitJournal();
-  ConvertPDBASCII ( S );
-}
-
-CJournal::CJournal ( RPCStream Object ) : CContString(Object)  {
-  InitJournal();
-}
-
-CJournal::~CJournal() {}
-
-void  CJournal::InitJournal()  {
-  CreateCopy ( CIFCategory,CIFCAT_CITATION );
-  CreateCopy ( CIFTag     ,CIFTAG_TEXT     );
-}
-
-int  CJournal::ConvertPDBASCII ( cpstr S )  {
-  if (strlen(S)>10)
-       CreateCopy ( Line,&(S[10]) );
-  else CreateCopy ( Line,pstr(" ") );
-  return 0;
-}
-
-void  CJournal::PDBASCIIDump ( pstr S, int )  {
-  strcpy ( S,"JRNL      " );
-  strcat ( S,Line         );
-}
-
-void  CJournal::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CContString::write ( f );
-}
-
-void  CJournal::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CContString::read ( f );
-}
-
-MakeStreamFunctions(CJournal)
-
-
-
-//  ===================  CRemark  ======================
-
-CRemark::CRemark() : CContainerClass()  {
-  InitRemark();
-}
-
-CRemark::CRemark ( cpstr S ) : CContainerClass()  {
-  InitRemark();
-  ConvertPDBASCII ( S );
-}
-
-CRemark::CRemark ( RPCStream Object ) : CContainerClass(Object)  {
-  InitRemark();
-}
-
-CRemark::~CRemark() {
-  if (Remark)  delete[] Remark;
-}
-
-void  CRemark::InitRemark()  {
-  remarkNum = 0;
-  Remark    = NULL;
-}
-
-int  CRemark::ConvertPDBASCII ( cpstr S )  {
-int i;
-  GetInteger ( remarkNum,&(S[7]),3 );
-  if (remarkNum==MinInt4)  CreateCopy ( Remark,S );
-  else if (strlen(S)>11)   CreateCopy ( Remark,&(S[11])  );
-                     else  CreateCopy ( Remark,pstr(" ") );
-  i = strlen(Remark)-1;
-  while ((i>0) && (Remark[i]==' '))  i--;
-  Remark[i+1] = char(0);
-  return 0;
-}
-
-void  CRemark::PDBASCIIDump ( pstr S, int )  {
-  if (remarkNum==MinInt4)
-    strcpy ( S,Remark );
-  else  {
-    strcpy     ( S,"REMARK" );
-    PadSpaces  ( S,80 );
-    PutInteger ( &(S[7]) ,remarkNum,3 );
-    strncpy    ( &(S[11]),Remark,IMin(68,strlen(Remark)) );
-  }
-}
-
-void  CRemark::MakeCIF ( PCMMCIFData CIF, int N )  {
-PCMMCIFLoop Loop;
-int         RC;
-  RC = CIF->AddLoop ( CIFCAT_NDB_DATABASE_REMARK,Loop );
-  if ((RC!=CIFRC_Ok) || (N==0))  {
-    // the category was (re)created, privide tags
-    Loop->AddLoopTag ( CIFTAG_ID   );
-    Loop->AddLoopTag ( CIFTAG_TEXT );
-  }
-  if (remarkNum==MinInt4)  Loop->AddString  ( NULL      );
-                     else  Loop->AddInteger ( remarkNum );
-  Loop->AddString ( Remark );
-}
-
-void  CRemark::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-PCMMCIFLoop Loop;
-int         RC;
-
-  Loop = CIF->GetLoop ( CIFCAT_NDB_DATABASE_REMARK );
-  if (!Loop)  {
-    Signal = -1;
-    return;
-  }
-  if (Signal>=Loop->GetLoopLength() )  {
-    Signal = -1;
-    return;
-  }
-
-  RC = Loop->GetInteger ( remarkNum,CIFTAG_ID,Signal,True );
-  if (RC==CIFRC_WrongFormat)  {
-    sprintf ( CIFErrorLocation,"loop %s.%s row %i",
-              CIFCAT_NDB_DATABASE_REMARK,CIFTAG_ID,Signal );
-    Signal = -Error_UnrecognizedInteger-1;
-    return;
-  } else if (RC)
-    remarkNum = MinInt4;
-  Loop->GetString ( Remark,CIFTAG_TEXT,Signal,True );
-
-  Signal++;
-
-}
-
-void  CRemark::Copy ( PCContainerClass RemarkClass )  {
-  remarkNum = PCRemark(RemarkClass)->remarkNum;
-  CreateCopy ( Remark,PCRemark(RemarkClass)->Remark );
-}
-
-void  CRemark::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte   ( &Version   );
-  f.WriteInt    ( &remarkNum );
-  f.CreateWrite ( Remark     );
-}
-
-void  CRemark::read ( RCFile f )  {
-byte Version;
-  f.ReadByte   ( &Version   );
-  f.ReadInt    ( &remarkNum );
-  f.CreateRead ( Remark     );
-}
-
-MakeStreamFunctions(CRemark)
-
-
-//  =================  CBiomolecule  =====================
-
-#define  R350_ERRBIOMT     (-3)
-#define  R350_ERROR        (-2)
-#define  R350_END          (-1)
-#define  R350_NONE           0
-#define  R350_BIOMOLECULE    1
-#define  R350_CHAINS         2
-#define  R350_BIOMT          3
-
-void getRemarkKey ( RPCRemark rem, int & lkey )  {
-  if (rem)  {
-    if (rem->remarkNum!=350)  lkey = R350_END;
-    else if (rem->Remark)  {
-      if (strcasestr(rem->Remark,"BIOMOLECULE:"))
-        lkey = R350_BIOMOLECULE;
-      else if (strcasestr(rem->Remark,"CHAINS:"))
-        lkey = R350_CHAINS;
-      else if (strcasestr(rem->Remark,"BIOMT1") ||
-               strcasestr(rem->Remark,"BIOMT2") ||
-               strcasestr(rem->Remark,"BIOMT3"))
-        lkey = R350_BIOMT;
-      else
-        lkey = R350_NONE;
-    }
-  }
-}
-
-int lookupRemarks ( int & i, RPCRemark rem,
-                    RCTitleContainer Remark )  {
-int l,lkey;
-
-  l    = Remark.Length();
-  lkey = R350_NONE;
-  while ((i<l) && (lkey==R350_NONE))  {
-    getRemarkKey ( rem,lkey );
-    if (lkey==R350_NONE)  {
-      i++;
-      rem = (PCRemark)Remark.GetContainerClass ( i );
-    }
-  }
-
-  return lkey;
-
-}
-
-
-
-CBMApply::CBMApply() : CStream()  {
-  InitBMApply();
-}
-
-CBMApply::CBMApply ( RPCStream Object ) : CStream ( Object )  {
-  InitBMApply();
-}
-
-CBMApply::~CBMApply()  {
-  FreeMemory();
-}
-
-void  CBMApply::InitBMApply()  {
-  chain     = NULL;
-  nChains   = 0;
-  tm        = NULL;
-  nMatrices = 0;
-}
-
-void  CBMApply::FreeMemory()  {
-  if (chain)  delete[] chain;
-  if (tm)     delete[] tm;
-  chain     = NULL;
-  nChains   = 0;
-  tm        = NULL;
-  nMatrices = 0;
-}
-
-int  CBMApply::addChains ( int & i, RPCRemark rem,
-                           RCTitleContainer Remark )  {
-PChainID ch1;
-pstr     p;
-int      l,lkey,nAdd,j;
-
-  l    = Remark.Length();
-  lkey = R350_NONE;
-
-  while ((i<l) && (lkey==R350_NONE))  {
-
-    p = strcasestr ( rem->Remark,"CHAINS:" );
-    if (p)  p += 7;
-    else  {
-      p = rem->Remark;
-      while (*p==' ')  p++;
-      if ((p[1]!=',') && (p[1]!=' '))  p = NULL;
-    }
-
-    if (p)  {
-      nAdd  = strlen(p)/2 + 3;
-      ch1   = chain;
-      chain = new ChainID[nChains+nAdd];
-      for (j=0;j<nChains;j++)
-        strcpy ( chain[j],ch1[j] );
-      if (ch1)  delete[] ch1;
-
-      while (*p)  {
-        while ((*p==' ') || (*p==','))  p++;
-        if (*p)  {
-          if ((p[1]==',') || (p[1]==' ') || (p[1]==char(0)))  {
-            chain[nChains][0] = *p;
-            chain[nChains][1] = char(0);
-            nChains++;
-            p++;
-          } else
-            break;
-        }
-      }
-    }
-
-    do  {
-      i++;
-      if (i<l)  {
-        rem = (PCRemark)Remark.GetContainerClass ( i );
-        if (rem)  {
-          if (rem->remarkNum!=350)  lkey = R350_END;
-          else getRemarkKey ( rem,lkey );
-        }
-      } else
-        lkey = R350_END;
-    } while ((!rem) && (lkey==R350_NONE));
-
-  }
-
-  return lkey;
-
-}
-
-int getBIOMT ( RPCRemark rem, int biomtNo, mat44 & t,
-               RCTitleContainer Remark, int & i )  {
-char PN[20];
-pstr p1,p2;
-int  l,j,lkey;
-
-  sprintf ( PN,"BIOMT%1i",biomtNo );
-  p1 = strcasestr ( rem->Remark,PN );
-  if (!p1)  return R350_ERRBIOMT;
-
-  p1 += 6;
-  while (*p1==' ')  p1++;
-  while (*p1 && (*p1!=' '))  p1++;
-
-  l = biomtNo - 1;
-  t[l][0] = strtod ( p1,&p2 );
-  if (p1==p2)  return R350_ERRBIOMT;
-  t[l][1] = strtod ( p2,&p1 );
-  if (p1==p2)  return R350_ERRBIOMT;
-  t[l][2] = strtod ( p1,&p2 );
-  if (p1==p2)  return R350_ERRBIOMT;
-  t[l][3] = strtod ( p2,&p1 );
-  if (p1==p2)  return R350_ERRBIOMT;
-
-  if (biomtNo==3)  {
-    for (j=0;j<3;j++)
-      t[3][j] = 0.0;
-    t[3][3] = 1.0;
-  }
-
-  l    = Remark.Length();
-  lkey = R350_BIOMT;
-  do  {
-    i++;
-    if (i<l)  {
-      rem = (PCRemark)Remark.GetContainerClass ( i );
-      if (rem)  {
-        if (rem->remarkNum!=350)  lkey = R350_END;
-                            else  getRemarkKey ( rem,lkey );
-      }
-    } else
-      lkey = R350_END;
-  } while ((lkey==R350_NONE) || ((!rem) && (lkey==R350_BIOMT)));
-
-  return lkey;
-
-}
-
-int  CBMApply::addMatrices ( int & i, RPCRemark rem,
-                             RCTitleContainer Remark )  {
-pmat44 tm1;
-int    l,lkey,j,k1,k2,nAlloc;
-
-  l      = Remark.Length();
-  lkey   = R350_BIOMT;
-  nAlloc = nMatrices;
-
-  while ((i<l) && (lkey==R350_BIOMT))  {
-
-    if (nMatrices>=nAlloc)  {
-      nAlloc = nMatrices + 10;
-      tm1    = tm;
-      tm     = new mat44[nAlloc];
-      for (j=0;j<nMatrices;j++)
-        for (k1=0;k1<4;k1++)
-          for (k2=0;k2<4;k2++)
-            tm[j][k1][k2] = tm1[j][k1][k2];
-      if (tm1)  delete[] tm1;
-    }
-
-    lkey = getBIOMT ( rem,1,tm[nMatrices],Remark,i );
-    if (lkey==R350_BIOMT)
-      lkey = getBIOMT ( rem,2,tm[nMatrices],Remark,i );
-    if (lkey==R350_BIOMT)
-      lkey = getBIOMT ( rem,3,tm[nMatrices],Remark,i );
-    nMatrices++;
-
-  }
-
-  return lkey;
-
-}
-
-void  CBMApply::Copy ( PCBMApply BMA )  {
-// if BMA is NULL, then empties the class
-int  i,j,k;
-
-  FreeMemory();
-
-  if (BMA)  {
-
-    nChains = BMA->nChains;
-    if (nChains>0)  {
-      chain = new ChainID[nChains];
-      for (i=0;i<nChains;i++)
-        strcpy ( chain[i],BMA->chain[i] );
-    }
-
-    nMatrices = BMA->nMatrices;
-    if (nMatrices>0)  {
-      tm = new mat44[nMatrices];
-      for (i=0;i<nMatrices;i++)
-        for (j=0;j<4;j++)
-          for (k=0;k<4;k++)
-            tm[i][j][k] = BMA->tm[i][j][k];
-     }
-  }
-
-}
-
-void  CBMApply::write ( RCFile f )  {
-int i,j,k;
-  f.WriteInt ( &nChains );
-  for (i=0;i<nChains;i++)
-    f.WriteTerLine ( chain[i],False );
-  f.WriteInt ( &nMatrices );
-  for (i=0;i<nMatrices;i++)
-    for (j=0;j<3;j++)
-      for (k=0;k<4;k++)
-        f.WriteReal ( &(tm[i][j][k]) );
-}
-
-void  CBMApply::read ( RCFile f )  {
-int i,j,k;
-  FreeMemory();
-  f.ReadInt ( &nChains );
-  if (nChains>0)  {
-    chain = new ChainID[nChains];
-    for (i=0;i<nChains;i++)
-      f.ReadTerLine ( chain[i],False );
-  }
-  f.ReadInt ( &nMatrices );
-  if (nMatrices>0)  {
-    tm = new mat44[nMatrices];
-    for (i=0;i<nMatrices;i++)  {
-      for (j=0;j<3;j++)  {
-        for (k=0;k<4;k++)
-          f.ReadReal ( &(tm[i][j][k]) );
-        tm[i][3][j] = 0.0;
-      }
-      tm[i][3][3] = 1.0;
-    }
-  }
-}
-
-MakeStreamFunctions(CBMApply)
-
-
-CBiomolecule::CBiomolecule() : CStream()  {
-  InitBiomolecule();
-}
-
-CBiomolecule::CBiomolecule ( RPCStream Object )
-            : CStream ( Object )  {
-  InitBiomolecule();
-}
-
-CBiomolecule::~CBiomolecule()  {
-  FreeMemory();
-}
-
-void  CBiomolecule::InitBiomolecule()  {
-  BMApply = NULL;
-  nBMAs   = 0;
-}
-
-void  CBiomolecule::FreeMemory()  {
-int i;
-  if (BMApply)  {
-    for (i=0;i<nBMAs;i++)
-      if (BMApply[i])  delete BMApply[i];
-    delete[] BMApply;
-    BMApply = NULL;
-  }
-  nBMAs = 0;
-}
-
-
-PCBMApply CBiomolecule::addBMApply()  {
-PPCBMApply BMA1;
-int        i;
-  BMA1 = BMApply;
-  BMApply = new PCBMApply[nBMAs+1];
-  for (i=0;i<nBMAs;i++)
-    BMApply[i] = BMA1[i];
-  if (BMA1)  delete[] BMA1;
-  BMApply[nBMAs] = new CBMApply();
-  nBMAs++;
-  return BMApply[nBMAs-1];
-}
-
-int CBiomolecule::Size()  {
-int i,k;
-  k = 0;
-  for (i=0;i<nBMAs;i++)
-    k += BMApply[i]->nChains*BMApply[i]->nMatrices;
-  return k;
-}
-
-Boolean CBiomolecule::checkComposition ( PChainID chID, ivector occ,
-                                         ivector  wocc, int n )  {
-// chID[n] is list of chain IDs
-// occ[n]  is list of chain occurencies
-// wocc[n] is working array
-int     i,j,k,k1;
-Boolean cmp;
-
-  for (i=0;i<n;i++)
-    wocc[i] = 0;
-
-  cmp = True;
-
-  for (i=0;(i<nBMAs) && cmp;i++)
-    for (j=0;(j<BMApply[i]->nChains) && cmp;j++)  {
-      k1 = -1;
-      for (k=0;(k<n) && (k1<0);k++)
-        if (!strcmp(chID[k],BMApply[i]->chain[j]))
-          k1 = k;
-      if (k1<0)  cmp = False;  // chain not found in the list
-           else  wocc[k1] += BMApply[i]->nMatrices;
-    }
-
-  for (i=0;(i<n) && cmp;i++)
-    if (occ[i]!=wocc[i])  cmp = False;
-
-  return cmp;
-
-}
-
-void  CBiomolecule::Copy ( PCBiomolecule B )  {
-// if B is NULL, then empties the class
-int  i;
-
-  FreeMemory();
-
-  if (B)  {
-
-    nBMAs = B->nBMAs;
-    if (nBMAs>0)  {
-      BMApply = new PCBMApply[nBMAs];
-      for (i=0;i<nBMAs;i++)
-        if (B->BMApply[i])  {
-          BMApply[i] = new CBMApply();
-          BMApply[i]->Copy ( B->BMApply[i] );
-        } else
-          BMApply[i] = NULL;
-    }
-
-  }
-
-}
-
-void  CBiomolecule::write ( RCFile f )  {
-int i;
-  f.WriteInt ( &nBMAs );
-  for (i=0;i<nBMAs;i++)
-    StreamWrite ( f,BMApply[i] );
-}
-
-void  CBiomolecule::read ( RCFile f )  {
-int i;
-  FreeMemory();
-  f.ReadInt ( &nBMAs );
-  if (nBMAs>0)  {
-    BMApply = new PCBMApply[nBMAs];
-    for (i=0;i<nBMAs;i++)  {
-      BMApply[i] = NULL;
-      StreamRead ( f,BMApply[i] );
-    }
-  }
-}
-
-MakeStreamFunctions(CBiomolecule)
-
-
-//  =====================   CMMDBFTitle   =======================
-
-CMMDBTitle::CMMDBTitle() : CStream() {
-  Init();
-}
-
-CMMDBTitle::CMMDBTitle ( RPCStream Object )  : CStream(Object)  {
-  Init();
-}
-
-void  CMMDBTitle::Init()  {
-
-  //  Header data
-  classification = NULL;
-  depDate[0]     = char(0);
-  idCode [0]     = char(0);
-  resolution     = -2.0;
-  col73          = False;
-
-  Biomolecule    = NULL;
-  nBiomolecules  = 0;
-
-}
-
-CMMDBTitle::~CMMDBTitle() {
-  FreeMemory ( False );
-}
-
-void  CMMDBTitle::FreeMemory ( Boolean keepBiomolecules )  {
-
-  if (classification)  delete[] classification;
-  classification = NULL;
-  resolution     = -2.0;
-
-  ObsData  .FreeContainer();
-  Title    .FreeContainer();
-  CAVEAT   .FreeContainer();
-  Compound .FreeContainer();
-  Source   .FreeContainer();
-  KeyWords .Delete       ();
-  ExpData  .FreeContainer();
-  MdlType  .FreeContainer();
-  Author   .FreeContainer();
-  RevData  .FreeContainer();
-  Supersede.FreeContainer();
-  Journal  .FreeContainer();
-  Remark   .FreeContainer();
-
-  col73 = False;
-
-  if (!keepBiomolecules)
-    FreeBiomolecules();
-
-}
-
-void  CMMDBTitle::FreeBiomolecules()  {
-int  i;
-  if (Biomolecule)  {
-    for (i=0;i<nBiomolecules;i++)
-      if (Biomolecule[i])  delete Biomolecule[i];
-    delete[] Biomolecule;
-    Biomolecule = NULL;
-  }
-  nBiomolecules = 0;
-}
-
-
-void  CMMDBTitle::SetHeader ( cpstr Classification,
-                              cpstr DepDate,
-                              cpstr IDCode )  {
-// fills the PDB file header
-  CreateCopy ( classification ,Classification  );
-  strncpy    ( depDate,DepDate,sizeof(depDate) );
-  strncpy    ( idCode ,IDCode ,sizeof(idCode)  );
-  depDate[sizeof(depDate)-1] = char(0);
-  idCode [sizeof(idCode) -1] = char(0);
-}
-
-int  CMMDBTitle::ConvertPDBString ( pstr PDBString ) {
-// Interprets the ASCII PDB line belonging to the title section
-// and fills the corresponding fields.
-//   Returns zero if the line was converted, otherwise returns a
-// non-negative value of Error_XXXX.
-//   PDBString must be not shorter than 81 characters.
-int              i;
-char             c;
-PCContainerClass ContainerClass;
-
-  //  pad input line with spaces, if necessary
-  PadSpaces ( PDBString,80 );
-
-  if (!strncmp(PDBString,"HEADER",6))  {
-
-    i = 49;
-    while ((i>=10) && (PDBString[i]==' '))  i--;
-    i++;
-    c = PDBString[i];
-    PDBString[i] = char(0);
-    CreateCopy ( classification,&(PDBString[10]) );
-    PDBString[i] = c;
-
-    Date9to11 ( &(PDBString[50]),depDate );
-
-    strncpy ( idCode,&(PDBString[62]),4 );
-    idCode[4] = char(0);
-
-  } else if (!strncmp(PDBString,"OBSLTE",6))  {
-
-    ContainerClass = new CObsLine(PDBString);
-    ObsData.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"TITLE ",6))  {
-
-    ContainerClass = new CTitleLine(PDBString);
-    Title.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"CAVEAT",6))  {
-
-    ContainerClass = new CCaveat(PDBString);
-    CAVEAT.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"COMPND",6))  {
-
-    ContainerClass = new CCompound(PDBString);
-    Compound.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"SOURCE",6))  {
-
-    ContainerClass = new CSource(PDBString);
-    Source.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"KEYWDS",6))  {
-
-    KeyWords.ConvertPDBASCII ( PDBString );
-
-  } else if (!strncmp(PDBString,"EXPDTA",6))  {
-
-    ContainerClass = new CExpData(PDBString);
-    ExpData.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"MDLTYPE",6))  {
-
-    ContainerClass = new CMdlType(PDBString);
-    MdlType.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"AUTHOR",6))  {
-
-    ContainerClass = new CAuthor(PDBString);
-    Author.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"REVDAT",6))  {
-
-    ContainerClass = new CRevData(PDBString);
-    RevData.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"SPRSDE",6))  {
-
-    ContainerClass = new CSupersede(PDBString);
-    Supersede.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"JRNL  ",6))  {
-
-    ContainerClass = new CJournal(PDBString);
-    Journal.AddData ( ContainerClass );
-
-  } else if (!strncmp(PDBString,"REMARK",6))  {
-
-    ContainerClass = new CRemark(PDBString);
-    Remark.AddData ( ContainerClass );
-
-  } else
-    return Error_WrongSection;
-
-  //  check for ID code in columns 73-80
-
-  if (!col73)  {
-    if (('0'<=idCode[0]) && (idCode[0]<='9'))  {
-      if (!strncasecmp(idCode,&(PDBString[72]),4))
-        col73 = True;
-    }
-  }
-
-  return  0;
-
-}
-
-PCTitleContainer CMMDBTitle::GetRemarks()  {
-  return &Remark;
-}
-
-PCTitleContainer CMMDBTitle::GetJournal()  {
-  return &Journal;
-}
-
-realtype CMMDBTitle::GetResolution()  {
-//  returns -1.0 if there is no resolution record in the file
-PCRemark rem;
-pstr     p,eptr;
-int      i,l;
-  if (resolution>-1.5)  return resolution;
-  l = Remark.Length();
-  for (i=0;(i<l) && (resolution<-1.5);i++)  {
-    rem = (PCRemark)Remark.GetContainerClass ( i );
-    if (rem)  {
-      if (rem->remarkNum==2)  {
-        if (rem->Remark)  {
-          p = strcasestr ( rem->Remark,"RESOLUTION" );
-          if (p)  {
-            while ((*p) && (*p!=' '))  p++;
-            if (*p)  {
-              resolution = strtod ( p,&eptr );
-              if ((resolution<0.0) || (eptr==p))
-                resolution = -1.0;
-            }
-          }
-        }
-      } else if (rem->remarkNum>2)
-        resolution = -1.0;
-    }
-  }
-  return resolution;
-}
-
-PCBiomolecule CMMDBTitle::addBiomolecule()  {
-PPCBiomolecule  BM1;
-int             i;
-  BM1 = Biomolecule;
-  Biomolecule = new PCBiomolecule[nBiomolecules+1];
-  for (i=0;i<nBiomolecules;i++)
-    Biomolecule[i] = BM1[i];
-  if (BM1)  delete[] BM1;
-  Biomolecule[nBiomolecules] = new CBiomolecule();
-  nBiomolecules++;
-  return Biomolecule[nBiomolecules-1];
-}
-
-int CMMDBTitle::ParseBiomolecules()  {
-PCRemark       rem;
-PCBiomolecule  BMol;
-PCBMApply      BMA;
-int            i,l, lkey;
-
-  FreeBiomolecules();
-
-  l    = Remark.Length();
-  i    = 0;
-  lkey = 0;
-  while ((i<l) && (!lkey))  {
-    rem = (PCRemark)Remark.GetContainerClass ( i );
-    if (rem)  {
-      if (rem->remarkNum==350)      lkey = 1;
-      else if (rem->remarkNum>350)  lkey = -1;
-    }
-    if (!lkey) i++;
-  }
-
-  BMol = NULL;
-  BMA  = NULL;
-
-  while (lkey>0)  {
-
-    rem = (PCRemark)Remark.GetContainerClass ( i );
-    lkey = lookupRemarks ( i,rem,Remark );
-
-    switch (lkey)  {
-      case R350_BIOMOLECULE : BMol = addBiomolecule();
-                              i++;
-                            break;
-      case R350_CHAINS      : if (BMol)  {
-                                BMA = BMol->addBMApply();
-                                while (lkey==R350_CHAINS)
-                                  lkey = BMA->addChains(i,rem,Remark);
-                              } else
-                                lkey = R350_ERROR;
-                            break;
-      case R350_BIOMT       : if (BMA)
-                                lkey = BMA->addMatrices(i,rem,Remark);
-                              else
-                                lkey = R350_ERROR;
-                            break;
-      default : i++;
-    }
-
-  }
-
-  if (lkey<=R350_ERROR)  {
-    FreeBiomolecules();
-    return lkey;
-  }
-
-  return nBiomolecules;
-
-}
-
-int CMMDBTitle::GetNofBiomolecules()  {
-  return nBiomolecules;
-}
-
-void CMMDBTitle::GetBiomolecules ( PPCBiomolecule & BM, int & nBMs ) {
-  BM   = Biomolecule;
-  nBMs = nBiomolecules;
-}
-
-PCBiomolecule CMMDBTitle::GetBiomolecule ( int bmNo )  { // bmno=0,1,..
-  if ((0<=bmNo) && (bmNo<nBiomolecules))
-    return Biomolecule[bmNo];
-  return NULL;
-}
-
-
-int  CMMDBTitle::GetCIF ( PCMMCIFData CIF )  {
-pstr  S;
-int  RC;
-
-  S = NULL;
-  CIF->GetDataName ( S,True );
-  if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_ENTRY_ID,True );
-  if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_CODE_NDB,True );
-  if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_CODE_PDB,True );
-  if (S)  {
-    strncpy ( idCode,S,sizeof(IDCode)-1 );
-    idCode[sizeof(IDCode)-1] = char(0);
-    delete[] S;
-    S = NULL;
-    CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
-    CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_CODE_NDB );
-    CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_CODE_PDB );
-  } else
-    idCode[0] = char(0);
-  CIF->GetString ( classification,CIFCAT_STRUCT_KEYWORDS,
-                                  CIFTAG_NDB_KEYWORDS,True );
-  CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL,True );
-  if (S)  {
-    DateCIFto11 ( S,depDate );
-    delete[] S;
-    S = NULL;
-  } else
-    depDate[0] = char(0);
-
-  ObsData .GetCIF ( CIF,ClassID_ObsLine   );
-  Title   .GetCIF ( CIF,ClassID_TitleLine );
-  CAVEAT  .GetCIF ( CIF,ClassID_CAVEAT    );
-  Compound.GetCIF ( CIF,ClassID_Compound  );
-  Source  .GetCIF ( CIF,ClassID_Source    );
-  KeyWords.GetCIF ( CIF );
-  ExpData .GetCIF ( CIF,ClassID_ExpData   );
-  MdlType .GetCIF ( CIF,ClassID_MdlType   );
-  Author  .GetCIF ( CIF,ClassID_Author    );
-  RC = RevData.GetCIF ( CIF,ClassID_RevData );
-  if (!RC)  {
-    Supersede.GetCIF ( CIF,ClassID_Supersede );
-    Journal  .GetCIF ( CIF,ClassID_Journal   );
-    RC = Remark   .GetCIF ( CIF,ClassID_Remark );
-  }
-  return RC;
-
-}
-
-void  CMMDBTitle::MakePDBHeaderString ( pstr PDBString )  {
-//  makes the ASCII PDB HEADER line from the class' data
-int i;
-
-  if (classification)  {
-
-    strcpy ( PDBString,"HEADER    " );
-    strcat ( PDBString,classification );
-    i = strlen(PDBString);
-    while (i<80)
-      PDBString[i++] = ' ';
-    PDBString[IMin(i,80)] = char(0);
-    Date11to9 ( depDate,&(PDBString[50]) );
-    strncpy   ( &(PDBString[62]),idCode,4 );
-
-  } else
-    strcpy ( PDBString,
-      "HEADER    XXXXXXXXXXXXXXXXXXXXXXXXXXXX            XX-XXX-XX   ----" );
-
-}
-
-pstr  CMMDBTitle::GetStructureTitle ( pstr & S )  {
-// GetStructureTitle() returns the contents of TITLE record
-// unfolded into single line. If Title is missing, returns
-// contents of COMPND(:MOLECULE). If COMPND is missing, returns
-// HEADER. If Header is missing, returns PDB code. If no PDB
-// code is there, returns "Not available".
-PCTitleLine TLine;
-PCCompound  CLine;
-pstr        p;
-int         i,cl,l;
-Boolean     B;
-
-  if (S)  delete[] S;
-  S  = NULL;
-
-  cl = Title.Length();
-  if (cl>0)  {
-    l = 0;
-    for (i=0;i<cl;i++)  {
-      TLine = PCTitleLine(Title.GetContainerClass(i));
-      if (TLine)  l += strlen_des(TLine->Line)+5;
-    }
-    S = new char[l];
-    S[0] = char(0);
-    for (i=0;i<cl;i++)  {
-      TLine = PCTitleLine(Title.GetContainerClass(i));
-      if (TLine)  {
-        if (i>0)  strcat ( S," " );
-        strcat_des ( S,TLine->Line );
-      }
-    }
-  } else  {
-    cl = Compound.Length();
-    if (cl>0)  {
-      l = 0;
-      p = NULL;
-      B = True;
-      for (i=0;(i<cl) && B;i++)  {
-        CLine = PCCompound(Compound.GetContainerClass(i));
-        if (CLine)  {
-          if (!p)  {
-            p = strstr(CLine->Line,"MOLECULE:");
-            if (p)  l += strlen_des(&(p[9]))+5;
-          } else  {
-            p = strstr(CLine->Line,"MOLECULE:");
-            if (p)
-              l += strlen_des(&(p[9]))+5;
-            else {
-              p = strchr(CLine->Line,':');
-              if (!p)  {
-                l += strlen_des(CLine->Line)+5;
-                p = CLine->Line;
-              } else
-                B = False;
-            }
-          }
-        }
-      }
-      if (l>0)  {
-        S = new char[l];
-        S[0] = char(0);
-        p = NULL;
-        B = True;
-        for (i=0;(i<cl) && B;i++)  {
-          CLine = PCCompound(Compound.GetContainerClass(i));
-          if (CLine)  {
-            if (!p)  {
-              p = strstr(CLine->Line,"MOLECULE:");
-              if (p)  strcat_des ( S,&(p[9]) );
-            } else  {
-              p = strstr(CLine->Line,"MOLECULE:");
-              if (p)
-                strcat_des ( S,&(p[9]) );
-              else {
-                p = strchr(CLine->Line,':');
-                if (!p)  {
-                  strcat_des ( S,CLine->Line );
-                  p = CLine->Line;
-                } else
-                  B = False;
-              }
-            }
-            l = strlen(S)-1;
-            if (S[l]==';')  S[l] = char(0);
-          }
-        }
-      } else  {
-        l = 0;
-        for (i=0;i<cl;i++)  {
-          CLine = PCCompound(Compound.GetContainerClass(i));
-          if (CLine)  l += strlen_des(CLine->Line)+5;
-        }
-        S = new char[l];
-        S[0] = char(0);
-        for (i=0;i<cl;i++)  {
-          CLine = PCCompound(Compound.GetContainerClass(i));
-          if (CLine)  {
-            if (i>0)  strcat ( S," " );
-            strcat_des ( S,CLine->Line );
-          }
-        }
-      }
-    } else if (classification)
-      CreateCopy ( S,classification );
-    else if (idCode[0])
-      CreateCopy ( S,idCode );
-    else
-      CreateCopy ( S,pstr("Not available") );
-  }
-
-  if (!S[0])  CreateCopy ( S,pstr("Not available") );
-
-  return S;
-
-}
-
-void  CMMDBTitle::PDBASCIIDump ( RCFile f )  {
-char  PDBString[100];
-  if (classification)  {
-    MakePDBHeaderString ( PDBString );
-    f.WriteLine ( PDBString );
-  }
-  ObsData  .PDBASCIIDump ( f );
-  Title    .PDBASCIIDump ( f );
-  CAVEAT   .PDBASCIIDump ( f );
-  Compound .PDBASCIIDump ( f );
-  Source   .PDBASCIIDump ( f );
-  KeyWords .PDBASCIIDump ( f );
-  ExpData  .PDBASCIIDump ( f );
-  MdlType  .PDBASCIIDump ( f );
-  Author   .PDBASCIIDump ( f );
-  RevData  .PDBASCIIDump ( f );
-  Supersede.PDBASCIIDump ( f );
-  Journal  .PDBASCIIDump ( f );
-  Remark   .PDBASCIIDump ( f );
-}
-
-
-void  CMMDBTitle::MakeCIF ( PCMMCIFData CIF )  {
-char DateCIF[20];
-
-  if (idCode[0])  {
-    CIF->PutDataName ( idCode );
-    CIF->PutString   ( idCode, CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
-    CIF->PutString   ( idCode, CIFCAT_DATABASE,CIFTAG_CODE_NDB );
-    CIF->PutString   ( idCode, CIFCAT_DATABASE,CIFTAG_CODE_PDB );
-  } else  {
-    CIF->PutDataName ( pstr("")                              );
-    CIF->PutString   ( NULL, CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
-    CIF->PutString   ( NULL, CIFCAT_DATABASE,CIFTAG_CODE_NDB );
-    CIF->PutString   ( NULL, CIFCAT_DATABASE,CIFTAG_CODE_PDB );
-  }
-  CIF->PutString   ( classification, CIFCAT_STRUCT_KEYWORDS,
-                                     CIFTAG_NDB_KEYWORDS );
-  if (depDate[0])  {
-    Date11toCIF ( depDate,DateCIF );
-    CIF->PutString ( DateCIF,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL );
-  } else
-    CIF->PutString ( NULL,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL );
-
-  ObsData  .MakeCIF ( CIF );
-  Title    .MakeCIF ( CIF );
-  CAVEAT   .MakeCIF ( CIF );
-  Compound .MakeCIF ( CIF );
-  Source   .MakeCIF ( CIF );
-  KeyWords .MakeCIF ( CIF );
-  ExpData  .MakeCIF ( CIF );
-  MdlType  .MakeCIF ( CIF );
-  Author   .MakeCIF ( CIF );
-  RevData  .MakeCIF ( CIF );
-  Supersede.MakeCIF ( CIF );
-  Journal  .MakeCIF ( CIF );
-  Remark   .MakeCIF ( CIF );
-
-}
-
-void  CMMDBTitle::Copy ( PCMMDBTitle TS )  {
-int  i;
-
-  FreeBiomolecules();
-
-  if (TS)  {
-
-    CreateCopy ( classification,TS->classification );
-    strcpy     ( depDate       ,TS->depDate        );
-    strcpy     ( idCode        ,TS->idCode         );
-    resolution = TS->resolution;
-
-    ObsData  .Copy ( &(TS->ObsData)   );
-    Title    .Copy ( &(TS->Title)     );
-    CAVEAT   .Copy ( &(TS->CAVEAT)    );
-    Compound .Copy ( &(TS->Compound)  );
-    Source   .Copy ( &(TS->Source)    );
-    KeyWords .Copy ( &(TS->KeyWords)  );
-    ExpData  .Copy ( &(TS->ExpData)   );
-    MdlType  .Copy ( &(TS->MdlType)   );
-    Author   .Copy ( &(TS->Author)    );
-    RevData  .Copy ( &(TS->RevData)   );
-    Supersede.Copy ( &(TS->Supersede) );
-    Journal  .Copy ( &(TS->Journal)   );
-    Remark   .Copy ( &(TS->Remark)    );
-
-    nBiomolecules = TS->nBiomolecules;
-    if (nBiomolecules>0)  {
-      Biomolecule = new PCBiomolecule[nBiomolecules];
-      for (i=0;i<nBiomolecules;i++)
-        if (TS->Biomolecule[i])  {
-          Biomolecule[i] = new CBiomolecule();
-          Biomolecule[i]->Copy ( TS->Biomolecule[i] );
-        } else
-          Biomolecule[i] = NULL;
-    }
-
-  } else  {
-
-    if (classification)  delete[] classification;
-    classification = NULL;
-    resolution     = -2.0;
-    ObsData  .FreeContainer();
-    Title    .FreeContainer();
-    CAVEAT   .FreeContainer();
-    Compound .FreeContainer();
-    Source   .FreeContainer();
-    KeyWords .Delete       ();
-    ExpData  .FreeContainer();
-    MdlType  .FreeContainer();
-    Author   .FreeContainer();
-    RevData  .FreeContainer();
-    Supersede.FreeContainer();
-    Journal  .FreeContainer();
-    Remark   .FreeContainer();
-
-  }
-
-}
-
-void  CMMDBTitle::TrimInput ( pstr PDBString )  {
-  if (col73)  {
-    if (!strncasecmp(idCode,&(PDBString[72]),4))
-      PDBString[72] = char(0);
-  }
-  PadSpaces ( PDBString,80 );
-}
-
-void  CMMDBTitle::write ( RCFile f )  {
-// writes header to PDB binary file
-int  i;
-byte Version=3;
-
-  f.WriteByte    ( &Version       );
-
-  //  Header data
-  f.CreateWrite  ( classification );
-  f.WriteTerLine ( depDate,False  );
-  f.WriteTerLine ( idCode ,False  );
-  f.WriteReal    ( &resolution    );
-
-  ObsData  .write ( f );  //  Obsoletion data
-  Title    .write ( f );  //  Title
-  CAVEAT   .write ( f );  //  Error data
-  Compound .write ( f );  //  Compound
-  Source   .write ( f );  //  Source
-  KeyWords .write ( f );  //  Key words
-  ExpData  .write ( f );  //  Experimental data
-  MdlType  .write ( f );  //  Model descriptions
-  Author   .write ( f );  //  Author data
-  RevData  .write ( f );  //  Revision data
-  Supersede.write ( f );  //  Supersede records
-  Journal  .write ( f );  //  Journal records
-  Remark   .write ( f );  //  Remarks
-
-  f.WriteInt ( &nBiomolecules );
-  for (i=0;i<nBiomolecules;i++)
-    StreamWrite ( f,Biomolecule[i] );
-
-}
-
-void  CMMDBTitle::read ( RCFile f )  {
-// reads header from PDB binary file
-int  i;
-byte Version;
-
-  f.ReadByte    ( &Version );
-
-  //  Header data
-  f.CreateRead  ( classification );
-  f.ReadTerLine ( depDate,False  );
-  f.ReadTerLine ( idCode ,False  );
-  if (Version>1)
-    f.ReadReal  ( &resolution    );
-  else
-    resolution = -2.0;
-
-  ObsData  .read ( f );   //  Obsoletion data
-  Title    .read ( f );   //  Title
-  CAVEAT   .read ( f );   //  Error data
-  Compound .read ( f );   //  Compound
-  Source   .read ( f );   //  Source
-  KeyWords .read ( f );   //  Key words
-  ExpData  .read ( f );   //  Experimental data
-  if (Version>2)
-    MdlType.read ( f );   //  Model descriptions
-  Author   .read ( f );   //  Author data
-  RevData  .read ( f );   //  Revision data
-  Supersede.read ( f );   //  Supersede records
-  Journal  .read ( f );   //  Journal records
-  Remark   .read ( f );   //  Remarks
-
-  FreeBiomolecules();
-  if (Version>1)  {
-    f.ReadInt ( &nBiomolecules );
-    if (nBiomolecules>0)  {
-      Biomolecule = new PCBiomolecule[nBiomolecules];
-      for (i=0;i<nBiomolecules;i++)  {
-        Biomolecule[i] = NULL;
-        StreamRead ( f,Biomolecule[i] );
-      }
-    }
-  }
-
-}
-
-MakeStreamFunctions(CMMDBTitle)
-
-
-
-// ===================================================================
-
-/*
-void  TestHeader()  {
-PCMMDBTitle  Hdr;
-char         S[81],S1[81];
-
-  Hdr = new CMMDBTitle();
-
-  Hdr->SetHeader ( pstr("MUSCLE PROTEIN"),pstr("02-JUN-1993"),pstr("1MYS") );
-  Hdr->MakePDBHeaderString ( S );
-  printf ( "1234567890123456789012345678901234567890"
-           "1234567890123456789012345678901234567890\n" );
-  printf ( S );
-  printf ( "\n" );
-
-  strcpy ( S,
-// 1234567890123456789012345678901234567890123456789012345678901234567890
-  "HEADER    HYDROLASE (CARBOXYLIC ESTER)            07-APR-01   2PHI" );
-
-  Hdr->ConvertPDBString ( S );
-  Hdr->MakePDBHeaderString    ( S1 );
-  printf ( "1234567890123456789012345678901234567890"
-           "1234567890123456789012345678901234567890\n" );
-  printf ( S1 );
-  printf ( "\n" );
-
-  Hdr->SetHeader (
-     pstr("MUSCLE PROTEIN;**A VERY LONG TITLE TEST;**ARBITRARY LENGTH"),
-     pstr("02-JUN-1993"),pstr("1MYS") );
-  Hdr->MakePDBHeaderString ( S );
-  printf ( "1234567890123456789012345678901234567890"
-           "1234567890123456789012345678901234567890\n" );
-  printf ( S );
-  printf ( "\n" );
-
-  delete Hdr;
-
-  printf ( " header deleted \n" );
-
-}
-
-void  TestTitle() {
-// reads PDB title from file 'in.title'
-// and rewrites it into 'out.title' and 'abin.title'
-CFile        f;
-char         S[81];
-PCMMDBTitle  Title;
-
-  Title = new CMMDBTitle();
-
-  f.assign ( pstr("in.title"),True );
-  if (f.reset()) {
-    while (!f.FileEnd()) {
-      f.ReadLine ( S,sizeof(S) );
-      Title->ConvertPDBString ( S );
-    }
-    f.shut();
-  } else {
-    printf ( " Can't open input file 'in.title' \n" );
-    delete Title;
-    return;
-  }
-
-  f.assign ( pstr("out.title"),True );
-  if (f.rewrite()) {
-    Title->PDBASCIIDump ( f );
-    f.shut();
-  } else {
-    printf ( " Can't open output file 'out.title' \n" );
-    delete Title;
-    return;
-  }
-
-
-
-  f.assign ( pstr("mmdb.title.bin"),False );
-  if (f.rewrite()) {
-    Title->write ( f );
-    f.shut();
-  } else {
-    printf ( "  Can't open binary file for writing.\n" );
-    delete Title;
-    return;
-  }
-
-  delete Title;
-  printf ( "   Title deleted.\n" );
-
-  Title = new CMMDBTitle();
-  if (f.reset()) {
-    Title->read ( f );
-    f.shut();
-  } else {
-    printf ( "  Can't open binary file for reading.\n" );
-    delete Title;
-    return;
-  }
-
-  f.assign ( pstr("abin.title"),True );
-  if (f.rewrite()) {
-    Title->PDBASCIIDump ( f );
-    f.shut();
-  } else {
-    printf ( " Can't open output file 'abin.title' \n" );
-  }
-
-  delete Title;
-
-}
-
-
-*/
diff --git a/mmdb/mmdb_title.h b/mmdb/mmdb_title.h
deleted file mode 100755
index 17a3b78..0000000
--- a/mmdb/mmdb_title.h
+++ /dev/null
@@ -1,734 +0,0 @@
-//  $Id: mmdb_title.h,v 1.22 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    23.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_Title <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CTitleContainer  (container of title classes)
-//       ~~~~~~~~~  CObsLine
-//                  CTitleLine
-//                  CCaveat
-//                  CCompound
-//                  CSource
-//                  CKeyWords
-//                  CExpData
-//                  CMdlType
-//                  CAuthor
-//                  CRevData
-//                  CSupersede
-//                  CJournal
-//                  CRemark
-//                  CBiomolecule
-//                  CMMDBTitle       ( MMDB title section )
-//
-//   (C) E. Krissinel 2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Title__
-#define __MMDB_Title__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef  __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef  __MMDB_Utils__
-#include "mmdb_utils.h"
-#endif
-
-#ifndef  __MMDB_MMCIF__
-#include "mmdb_mmcif.h"
-#endif
-
-
-//  ====================  CTitleContainer  ======================
-
-DefineClass(CTitleContainer);
-DefineStreamFunctions(CTitleContainer);
-
-class CTitleContainer : public CClassContainer  {
-
-  public :
-
-    CTitleContainer  () : CClassContainer() {}
-    CTitleContainer  ( RPCStream Object )
-                        : CClassContainer ( Object ) {}
-    ~CTitleContainer () {}
-
-    PCContainerClass MakeContainerClass ( int ClassID );
-
-};
-
-
-//  ==================  CObsLine  ========================
-
-DefineClass(CObsLine);
-DefineStreamFunctions(CObsLine);
-
-class CObsLine : public CContainerClass  {
-
-  public :
-
-    Date   repDate;    //  date of replacement
-    IDCode idCode;     //  ID code of replaced entry
-    IDCode rIdCode[8]; //  ID codes of entries that replaced this one
-
-    CObsLine ();
-    CObsLine ( cpstr S );
-    CObsLine ( RPCStream Object );
-    ~CObsLine();
-
-    void  PDBASCIIDump    ( pstr S, int N   );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_ObsLine; }
-
-    void  Copy  ( PCContainerClass ObsLine );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitObsLine();
-
-};
-
-
-//  ====================  CTitleLine  =====================
-
-DefineClass(CTitleLine);
-DefineStreamFunctions(CTitleLine);
-
-class CTitleLine : public CContString  {
-
-  public :
-
-    CTitleLine ();
-    CTitleLine ( cpstr S );
-    CTitleLine ( RPCStream Object );
-    ~CTitleLine();
-
-    int   ConvertPDBASCII ( cpstr S );
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile ) { return False; }
-    int   GetClassID      () { return ClassID_TitleLine; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass TitleLine );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitTitleLine();
-
-};
-
-
-//  ====================  CCaveat  =====================
-
-DefineClass(CCaveat);
-DefineStreamFunctions(CCaveat);
-
-class CCaveat : public CContString  {
-
-  public :
-
-    IDCode idCode;   //  ID code of the entry
-
-    CCaveat ();
-    CCaveat ( cpstr S );
-    CCaveat ( RPCStream Object );
-    ~CCaveat();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile ) { return False; }
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    int   GetClassID      () { return ClassID_CAVEAT; }
-
-    void  Copy  ( PCContainerClass Caveat );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitCaveat();
-
-};
-
-
-//  ====================  CCompound  =====================
-
-DefineClass(CCompound);
-DefineStreamFunctions(CCompound);
-
-class CCompound : public CContString  {
-
-  public :
-
-    CCompound ();
-    CCompound ( cpstr S );
-    CCompound ( RPCStream Object );
-    ~CCompound();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile  ) { return False; }
-    int   ConvertPDBASCII ( cpstr S );
-    int   GetClassID      () { return ClassID_Compound; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass Compound );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitCompound();
-
-};
-
-
-//  ====================  CSource  =====================
-
-DefineClass(CSource);
-DefineStreamFunctions(CSource);
-
-class CSource : public CContString  {
-
-  public :
-
-    CSource ();
-    CSource ( cpstr S );
-    CSource ( RPCStream Object );
-    ~CSource();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile  ) { return False; }
-    int   ConvertPDBASCII ( cpstr S );
-    int   GetClassID      () { return ClassID_Source; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass Source );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitSource();
-
-};
-
-
-//  ====================  CKeyWords  =====================
-
-DefineClass(CKeyWords);
-DefineStreamFunctions(CKeyWords);
-
-class CKeyWords : public CStream  {
-
-  public :
-
-    int      nKeyWords;     // number of key words
-    psvector KeyWord;       // key word array
-
-    CKeyWords ();
-    CKeyWords ( cpstr S );
-    CKeyWords ( RPCStream Object );
-    ~CKeyWords();
-
-    void  Delete          ();
-
-    void  PDBASCIIDump    ( RCFile f );
-    void  MakeCIF         ( PCMMCIFData CIF );
-
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF );
-
-    void  Copy  ( PCKeyWords KeyWords );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    Boolean Cont;
-
-    void  Init();
-
-};
-
-
-//  ====================  CExpData  =====================
-
-DefineClass(CExpData);
-DefineStreamFunctions(CExpData);
-
-class CExpData : public CContString  {
-
-  public :
-
-    CExpData ();
-    CExpData ( cpstr S );
-    CExpData ( RPCStream Object );
-    ~CExpData();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile ) { return False; }
-
-    int   ConvertPDBASCII ( cpstr S );
-    int   GetClassID      () { return ClassID_ExpData; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass ExpData );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitExpData();
-
-};
-
-
-//  ====================  CMdlType  =====================
-
-DefineClass(CMdlType);
-DefineStreamFunctions(CMdlType);
-
-class CMdlType : public CContString  {
-
-  public :
-
-    CMdlType ();
-    CMdlType ( cpstr S );
-    CMdlType ( RPCStream Object );
-    ~CMdlType();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile ) { return False; }
-
-    int   ConvertPDBASCII ( cpstr S );
-    int   GetClassID      () { return ClassID_MdlType; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass ExpData );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitMdlType();
-
-};
-
-
-//  ====================  CAuthor  =====================
-
-DefineClass(CAuthor);
-DefineStreamFunctions(CAuthor);
-
-class CAuthor : public CContString  {
-
-  public :
-
-    CAuthor ();
-    CAuthor ( cpstr S );
-    CAuthor ( RPCStream Object );
-    ~CAuthor();
-
-    void  PDBASCIIDump    ( pstr S, int N   );
-    Boolean PDBASCIIDump1 ( RCFile ) { return False; }
-
-    int   ConvertPDBASCII ( cpstr S );
-    int   GetClassID      () { return ClassID_Author; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass Author );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitAuthor();
-
-};
-
-
-//  ====================  CRevData  =====================
-
-DefineClass(CRevData);
-DefineStreamFunctions(CRevData);
-
-#define REVDAT_WARN_MODNUM   0x00000001
-#define REVDAT_WARN_MODTYPE  0x00000002
-
-class CRevData : public CContainerClass  {
-
-  public :
-
-    int     modNum;
-    Date    modDate;
-    char    modId[13];
-    int     modType;
-    RecName record[4];
-    word    Warning;
-
-    CRevData ();
-    CRevData ( cpstr S );
-    CRevData ( RPCStream Object );
-    ~CRevData();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-
-    int   GetClassID      () { return ClassID_RevData; }
-
-    void  Copy  ( PCContainerClass RevData );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitRevData();
-
-};
-
-
-//  ==================  CSupersede  ========================
-
-DefineClass(CSupersede);
-DefineStreamFunctions(CSupersede);
-
-class CSupersede : public CContainerClass  {
-
-  public :
-
-    Date   sprsdeDate;  //  date of supersede
-    IDCode idCode;      //  ID code of the entry
-    IDCode sIdCode[8];  //  ID codes of superseded entries
-
-    CSupersede ();
-    CSupersede ( cpstr S );
-    CSupersede ( RPCStream Object );
-    ~CSupersede();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-
-    int   GetClassID      () { return ClassID_Supersede; }
-
-    void  Copy  ( PCContainerClass Supersede );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitSupersede();
-
-};
-
-
-//  ====================  CJournal  =====================
-
-DefineClass(CJournal);
-DefineStreamFunctions(CJournal);
-
-class CJournal : public CContString  {
-
-  public :
-
-    CJournal ();
-    CJournal ( cpstr S );
-    CJournal ( RPCStream Object );
-    ~CJournal();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile ) { return False; }
-
-    int   ConvertPDBASCII ( cpstr S );
-    int   GetClassID      () { return ClassID_Journal; }
-
-//    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-//    void  MakeCIF         ( PCMMCIFData CIF, int N        );
-//    void  Copy  ( PCContainerClass Journal );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitJournal();
-
-};
-
-
-//  ====================  CRemark  =====================
-
-DefineClass(CRemark);
-DefineStreamFunctions(CRemark);
-
-class CRemark : public CContainerClass  {
-
-  public :
-
-    int  remarkNum;  // remark id
-    pstr Remark;     // remark line
-
-    CRemark ();
-    CRemark ( cpstr S );
-    CRemark ( RPCStream Object );
-    ~CRemark();
-
-    void  PDBASCIIDump    ( pstr S, int N );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-
-    int   ConvertPDBASCII ( cpstr S );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-
-    int   GetClassID      () { return ClassID_Remark; }
-
-    void  Copy  ( PCContainerClass RemarkClass );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-
-    void InitRemark();
-
-};
-
-//  =================  CBiomolecule  =====================
-
-DefineClass(CBMApply);
-DefineStreamFunctions(CBMApply);
-
-class CBMApply : public CStream  {
-
-  public :
-    PChainID  chain;
-    int       nChains;
-    pmat44    tm;
-    int       nMatrices;
-
-    CBMApply ();
-    CBMApply ( RPCStream Object );
-    ~CBMApply();
-
-    void  FreeMemory();
-
-    int   addChains ( int & i, RPCRemark rem, RCTitleContainer Remark );
-    int addMatrices ( int & i, RPCRemark rem, RCTitleContainer Remark );
-
-    void  Copy  ( PCBMApply BMA );  // if BMA is NULL, then empties
-                                    // the class
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    void  InitBMApply();
-
-};
-
-
-DefineClass(CBiomolecule);
-DefineStreamFunctions(CBiomolecule);
-
-class CBiomolecule : public CStream  {
-
-  public :
-    PPCBMApply BMApply;
-    int        nBMAs;
-
-    CBiomolecule ();
-    CBiomolecule ( RPCStream Object );
-    ~CBiomolecule();
-
-    void  FreeMemory();
-
-    PCBMApply addBMApply();
-
-    int     Size();
-    Boolean checkComposition ( PChainID chID, ivector occ,
-                               ivector  wocc, int n );
-
-    void  Copy  ( PCBiomolecule B );  // if B is NULL, then empties
-                                      // the class
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    void  InitBiomolecule();
-
-};
-
-//  =================  CMMDBTitle  =======================
-
-DefineClass(CMMDBTitle);
-DefineStreamFunctions(CMMDBTitle);
-
-class CMMDBTitle : public CStream  {
-
-  friend class CModel;
-  friend class CChain;
-  friend class CMMDBFile;
-
-  public :
-
-    CMMDBTitle ();
-    CMMDBTitle ( RPCStream Object );
-    ~CMMDBTitle();
-
-    void  FreeMemory ( Boolean keepBiomolecules );
-
-    // Fills the PDB file header
-    void  SetHeader ( cpstr Classification, // any length is Ok
-                      cpstr DepDate,    // DD-MMM-YYYY
-                      cpstr ID_Code );  // not more than 11 chars
-
-    // Interprets the ASCII PDB line belonging to the title section
-    // and fills the corresponding fields.
-    //   Returns zero if the line was converted, otherwise returns a
-    // non-negative value of Error_XXXX.
-    //   PDBString must be not shorter than 81 characters.
-    int   ConvertPDBString ( pstr PDBString );
-
-    // MakePDBString() makes the ASCII PDB HEADER line from the
-    // class data. PDBString must be not shorter than 81 characters.
-    void  MakePDBHeaderString ( pstr PDBString );
-
-    // GetStructureTitle() returns the contents of TITLE record
-    // unfolded into single line. If Title is missing, returns
-    // contents of COMPND(:MOLECULE). If COMPND is missing, returns
-    // HEADER. If Header is missing, returns PDB code. If no PDB
-    // code is there, returns "Not available".
-    pstr  GetStructureTitle ( pstr & S );
-
-    PCTitleContainer GetRemarks();
-    PCTitleContainer GetJournal();
-
-    realtype GetResolution(); // -1.0 mean no resolution record in file
-
-    int   ParseBiomolecules(); // returns the number of biomolecules,
-                               // -2 for general format error
-                               // -3 for errors in BIOMT records
-
-    int   GetNofBiomolecules();
-    void  GetBiomolecules   ( PPCBiomolecule & BM, int & nBMs );
-    PCBiomolecule GetBiomolecule ( int bmNo ); // bmno=0,1,..
-                               // returns NULL if bmNo is incorrect
-
-    void  PDBASCIIDump ( RCFile      f   );
-    void  MakeCIF      ( PCMMCIFData CIF );
-
-    //   GetCIF(..) returns the same code as ConvertPDBString(..)
-    // save for Error_WrongSection
-    int   GetCIF       ( PCMMCIFData CIF );
-
-    pstr   GetIDCode() { return idCode; }
-    Boolean GetCol73() { return col73;  }
-    void  TrimInput ( pstr PDBString );
-
-    void  Copy  ( PCMMDBTitle TS );  // if TS is NULL, then empties
-                                     // the class
-
-    void  write ( RCFile f );    // writes header to PDB binary file
-    void  read  ( RCFile f );    // reads header from PDB binary file
-
-  protected :
-
-    //   Header data
-    pstr     classification;  // classification of the molecule
-    Date     depDate;         // deposition date DD-MMM-YYYY
-    IDCode   idCode;          // unique PDB identifier
-    realtype resolution;      // resolution
-    Boolean  col73;           // True if columns 73-80 contain PDB ID
-
-    CTitleContainer ObsData;     // obsoletion data
-    CTitleContainer Title;       // title data
-    CTitleContainer CAVEAT;      // error data
-    CTitleContainer Compound;    // compound data
-    CTitleContainer Source;      // source
-    CKeyWords       KeyWords;    // key words
-    CTitleContainer ExpData;     // experimental data
-    CTitleContainer MdlType;     // model desctiptions
-    CTitleContainer Author;      // author data
-    CTitleContainer RevData;     // revision data
-    CTitleContainer Supersede;   // supersede records
-    CTitleContainer Journal;     // journal records
-    CTitleContainer Remark;      // remark records
-
-    PPCBiomolecule  Biomolecule;
-    int             nBiomolecules;
-
-    void  Init();
-    void  FreeBiomolecules();
-
-    PCBiomolecule addBiomolecule();
-
-};
-
-extern void  TestHeader();
-extern void  TestTitle (); // reads PDB title from file 'in.title'
-                           // and rewrites it into 'out.title' and
-                           // 'abin.title'
-
-#endif
-
diff --git a/mmdb/mmdb_uddata.cpp b/mmdb/mmdb_uddata.cpp
deleted file mode 100755
index a76231d..0000000
--- a/mmdb/mmdb_uddata.cpp
+++ /dev/null
@@ -1,537 +0,0 @@
-//  $Id: mmdb_uddata.cpp,v 1.19 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_UDData <implementation>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CUDData ( user-defined data )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __STRING_H
-#include <string.h>
-#endif
-
-
-#ifndef __MMDB_UDData__
-#include "mmdb_uddata.h"
-#endif
-
-
-//  ========================  CUDRegister  ==========================
-
-#define  nUDRTypes  5
-
-CUDRegister::CUDRegister() : CStream()  {
-  InitUDRegister();
-}
-
-CUDRegister::CUDRegister ( RPCStream Object ) : CStream(Object)  {
-  InitUDRegister();
-}
-
-CUDRegister::~CUDRegister()  {
-  FreeUDRegister();
-}
-
-void  CUDRegister::InitUDRegister()  {
-int i;
-  for (i=0;i<nUDRTypes;i++)  {
-    nIUDR[i]       = 0;
-    nRUDR[i]       = 0;
-    nSUDR[i]       = 0;
-    IUDRegister[i] = NULL;
-    RUDRegister[i] = NULL;
-    SUDRegister[i] = NULL;
-  }
-}
-
-void  CUDRegister::FreeUDRegister()  {
-int i,j;
-
-  for (j=0;j<nUDRTypes;j++)  {
-
-    if (IUDRegister[j])  {
-      for (i=0;i<nIUDR[j];i++)
-        if (IUDRegister[j][i])  delete[] IUDRegister[j][i];
-      delete[] IUDRegister[j];
-      IUDRegister[j] = NULL;
-    }
-    nIUDR[j] = 0;
-
-    if (RUDRegister[j])  {
-      for (i=0;i<nRUDR[j];i++)
-        if (RUDRegister[j][i])  delete[] RUDRegister[j][i];
-      delete[] RUDRegister[j];
-      RUDRegister[j] = NULL;
-    }
-    nRUDR[j] = 0;
-    if (SUDRegister[j])  {
-      for (i=0;i<nRUDR[j];i++)
-        if (SUDRegister[j][i])  delete[] SUDRegister[j][i];
-      delete[] SUDRegister[j];
-      SUDRegister[j] = NULL;
-    }
-    nSUDR[j] = 0;
-
-  }
-
-}
-
-int CUDRegister::RegisterUDData ( psvector & UDRegister,
-                                  int      & nUDR,
-                                  cpstr      UDDataID )  {
-psvector UDReg;
-int      i,UDDhandle,n;
-
-  n         = -1;
-  UDDhandle = 0;
-  for (i=0;(i<nUDR) && (!UDDhandle);i++)
-    if (UDRegister[i])  {
-      if (!strcmp(UDDataID,UDRegister[i]))
-        UDDhandle = i+1;
-    } else
-      n = i;
-
-  if (!UDDhandle)  {
-    if (n<0)  {
-      UDReg = new pstr[nUDR+1];
-      for (i=0;i<nUDR;i++)
-        UDReg[i] = UDRegister[i];
-      UDReg[nUDR] = NULL;
-      if (UDRegister)  delete[] UDRegister;
-      UDRegister = UDReg;
-      n = nUDR;
-      nUDR++;
-    }
-    CreateCopy ( UDRegister[n],UDDataID );
-    UDDhandle = n+1;
-  }
-
-  return UDDhandle;
-
-}
-
-static int UDRegisterFlag[nUDRTypes] = {
-  UDRF_ATOM,
-  UDRF_RESIDUE,
-  UDRF_CHAIN,
-  UDRF_MODEL,
-  UDRF_HIERARCHY
-};
-
-
-int  CUDRegister::RegisterUDInteger ( int udr_type,
-                                      cpstr UDDataID )  {
-  if ((udr_type>=0) && (udr_type<nUDRTypes))
-    return RegisterUDData ( IUDRegister[udr_type],
-                            nIUDR[udr_type],UDDataID ) |
-           UDRegisterFlag[udr_type];
-  else
-    return UDDATA_WrongUDRType;
-}
-
-int  CUDRegister::RegisterUDReal ( int udr_type,
-                                   cpstr UDDataID )  {
-  if ((udr_type>=0) && (udr_type<nUDRTypes))
-    return RegisterUDData ( RUDRegister[udr_type],
-                            nRUDR[udr_type],UDDataID ) |
-           UDRegisterFlag[udr_type];
-  else
-    return UDDATA_WrongUDRType;
-}
-
-int  CUDRegister::RegisterUDString ( int udr_type,
-                                     cpstr UDDataID )  {
-  if ((udr_type>=0) && (udr_type<nUDRTypes))
-    return RegisterUDData ( SUDRegister[udr_type],
-                            nSUDR[udr_type],UDDataID ) |
-           UDRegisterFlag[udr_type];
-  else
-    return UDDATA_WrongUDRType;
-}
-
-int  CUDRegister::GetUDDHandle ( int udr_type,
-                                 cpstr UDDataID )  {
-int  i,UDDhandle;
-
-  if ((udr_type>=0) && (udr_type<nUDRTypes))  {
-
-    UDDhandle = 0;
-
-    for (i=0;(i<nIUDR[udr_type]) && (!UDDhandle);i++)
-      if (IUDRegister[udr_type][i])  {
-        if (!strcmp(UDDataID,IUDRegister[udr_type][i]))
-          UDDhandle = i+1;
-      }
-    for (i=0;(i<nRUDR[udr_type]) && (!UDDhandle);i++)
-      if (RUDRegister[udr_type][i])  {
-        if (!strcmp(UDDataID,RUDRegister[udr_type][i]))
-          UDDhandle = i+1;
-      }
-    for (i=0;(i<nSUDR[udr_type]) && (!UDDhandle);i++)
-      if (SUDRegister[udr_type][i])  {
-        if (!strcmp(UDDataID,SUDRegister[udr_type][i]))
-          UDDhandle = i+1;
-      }
-
-    if (UDDhandle)  return UDDhandle | UDRegisterFlag[udr_type];
-              else  return UDDhandle;
-
-  } else
-    return UDDATA_WrongUDRType;
-
-}
-
-
-void  CUDRegister::write ( RCFile f )  {
-int  i,j;
-byte Version=1;
-  f.WriteByte ( &Version );
-  for (j=0;j<nUDRTypes;j++)  {
-    f.WriteInt ( &nIUDR[j] );
-    for (i=0;i<nIUDR[j];i++)
-      f.CreateWrite ( IUDRegister[j][i] );
-    f.WriteInt ( &nRUDR[j] );
-    for (i=0;i<nRUDR[j];i++)
-      f.CreateWrite ( RUDRegister[j][i] );
-    f.WriteInt ( &nSUDR[j] );
-    for (i=0;i<nSUDR[j];i++)
-      f.CreateWrite ( SUDRegister[j][i] );
-  }
-}
-
-void  CUDRegister::read ( RCFile f )  {
-int  i,j;
-byte Version;
-  f.ReadByte ( &Version );
-  FreeUDRegister();
-  for (j=0;j<nUDRTypes;j++)  {
-    f.ReadInt ( &nIUDR[j] );
-    if (nIUDR[j]>0)  {
-      IUDRegister[j] = new pstr[nIUDR[j]];
-      for (i=0;i<nIUDR[j];i++)  {
-        IUDRegister[j][i] = NULL;
-        f.CreateRead ( IUDRegister[j][i] );
-      }
-    }
-    f.ReadInt ( &nRUDR[j] );
-    if (nRUDR[j]>0)  {
-      RUDRegister[j] = new pstr[nRUDR[j]];
-      for (i=0;i<nRUDR[j];i++)  {
-        RUDRegister[j][i] = NULL;
-        f.CreateRead ( RUDRegister[j][i] );
-      }
-    }
-    f.ReadInt ( &nSUDR[j] );
-    if (nSUDR[j]>0)  {
-      SUDRegister[j] = new pstr[nSUDR[j]];
-      for (i=0;i<nSUDR[j];i++)  {
-        SUDRegister[j][i] = NULL;
-        f.CreateRead ( SUDRegister[j][i] );
-      }
-    }
-  }
-}
-
-
-MakeStreamFunctions(CUDRegister)
-
-
-
-//  ==========================  CUDData  ============================
-
-CUDData::CUDData() : CMask()  {
-  InitUDData();
-}
-
-CUDData::CUDData ( RPCStream Object ) : CMask(Object)  {
-  InitUDData();
-}
-
-CUDData::~CUDData()  {
-  FreeUDDMemory();
-}
-
-void CUDData::InitUDData()  {
-  IUData = NULL;
-  RUData = NULL;
-  SUData = NULL;
-}
-
-void CUDData::FreeUDDMemory()  {
-int i,l;
-  FreeVectorMemory ( IUData,0 );
-  FreeVectorMemory ( RUData,0 );
-  if (SUData)  {
-    l = getNofSUData();
-    for (i=0;i<=l;i++)
-      if (SUData[i])  delete[] SUData[i];
-    delete[] SUData;
-  }
-  IUData = NULL;
-  RUData = NULL;
-  SUData = NULL;
-}
-
-int  CUDData::getNofIUData()  {
-  if (!IUData)  return 0;
-  return IUData[0];
-}
-
-int  CUDData::getNofRUData()  {
-  if (!RUData)  return 0;
-  return mround(RUData[0]);
-}
-
-int  CUDData::getNofSUData()  {
-  if (!SUData)    return 0;
-  if (!SUData[0]) return 0;
-  return (int(SUData[0][0]) << 24) +
-         (int(SUData[0][1]) << 16) +
-         (int(SUData[0][2]) << 8)  +
-          int(SUData[0][3]);
-}
-
-void CUDData::setNofSUData ( int newN )  {
-  if (!SUData)    return;
-  if (!SUData[0]) return;
-  SUData[0][3] = byte( newN & 0x000000FF);
-  SUData[0][2] = byte((newN & 0x0000FF00) >> 8);
-  SUData[0][1] = byte((newN & 0x00FF0000) >> 16);
-  SUData[0][0] = byte((newN & 0xFF000000) >> 24);
-}
-
-
-int  CUDData::putUDData ( int UDDhandle, int iudd )  {
-ivector IUD;
-int     i,l,udh;
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  return UDDATA_WrongHandle;
-  l = getNofIUData();
-  if (udh>l)  {
-    GetVectorMemory ( IUD,udh+1,0 );
-    IUD[0] = udh;
-    for (i=1;i<=l;i++)
-      IUD[i] = IUData[i];
-    for (i=l+1;i<udh;i++)
-      IUD[i] = MinInt4;
-    FreeVectorMemory ( IUData,0 );
-    IUData = IUD;
-  }
-  IUData[udh] = iudd;
-  return UDDATA_Ok;
-}
-
-int  CUDData::putUDData ( int UDDhandle, realtype rudd )  {
-rvector RUD;
-int     i,l,udh;
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  return UDDATA_WrongHandle;
-  l = getNofRUData();
-  if (udh>l)  {
-    GetVectorMemory ( RUD,udh+1,0 );
-    RUD[0] = udh;
-    for (i=1;i<=l;i++)
-      RUD[i] = RUData[i];
-    for (i=l+1;i<udh;i++)
-      RUD[i] = -MaxReal;
-    FreeVectorMemory ( RUData,0 );
-    RUData = RUD;
-  }
-  RUData[udh] = rudd;
-  return UDDATA_Ok;
-}
-
-int  CUDData::putUDData ( int UDDhandle, cpstr sudd )  {
-psvector SUD;
-int      i,l,udh;
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  return UDDATA_WrongHandle;
-  l = getNofSUData();
-  if (udh>l)  {
-    if (l>0)  {
-      GetVectorMemory ( SUD,udh+1,0 );
-      for (i=0;i<=l;i++)
-        SUD[i] = SUData[i];
-      for (i=l+1;i<=udh;i++)
-        SUD[i] = NULL;
-      FreeVectorMemory ( SUData,0 );
-      SUData = SUD;
-    } else  {
-      GetVectorMemory ( SUData,udh+1,0 );
-      SUData[0] = new char[4];
-      for (i=1;i<=udh;i++)
-        SUData[i] = NULL;
-    }
-    setNofSUData ( udh );
-  }
-  CreateCopy ( SUData[udh],sudd );
-  return UDDATA_Ok;
-}
-
-int  CUDData::getUDData ( int UDDhandle, int & iudd )  {
-int l,udh;
-  iudd = 0;
-  udh  = UDDhandle & UDRF_MASK;
-  if (udh<1)  return UDDATA_WrongHandle;
-  l = getNofIUData();
-  if (udh>l)  return UDDATA_NoData;
-  iudd = IUData[udh];
-  if (iudd==MinInt4)  return UDDATA_NoData;
-  return UDDATA_Ok;
-}
-
-int  CUDData::getUDData ( int UDDhandle, realtype & rudd )  {
-int l,udh;
-  rudd = 0.0;
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  return UDDATA_WrongHandle;
-  l = getNofRUData();
-  if (udh>l)  return UDDATA_NoData;
-  rudd = RUData[udh];
-  if (rudd==-MaxReal)  return UDDATA_NoData;
-  return UDDATA_Ok;
-}
-
-int  CUDData::getUDData ( int UDDhandle, pstr sudd, int maxLen )  {
-int l,udh;
-  sudd[0] = char(0);
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  return UDDATA_WrongHandle;
-  l = getNofSUData();
-  if (udh>l)  return UDDATA_NoData;
-  if (!SUData[udh])  return UDDATA_NoData;
-  strcpy_n0 ( sudd,SUData[udh],maxLen-1 );
-  return UDDATA_Ok;
-}
-
-pstr  CUDData::getUDData ( int UDDhandle, int * retcode )  {
-int l,udh;
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  {
-    if (retcode)  *retcode = UDDATA_WrongHandle;
-    return NULL;
-  }
-  l = getNofSUData();
-  if (udh>l)  {
-    if (retcode)  *retcode = UDDATA_NoData;
-    return NULL;
-  }
-  if (!SUData[udh])  {
-    if (retcode)  *retcode = UDDATA_NoData;
-    return NULL;
-  }
-  if (retcode)  *retcode = UDDATA_Ok;
-  return SUData[udh];
-}
-
-int  CUDData::getUDData ( int UDDhandle, pstr & sudd )  {
-int l,udh;
-  udh = UDDhandle & UDRF_MASK;
-  if (udh<1)  {
-    if (sudd)  {
-      delete[] sudd;   
-      sudd = NULL;
-    }
-    return UDDATA_WrongHandle;
-  }
-  l = getNofSUData();
-  if (udh>l)  {
-    if (sudd)  {
-      delete[] sudd;   
-      sudd = NULL;
-    }
-    return UDDATA_NoData;
-  }
-  if (!SUData[udh])  {
-    if (sudd)  {
-      delete[] sudd;   
-      sudd = NULL;
-    }
-    return UDDATA_NoData;
-  }
-  CreateCopy ( sudd,SUData[udh] );
-  return UDDATA_Ok;
-}
-    
-
-void  CUDData::write ( RCFile f )  {
-int  i,l;
-byte Version=1;
-
-  f.WriteByte ( &Version );
-
-  CMask::write ( f );
-
-  if (IUData)  l = IUData[0];
-         else  l = -1;
-  f.WriteVector ( IUData,l+1,0 );
-  if (RUData)  l = mround(RUData[0]);
-         else  l = -1;
-  f.WriteVector ( RUData,l+1,0 );
-  l = getNofSUData();
-  f.WriteInt ( &l );
-  for (i=1;i<=l;i++)
-    f.CreateWrite ( SUData[i] );
-}
-
-void  CUDData::read  ( RCFile f )  {
-int  i,l;
-byte Version;
-
-  f.ReadByte ( &Version );
-
-  FreeUDDMemory();
-
-  CMask::read ( f );
-
-  f.CreateReadVector ( IUData,0 );
-  f.CreateReadVector ( RUData,0 );
-  f.ReadInt ( &l );
-  if (l>0)  {
-    SUData = new pstr[l+1];
-    SUData[0] = new char[4];
-    setNofSUData ( l );
-    for (i=1;i<=l;i++)  {
-      SUData[i] = NULL;
-      f.CreateRead ( SUData[i] );
-    }
-  }
-}
-
-
-MakeStreamFunctions(CUDData)
-
-
diff --git a/mmdb/mmdb_uddata.h b/mmdb/mmdb_uddata.h
deleted file mode 100755
index 7c5812f..0000000
--- a/mmdb/mmdb_uddata.h
+++ /dev/null
@@ -1,152 +0,0 @@
-//  $Id: mmdb_uddata.h,v 1.19 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_UDData <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CUDData ( user-defined data )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_UDData__
-#define __MMDB_UDData__
-
-
-#ifndef __MMDB_Mask__
-#include "mmdb_mask.h"
-#endif
-
-
-
-//  ========================  CUDRegister  ==========================
-
-#define UDR_ATOM       0
-#define UDR_RESIDUE    1
-#define UDR_CHAIN      2
-#define UDR_MODEL      3
-#define UDR_HIERARCHY  4
-
-#define UDRF_ATOM       0x01000000
-#define UDRF_RESIDUE    0x02000000
-#define UDRF_CHAIN      0x04000000
-#define UDRF_MODEL      0x08000000
-#define UDRF_HIERARCHY  0x10000000
-#define UDRF_MASK       0x00FFFFFF
-
-
-DefineClass(CUDRegister);
-DefineStreamFunctions(CUDRegister);
-
-class CUDRegister : public CStream  {
-
-  public :
-
-    CUDRegister ();
-    CUDRegister ( RPCStream Object );
-    ~CUDRegister();
-
-    int RegisterUDInteger ( int udr_type, cpstr UDDataID );
-    int RegisterUDReal    ( int udr_type, cpstr UDDataID );
-    int RegisterUDString  ( int udr_type, cpstr UDDataID );
-    int GetUDDHandle      ( int udr_type, cpstr UDDataID );
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected :
-    int      nIUDR[5],nRUDR[5],nSUDR[5];
-    psvector IUDRegister[5];
-    psvector RUDRegister[5];
-    psvector SUDRegister[5];
-
-    void  InitUDRegister ();
-    void  FreeUDRegister ();
-    int   RegisterUDData ( psvector & UDRegister,
-                           int      & nUDR,
-                           cpstr      UDDataID );
-
-};
-
-
-//  ==========================  CUDData  ============================
-
-
-#define UDDATA_Ok             0
-#define UDDATA_WrongHandle   -1
-#define UDDATA_WrongUDRType  -2
-#define UDDATA_NoData        -3
-
-DefineClass(CUDData);
-DefineStreamFunctions(CUDData);
-
-class CUDData : public CMask  {
-
-  friend class CMMDBSelManager;
-
-  public :
-
-    CUDData ();
-    CUDData ( RPCStream Object );
-    ~CUDData();
-
-  protected :
-    ivector  IUData;
-    rvector  RUData;
-    psvector SUData;
-
-    void  InitUDData   ();
-    void  FreeUDDMemory();
-    int   getNofIUData ();
-    int   getNofRUData ();
-    int   getNofSUData ();
-    void  setNofSUData ( int newN );
-
-    int   putUDData ( int UDDhandle, int      iudd );
-    int   putUDData ( int UDDhandle, realtype rudd );
-    int   putUDData ( int UDDhandle, cpstr    sudd );
-
-    int   getUDData ( int UDDhandle, int      & iudd );
-    int   getUDData ( int UDDhandle, realtype & rudd );
-    int   getUDData ( int UDDhandle, pstr sudd, int maxLen );
-    pstr  getUDData ( int UDDhandle, int * retcode=NULL );
-    int   getUDData ( int UDDhandle, pstr     & sudd );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-};
-
-
-#endif
-
diff --git a/mmdb/mmdb_utils.cpp b/mmdb/mmdb_utils.cpp
deleted file mode 100755
index 59b6e8d..0000000
--- a/mmdb/mmdb_utils.cpp
+++ /dev/null
@@ -1,1974 +0,0 @@
-//  $Id: mmdb_utils.cpp,v 1.32 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    14.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDB_Utils  <implementation>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CContainerClass  ( containered class template   )
-//       ~~~~~~~~~   CContString      ( containered string           )
-//                   CClassContainer  ( container of classes         )
-//                   CAtomPath        ( atom path ID                 )
-//                   CQuickSort       ( quick sort of integers       )
-//
-//  **** Functions : Date9to11  ( DD-MMM-YY   -> DD-MMM-YYYY         )
-//       ~~~~~~~~~~~ Date11to9  ( DD-MMM-YYYY -> DD-MMM-YY           )
-//                   Date9toCIF ( DD-MMM-YY   -> YYYY-MM-DD          )
-//                   Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD          )
-//                   DateCIFto9 ( YYYY-MM-DD  -> DD-MMM-YY           )
-//                   DateCIFto11( YYYY-MM-DD  -> DD-MMM-YYYY         )
-//                   GetInteger ( reads integer from a string        )
-//                   GetReal    ( reads real from a string           )
-//                   GetIntIns  ( reads integer and insert code      )
-//                   PutInteger ( writes integer into a string       )
-//                   PutRealF   ( writes real in F-foram into a string)
-//                   PutIntIns  ( writes integer and insert code     )
-//                   CIFGetInteger  ( reads and deletes int from CIF )
-//                   CIFGetReal     ( reads and deletes real from CIF )
-//                   CIFGetString   (reads and deletes string from CIF)
-//                   CIFGetInteger1 (reads and del-s int from CIF loop)
-//                   CIFGetReal1    (reads and del-s int from CIF loop)
-//                   Mat4Inverse    ( inversion of 4x4 matrices      )
-//                   GetErrorDescription (ascii line to an Error_XXXXX)
-//                   ParseAtomID    ( parses atom ID line            )
-//                   ParseResID     ( parses residue ID line         )
-//                   ParseAtomPath  ( parses full atom path          )
-//
-//   (C) E. Krissinel  2000-2013
-//
-//  =================================================================
-//
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __MMDB_Utils__
-#include "mmdb_utils.h"
-#endif
-
-#ifndef IOTBX_PDB_HYBRID_36_C_H
-#include "hybrid_36.h"
-#endif
-
-
-// ====================== Date functions  =======================
-
-static cpstr Month[12] = {
-  "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
-  "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
-};
-
-static cpstr nMonth[12] = {
-  "01", "02", "03", "04", "05", "06",
-  "07", "08", "09", "10", "11", "12"
-};
-
-void  Date9to11 ( cpstr Date9, pstr Date11 )  {
-// converts  DD-MMM-YY to DD-MMM-YYYY
-int i;
-  i = 0;
-  while ((i<12) && (strncmp(Month[i],&(Date9[3]),3)))  i++;
-  if (i<12)  {   // DD-MMM-YY -> DD-MMM-YYYY
-    strncpy ( Date11,Date9,7 );
-    if (Date9[7]!='0')  strncpy ( &(Date11[7]),"19",2 );
-                  else  strncpy ( &(Date11[7]),"20",2 );
-    strncpy ( &(Date11[9]),&(Date9[7]),2 );
-  } else  {      // DD-MM-YY -> DD-MMM-YYYY
-    strncpy ( Date11,Date9,3 );
-    i = 0;
-    while ((i<12) && (strncmp(nMonth[i],&(Date9[3]),2)))  i++;
-    if (i<12)  strncpy ( &(Date11[3]),Month[i],3 );
-    else  {
-      strncpy ( &(Date11[3]),&(Date9[3]),2 );
-      Date11[5] = 'X';
-    }
-    if (Date9[6]!='0')  strncpy ( &(Date11[7]),"19",2 );
-                  else  strncpy ( &(Date11[7]),"20",2 );
-    strncpy ( &(Date11[9]),&(Date9[6]),2 );
-  }
-  Date11[2]  = '-';
-  Date11[6]  = '-';
-  Date11[11] = char(0);
-}
-
-void  Date11to9 ( cpstr Date11, pstr Date9 )  {
-// converts DD-MMM-YYYY to DD-MMM-YY
-int i;
-  i = 0;
-  while ((i<12) && (strncmp(Month[i],&(Date11[3]),3)))  i++;
-  if (i<12)  {   // DD-MMM-YYYY -> DD-MMM-YY
-    strncpy ( Date9,Date11,7 );
-    strncpy ( &(Date9[7]),&(Date11[9]),2 );
-  } else  {      // DD-MM-YYYY -> DD-MMM-YY
-    strncpy ( Date9,Date11,3 );
-    i = 0;
-    while ((i<12) && (strncmp(nMonth[i],&(Date11[3]),2)))  i++;
-    if (i<12)  strncpy ( &(Date9[3]),Month[i],3 );
-    else  {
-      strncpy ( &(Date9[3]),&(Date11[3]),2 );
-      Date9[5] = 'X';
-    }
-    strncpy ( &(Date9[7]),&(Date11[8]),2 );
-  }
-  Date9[2] = '-';
-  Date9[6] = '-';
-}
-
-void  Date9toCIF ( cpstr Date9, pstr DateCIF )  {
-//  DD-MMM-YY -> YYYY-MM-DD             )
-int  i;
-  i = 0;
-  while ((i<12) && (strncmp(Month[i],&(Date9[3]),3)))  i++;
-  if (i<12)  {   //  DD-MMM-YY  -> YYYY-MM-DD
-    if (Date9[7]!='0')  strcpy ( DateCIF,"19" );
-                  else  strcpy ( DateCIF,"20" );
-    strncpy ( &(DateCIF[2]),&(Date9[7]),2 );
-    strncpy ( &(DateCIF[5]),nMonth[i],2 );
-  } else  {      //  DD-MM-YY  ->  YYYY-MM-DD
-    if (Date9[6]!='0')  strcpy ( DateCIF,"19" );
-                  else  strcpy ( DateCIF,"20" );
-    strncpy ( &(DateCIF[2]),&(Date9[6]),2 );
-    strncpy ( &(DateCIF[5]),&(Date9[3]),2 );
-  }
-  DateCIF[4] = '-';
-  DateCIF[7] = '-';
-  strncpy ( &(DateCIF[8]),Date9,2 );
-  DateCIF[10] = char(0);
-}
-
-void  Date11toCIF ( cpstr Date11, pstr DateCIF )  {
-//  DD-MMM-YYYY -> YYYY-MM-DD
-int  i;
-  i = 0;
-  while ((i<12) && (strncmp(Month[i],&(Date11[3]),3)))  i++;
-  if (i<12) {
-    strncpy ( DateCIF,&(Date11[7]),4 );
-    strncpy ( &(DateCIF[5]),nMonth[i],2 );
-  } else  {
-    strncpy ( DateCIF,&(Date11[6]),4 );
-    strncpy ( &(DateCIF[5]),&(Date11[3]),2 );
-  }
-  DateCIF[4] = '-';
-  DateCIF[7] = '-';
-  strncpy ( &(DateCIF[8]),Date11,2 );
-  DateCIF[10] = char(0);
-}
-
-void  DateCIFto9 ( cpstr DateCIF, pstr Date9 )  {
-//  YYYY-MM-DD -> DD-MMM-YY
-int  i;
-  strncpy ( Date9,&(DateCIF[8]),2 );
-  Date9[2] = '-';
-  i = 0;
-  while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2)))  i++;
-  if (i<12) strncpy ( &(Date9[3]),Month[i],3 );
-  else  {
-    strncpy ( &(Date9[3]),&(DateCIF[5]),2 );
-    Date9[5] = 'X';
-  }
-  Date9[6] = '-';
-  strncpy ( &(Date9[7]),&(DateCIF[2]),2 );
-//  DateCIF[9] = char(0);
-}
-
-void  DateCIFto11 ( cpstr DateCIF, pstr Date11 )  {
-//  YYYY-MM-DD  -> DD-MMM-YYYY
-int  i;
-  strncpy ( Date11,&(DateCIF[8]),2 );
-  Date11[2] = '-';
-  i = 0;
-  while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2)))  i++;
-  if (i<12) strncpy ( &(Date11[3]),Month[i],3 );
-  else  {
-    strncpy ( &(Date11[3]),&(DateCIF[5]),2 );
-    Date11[5] = 'X';
-  }
-  Date11[6] = '-';
-  strncpy ( &(Date11[7]),DateCIF,4 );
-//  DateCIF[11] = char(0);
-}
-
-
-//  =============== Format functions  ===================
-
-Boolean GetInteger ( int & N, cpstr S, int M )  {
-//   Returns True if S contains an integer number in its
-// first M characters. This number is returned in N.
-//   The return is False if no integer number may be
-// recognized. In this case, N is assigned MinInt4 value.
-pstr endptr;
-char L[50];
-  strncpy ( L,S,M );
-  L[M] = char(0);
-  N    = mround(strtod(L,&endptr));
-  if ((N==0) && (endptr==L))  {
-    N = MinInt4;  // no number
-    return False;
-  } else
-    return True;
-}
-
-Boolean GetReal ( realtype & R, cpstr S, int M )  {
-//   Returns True if S contains a real number in its
-// first M characters. This number is returned in R.
-//   The return is False if no real number may be
-// recognized. In this case, R is assigned -MaxReal value.
-pstr endptr;
-char L[50];
-  strncpy ( L,S,M );
-  L[M] = char(0);
-  R    = strtod(L,&endptr);
-  if ((R==0.0) && (endptr==L))  {
-    R = -MaxReal;  // no number
-    return False;
-  } else
-    return True;
-}
-
-Boolean  GetIntIns ( int & N, pstr ins, cpstr S, int M )  {
-//   Returns True if S contains an integer number in its
-// first M characters. This number is returned in N. In addition
-// to that, GetIntIns() retrieves the insertion code which may
-// follow the integer and returns it in "ins" (1 character +
-// terminating 0).
-//   The return is False if no integer number may be
-// recognized. In this case, N is assigned MinInt4 value,
-// "ins" just returns (M+1)th symbol of S (+terminating 0).
-pstr endptr;
-char L[50];
-
-  if (S[M]!=' ')  {
-    ins[0] = S[M];
-    ins[1] = char(0);
-  } else
-    ins[0] = char(0);
-
-  strncpy ( L,S,M );
-  L[M] = char(0);
-  if ((M==4) && ((S[0]>='A') || ((S[0]=='-') && (S[1]>='A'))))
-    hy36decode ( M,L,M,&N);
-  else  {
-    endptr = NULL;
-    N      = mround(strtod(L,&endptr));
-    if ((N==0) && (endptr==L))  {
-      N = MinInt4;  // no number
-      return False;
-    }
-  }
-
-  return True;
-
-}
-
-void  PutInteger ( pstr S, int N, int M )  {
-//  Integer N is converted into ASCII string of length M
-// and pasted onto first M characters of string S. No
-// terminating zero is added.
-//  If N is set to MinInt4, then first M characters of
-// string S are set to the space character.
-int  i;
-char L[50];
-  if (N==MinInt4)
-    for (i=0;i<M;i++)
-      S[i] = ' ';
-  else  {
-    sprintf ( L,"%*i",M,N );
-    strncpy ( S,L,M );
-  }
-}
-
-void  PutRealF ( pstr S, realtype R, int M, int L )  {
-//  Real R is converted into ASCII string of length M
-// and pasted onto first M characters of string S. No
-// terminating zero is added. The conversion is done
-// according to fixed format FM.L
-//  If R is set to -MaxReal, then first M characters of
-// string S are set to the space character.
-int  i;
-char N[50];
-  if (R==-MaxReal)
-    for (i=0;i<M;i++)
-      S[i] = ' ';
-  else  {
-    sprintf ( N,"%*.*f",M,L,R );
-    strncpy ( S,N,M );
-  }
-}
-
-int CIFGetIntegerD ( int & I, PCMMCIFLoop Loop, cpstr Tag,
-                     int defValue )  {
-int RC,Signal;
-  Signal = 0;
-  RC = CIFGetInteger ( I,Loop,Tag,Signal );
-  if (RC)
-    I = defValue;
-  return RC;
-}
-
-int CIFGetInteger ( int & I, PCMMCIFLoop Loop, cpstr Tag,
-                    int & Signal )  {
-int  RC;
-pstr F;
-  RC = Loop->GetInteger ( I,Tag,Signal,True );
-  if (RC==CIFRC_WrongFormat)  {
-    F = Loop->GetString ( Tag,Signal,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,Signal,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,Signal );
-    Signal = -Error_UnrecognizedInteger-1;
-    return Error_UnrecognizedInteger;
-  }
-  if (RC==CIFRC_WrongIndex)  {
-    Signal = -1;
-    return Error_NoData;
-  }
-  if (RC)  {
-    F = Loop->GetString ( Tag,Signal,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,Signal,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,Signal );
-    Signal = -Error_NoData-1;
-    return Error_NoData;
-  }
-  return 0;
-}
-
-
-int CIFGetInteger1 ( int & I, PCMMCIFLoop Loop, cpstr Tag,
-                     int nrow )  {
-int  RC;
-pstr F;
-  RC = Loop->GetInteger ( I,Tag,nrow,True );
-  if (RC==CIFRC_WrongFormat)  {
-    F = Loop->GetString ( Tag,nrow,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,nrow,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,nrow );
-    return Error_UnrecognizedInteger;
-  }
-  if (RC==CIFRC_WrongIndex)
-    return Error_NoData;
-  if (RC)  {
-    F = Loop->GetString ( Tag,nrow,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,nrow,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,nrow );
-    return Error_NoData;
-  }
-  return 0;
-}
-
-
-int CIFGetReal ( realtype & R, PCMMCIFLoop Loop, cpstr Tag,
-                 int & Signal )  {
-int  RC;
-pstr F;
-  RC = Loop->GetReal ( R,Tag,Signal,True );
-  if (RC==CIFRC_WrongFormat)  {
-    F = Loop->GetString ( Tag,Signal,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,Signal,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,Signal );
-    Signal = -Error_UnrecognizedReal-1;
-    return Error_UnrecognizedReal;
-  }
-  if (RC==CIFRC_WrongIndex)  {
-    Signal = -1;
-    return Error_NoData;
-  }
-  if (RC)  {
-    F = Loop->GetString ( Tag,Signal,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,Signal,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,Signal );
-    Signal = -Error_NoData-1;
-    return Error_NoData;
-  }
-  return 0;
-}
-
-
-int CIFGetReal1 ( realtype & R, PCMMCIFLoop Loop, cpstr Tag,
-                  int nrow )  {
-int  RC;
-pstr F;
-  RC = Loop->GetReal ( R,Tag,nrow,True );
-  if (RC==CIFRC_WrongFormat)  {
-    F = Loop->GetString ( Tag,nrow,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,nrow,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,nrow );
-    return Error_UnrecognizedReal;
-  }
-  if (RC==CIFRC_WrongIndex)
-    return Error_NoData;
-  if (RC)  {
-    F = Loop->GetString ( Tag,nrow,RC );
-    if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
-                     Loop->GetCategoryName(),Tag,nrow,F );
-      else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
-                     Loop->GetCategoryName(),Tag,nrow );
-    return Error_NoData;
-  }
-  return 0;
-}
-
-
-int  CIFGetString ( pstr S, PCMMCIFLoop Loop, cpstr Tag,
-                    int row, int SLen, cpstr DefS )  {
-int RC;
-pstr F;
-  F = Loop->GetString ( Tag,row,RC );
-  if ((!RC) && F)  {
-    strncpy ( S,F,SLen-1 );
-    Loop->DeleteField ( Tag,row );
-    return 0;
-  } else  {
-    strcpy ( S,DefS );
-    return 1;
-  }
-}
-
-
-int CIFGetInteger ( int & I, PCMMCIFStruct Struct, cpstr Tag,
-                    Boolean Remove )  {
-int  RC;
-pstr F;
-  RC = Struct->GetInteger ( I,Tag,Remove );
-  if (RC==CIFRC_WrongFormat)  {
-    F = Struct->GetString ( Tag,RC );
-    if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
-                     Struct->GetCategoryName(),Tag,F );
-      else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
-                     Struct->GetCategoryName(),Tag );
-    return Error_UnrecognizedInteger;
-  }
-  if (RC)  {
-    F = Struct->GetString ( Tag,RC );
-    if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
-                     Struct->GetCategoryName(),Tag,F );
-      else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
-                     Struct->GetCategoryName(),Tag );
-    return Error_NoData;
-  }
-  return 0;
-}
-
-int CIFGetReal ( realtype & R, PCMMCIFStruct Struct, cpstr Tag,
-                 Boolean Remove )  {
-int RC;
-pstr F;
-  RC = Struct->GetReal ( R,Tag,Remove );
-  if (RC==CIFRC_WrongFormat)  {
-    F = Struct->GetString ( Tag,RC );
-    if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
-                     Struct->GetCategoryName(),Tag,F );
-      else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
-                     Struct->GetCategoryName(),Tag );
-    return Error_UnrecognizedReal;
-  }
-  if (RC)  {
-    F = Struct->GetString ( Tag,RC );
-    if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
-                     Struct->GetCategoryName(),Tag,F );
-      else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
-                     Struct->GetCategoryName(),Tag );
-    return Error_NoData;
-  }
-  return 0;
-}
-
-int  CIFGetString ( pstr S, PCMMCIFStruct Struct, cpstr Tag,
-                    int SLen, cpstr DefS, Boolean Remove )  {
-int RC;
-pstr F;
-  F = Struct->GetString ( Tag,RC );
-  if ((!RC) && F)  {
-    strcpy_n0 ( S,F,SLen-1 );
-    if (Remove)  Struct->DeleteField ( Tag );
-    return 0;
-  } else  {
-    strcpy ( S,DefS );
-    return 1;
-  }
-}
-
-
-void  PutIntIns ( pstr S, int N, int M, cpstr ins )  {
-//  Integer N is converted into ASCII string of length M
-// and pasted onto first M characters of string S. No
-// terminating zero is added. The insert code ins is put
-// immediately after the integer.
-//  If N is set to MinInt4, then first M+1 characters of
-// string S are set to space, and no insert code are
-// appended.
-int  i;
-char L[50];
-
-  if (N==MinInt4)  {
-    for (i=0;i<=M;i++)
-      S[i] = ' ';
-  } else  {
-    if ((M!=4) || ((N>=-999) && (N<=9999)))
-         sprintf    ( L,"%*i",M,N );
-    else hy36encode ( M,N,L );
-    strcpy_n1 ( S,L,M );
-    if (ins[0]) S[M] = ins[0];
-  }
-
-}
-
-
-void  Mat4Inverse ( mat44 & A, mat44 & AI )  {
-//       ***  FORMER RBRINV(A,AI)  ***
-//   Function to invert 4*4 matrices (AI=A^{-1})
-mat44    c;
-mat33    x;
-realtype s,s1;
-int      ii,jj,i,i1,j,j1;
-
-// ---- Get cofactors of 'a' in array 'c'
-
-  s1 = 1.0;
-  for (ii=0;ii<4;ii++)  {
-    s = s1;
-    for (jj=0;jj<4;jj++)  {
-      i = -1;
-      for (i1=0;i1<4;i1++)
-        if (i1!=ii)  {
-          i++;
-          j = -1;
-          for (j1=0;j1<4;j1++)
-            if (j1!=jj)  {
-              j++;
-              x[i][j] = A[i1][j1];
-            }
-        }
-      c[ii][jj] = s*(x[0][0]*(x[1][1]*x[2][2]-x[1][2]*x[2][1]) +
-                     x[0][1]*(x[1][2]*x[2][0]-x[1][0]*x[2][2]) +
-                     x[0][2]*(x[1][0]*x[2][1]-x[1][1]*x[2][0]));
-      s = -s;
-    }
-    s1 = -s1;
-  }
-
-// ---- Calculate determinant
-
-  s = 0.0;
-  for (i=0;i<4;i++)
-    s += A[i][0]*c[i][0];
-
-// ---- Get inverse matrix
-
-  if (s!=0.0)
-    for (i=0;i<4;i++)
-      for (j=0;j<4;j++)
-        AI[i][j] = c[j][i]/s;
-
-}
-
-realtype Mat3Inverse ( mat33 & A, mat33 & AI )  {
-mat33    c,x;
-realtype s;
-int      ii,jj,i,i1,j,j1;
-
-  // Get cofactors of 'a' in array 'c'
-
-  s = 1.0;
-  for (ii=0;ii<3;ii++)
-    for (jj=0;jj<3;jj++)  {
-      i = -1;
-      for (i1=0;i1<3;i1++)
-        if (i1!=ii)  {
-          i++;
-          j = -1;
-          for (j1=0;j1<3;j1++)
-            if (j1!=jj)  {
-              j++;
-              x[i][j] = A[i1][j1];
-            }
-        }
-      c[ii][jj] = s*(x[0][0]*x[1][1]-x[0][1]*x[1][0]);
-      s = -s;
-    }
-
-  // Calculate determinant
-
-  s = 0.0;
-  for (i=0;i<3;i++)
-    s += A[i][0]*c[i][0];
-
-  // Get inverse matrix
-
-  if (s!=0.0)
-    for (i=0;i<3;i++)
-      for (j=0;j<3;j++)
-        AI[i][j] = c[j][i]/s;
-
-  return s;
-
-}
-
-void  Mat4Mult ( mat44 & A, mat44 & B, mat44 & C )  {
-//  Calculates A=B*C
-int i,j,k;
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)  {
-      A[i][j] = 0.0;
-      for (k=0;k<4;k++)
-        A[i][j] += B[i][k]*C[k][j];
-    }
-}
-
-void  Mat4Div1 ( mat44 & A, mat44 & B, mat44 & C )  {
-//  Calculates A=B^{-1}*C
-mat44 B1;
-int   i,j,k;
-  B1[0][0] = 1.0; // in order to supress warnings from some
-                  // stupid compilers
-  Mat4Inverse ( B,B1 );
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)  {
-      A[i][j] = 0.0;
-      for (k=0;k<4;k++)
-        A[i][j] += B1[i][k]*C[k][j];
-    }
-}
-
-void  Mat4Div2 ( mat44 & A, mat44 & B, mat44 & C )  {
-//  Calculates A=B*C^{-1}
-mat44 C1;
-int   i,j,k;
-  C1[0][0] = 1.0; // in order to supress warnings from some
-                  // stupid compilers
-  Mat4Inverse ( C,C1 );
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)  {
-      A[i][j] = 0.0;
-      for (k=0;k<4;k++)
-        A[i][j] += B[i][k]*C1[k][j];
-    }
-}
-
-void  Mat4Init ( mat44 & A )  {
-int i,j;
-  for (i=0;i<4;i++)  {
-    for (j=0;j<4;j++)
-      A[i][j] = 0.0;
-    A[i][i] = 1.0;
-  }
-}
-
-realtype Mat4RotDet ( mat44 & T )  {
-//  returns determinant of the rotation part
-  return T[0][0]*T[1][1]*T[2][2] +
-         T[0][1]*T[1][2]*T[2][0] +
-         T[1][0]*T[2][1]*T[0][2] -
-         T[0][2]*T[1][1]*T[2][0] -
-         T[0][0]*T[1][2]*T[2][1] -
-         T[2][2]*T[0][1]*T[1][0];
-}
-
-Boolean isMat4Unit ( mat44 & A, realtype eps, Boolean rotOnly )  {
-// returns True if A is a unit 4x4 matrix
-int     i,j,k;
-Boolean B;
-
-  if (rotOnly)  k = 3;
-          else  k = 4;
-
-  B = True;
-  for (i=0;(i<k) && B;i++)
-    for (j=0;(j<k) && B;j++)
-      if (i==j)  B = (fabs(1.0-A[i][j])<eps);
-           else  B = (fabs(A[i][j])<eps);
-
-  return B;
-
-}
-
-void  Mat3Init ( mat33 & A )  {
-int i,j;
-  for (i=0;i<3;i++)  {
-    for (j=0;j<3;j++)
-      A[i][j] = 0.0;
-    A[i][i] = 1.0;
-  }
-}
-
-void  Mat4Copy ( mat44 & A, mat44 & AC )  {
-int i,j;
-  for (i=0;i<4;i++)
-    for (j=0;j<4;j++)
-      AC[i][j] = A[i][j];
-}
-
-void  Mat3Copy ( mat33 & A, mat33 & AC )  {
-int i,j;
-  for (i=0;i<3;i++)
-    for (j=0;j<3;j++)
-      AC[i][j] = A[i][j];
-}
-
-Boolean isMat4Eq ( mat44 & A, mat44 & B, realtype eps,
-                   Boolean rotOnly )  {
-// returns True if A is equal to B within precision eps
-int     i,j,k;
-Boolean Eq;
-
-  if (rotOnly)  k = 3;
-          else  k = 4;
-
-  Eq = True;
-  for (i=0;(i<k) && Eq;i++)
-    for (j=0;(j<k) && Eq;j++)
-      Eq = (fabs(A[i][j]-B[i][j])<eps);
-
-  return Eq;
-
-}
-
-
-void TransformXYZ ( mat44 & T, realtype & X, realtype & Y,
-                                             realtype & Z )  {
-realtype x1,y1,z1;
-  x1 = T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
-  y1 = T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
-  z1 = T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
-  X = x1;
-  Y = y1;
-  Z = z1;
-}
-
-realtype TransformX ( mat44 & T, realtype X, realtype Y,
-                                             realtype Z )  {
-  return  T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
-}
-
-realtype TransformY ( mat44 & T, realtype X, realtype Y,
-                                             realtype Z )  {
-  return  T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
-}
-
-realtype TransformZ ( mat44 & T, realtype X, realtype Y,
-                                             realtype Z )  {
-  return  T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
-}
-
-
-
-
-char CIFErrorLocation[200] = "no error";
-
-static cpstr msWrongSection =
-  "Wrong section. The sections in PDB file may be put in wrong order.";
-static cpstr msWrongChainID =
-  "Wrong chain ID. The input may have changed to another chain.";
-static cpstr msWrongEntryID =
-  "Entry ID does not match the header.";
-
-static cpstr msSEQRES_serNum   =
-  "Serial numbers of SEQRES records do not increment by 1.";
-static cpstr msSEQRES_numRes   =
-  "Different SEQRES records show different numbers of residues.";
-static cpstr msSEQRES_extraRes =
-  "SEQRES records contain more residues than specified.";
-
-static cpstr msNCSM_Unrecognized =
-  "Unrecognized numerical input in MTRIXn.";
-static cpstr msNCSM_AlreadySet   =
-  "Duplicate MTRIXn record.";
-static cpstr msNCSM_WrongSerial  =
-  "Serial number in MTRIXn record is wrong.";
-static cpstr msNCSM_UnmatchIG    =
-  "Different MTRIXn record show different iGiven flag.";
-
-static cpstr msATOM_Unrecognized =
-  "Numerical information in ATOM record is not recognized.";
-static cpstr msATOM_AlreadySet   =
-  "Atom is already in the system.";
-static cpstr msATOM_NoResidue    =
-  "No residue is found for atom.";
-static cpstr msATOM_Unmatch      =
-  "Unmatch in different records for the same atom.";
-
-static cpstr msCantOpenFile        = "File can not be opened.";
-static cpstr msUnrecognizedInteger =
-  "Wrong ASCII format of an integer.";
-static cpstr msWrongModelNo        = "Wrong model number.";
-static cpstr msDuplicatedModel     = "Duplicate model number.";
-static cpstr msNoModel             = "No model defined.";
-static cpstr msForeignFile         =
-  "Attempt to read unknown-type file.";
-static cpstr msWrongEdition        =
-  "Attempt to read a higher-version file.";
-
-static cpstr msNoData              = "Expected data field not found.";
-static cpstr msUnrecognizedReal    = "Wrong ASCII format of a real.";
-static cpstr msNotACIFFile         =
-  "Not a CIF file ('data_' missing).";
-static cpstr msUnrecognCIFItems    =
-  "Unrecognized item(s) in CIF file.";
-static cpstr msMissingCIFField     = "Expected CIF item(s) missing.";
-static cpstr msEmptyCIFLoop        = "Empty CIF loop encountered.";
-static cpstr msUnexpEndOfCIF       = "Unexpected end of CIF file.";
-static cpstr msMissgCIFLoopField   = "Inconsistent CIF loop.";
-static cpstr msNotACIFStructure    =
-  "Wrong use of CIF structure (as a loop?).";
-static cpstr msNotACIFLoop         =
-  "Wrong use of CIF loop (as a structure?).";
-
-static cpstr msNoSheetID           = "No Sheet ID on PDB ASCII card.";
-static cpstr msWrongSheetID        = "Wrong Sheet ID.";
-static cpstr msWrongStrandNo       =
-  "Wrong Strand number on PDB SHEET card.";
-
-static cpstr msWrongNumberOfStrands =
-  "Wrong number of strands in CIF file.";
-static cpstr msWrongSheetOrder     = "Incomplete _struct_sheet_order.";
-static cpstr msHBondInconsistency  =
-  "Inconsistency in _struct_sheet_hbond.";
-
-static cpstr msEmptyResidueName    =
-        "No residue name on PDB ATOM or TER card.";
-static cpstr msDuplicateSeqNum     =
-        "Duplicate sequence number and insertion code.";
-
-static cpstr msEmptyFile           = "Non-existent or empty file.";
-
-static cpstr msNoLogicalName       = "Logical file name not found.";
-
-
-cpstr  GetErrorDescription ( int ErrorCode )  {
-
-  switch (ErrorCode)  {
-
-    case 0                          :  return "No errors.";
-
-    case Error_WrongSection         :  return msWrongSection;
-    case Error_WrongChainID         :  return msWrongChainID;
-    case Error_WrongEntryID         :  return msWrongEntryID;
-
-    case Error_SEQRES_serNum        :  return msSEQRES_serNum;
-    case Error_SEQRES_numRes        :  return msSEQRES_numRes;
-    case Error_SEQRES_extraRes      :  return msSEQRES_extraRes;
-
-    case Error_NCSM_Unrecognized    :  return msNCSM_Unrecognized;
-    case Error_NCSM_AlreadySet      :  return msNCSM_AlreadySet;
-    case Error_NCSM_WrongSerial     :  return msNCSM_WrongSerial;
-    case Error_NCSM_UnmatchIG       :  return msNCSM_UnmatchIG;
-
-    case Error_ATOM_Unrecognized    :  return msATOM_Unrecognized;
-    case Error_ATOM_AlreadySet      :  return msATOM_AlreadySet;
-    case Error_ATOM_NoResidue       :  return msATOM_NoResidue;
-    case Error_ATOM_Unmatch         :  return msATOM_Unmatch;
-
-    case Error_CantOpenFile         :  return msCantOpenFile;
-    case Error_UnrecognizedInteger  :  return msUnrecognizedInteger;
-    case Error_WrongModelNo         :  return msWrongModelNo;
-    case Error_DuplicatedModel      :  return msDuplicatedModel;
-    case Error_NoModel              :  return msNoModel;
-    case Error_ForeignFile          :  return msForeignFile;
-    case Error_WrongEdition         :  return msWrongEdition;
-
-    case Error_NoData               :  return msNoData;
-    case Error_UnrecognizedReal     :  return msUnrecognizedReal;
-    case Error_NotACIFFile          :  return msNotACIFFile;
-    case Error_UnrecognCIFItems     :  return msUnrecognCIFItems;
-    case Error_MissingCIFField      :  return msMissingCIFField;
-    case Error_EmptyCIFLoop         :  return msEmptyCIFLoop;
-    case Error_UnexpEndOfCIF        :  return msUnexpEndOfCIF;
-    case Error_MissgCIFLoopField    :  return msMissgCIFLoopField;
-    case Error_NotACIFStructure     :  return msNotACIFStructure;
-    case Error_NotACIFLoop          :  return msNotACIFLoop;
-
-    case Error_NoSheetID            :  return msNoSheetID;
-    case Error_WrongSheetID         :  return msWrongSheetID;
-    case Error_WrongStrandNo        :  return msWrongStrandNo;
-
-    case Error_WrongNumberOfStrands :  return msWrongNumberOfStrands;
-    case Error_WrongSheetOrder      :  return msWrongSheetOrder;
-    case Error_HBondInconsistency   :  return msHBondInconsistency;
-
-    case Error_EmptyResidueName     :  return msEmptyResidueName;
-    case Error_DuplicateSeqNum      :  return msDuplicateSeqNum;
-
-    case Error_EmptyFile            :  return msEmptyFile;
-
-    case Error_NoLogicalName        :  return msNoLogicalName;
-
-    default                         :  return "Unknown error.";
-
-  }
-}
-
-
-//  ==============  CContainerClass  ====================
-
-CContainerClass::CContainerClass() : CStream()  {
-  ContinuationNo = 0;
-}
-
-CContainerClass::CContainerClass ( RPCStream Object )
-               : CStream(Object)  {
-  ContinuationNo = 0;
-}
-
-Boolean  CContainerClass::Append ( PCContainerClass CC )  {
-  return  (CC->ContinuationNo>1);
-}
-
-
-//  ===================  CContString  =====================
-
-CContString::CContString() : CContainerClass()  {
-  InitString();
-}
-
-CContString::CContString ( cpstr S ) : CContainerClass()  {
-  InitString();
-  ConvertPDBASCII ( S );
-}
-
-CContString::CContString ( RPCStream Object )
-           : CContainerClass(Object)  {
-  InitString();
-}
-
-CContString::~CContString() {
-  if (Line)        delete[] Line;
-  if (CIFCategory) delete[] CIFCategory;
-  if (CIFTag)      delete[] CIFTag;
-}
-
-void  CContString::InitString()  {
-  Line        = NULL;
-  CIFCategory = NULL;
-  CIFTag      = NULL;
-}
-
-int  CContString::ConvertPDBASCII ( cpstr S )  {
-  CreateCopy ( Line,S );
-  return 0;
-}
-
-void  CContString::PDBASCIIDump ( pstr S, int )  {
-  if (Line)  strcpy ( S,Line );
-       else  strcpy ( S,""   );
-}
-
-Boolean CContString::PDBASCIIDump1 ( RCFile f )  {
-  if (Line)  f.WriteLine ( Line );
-       else  f.LF();
-  return True;
-}
-
-void  CContString::GetCIF ( PCMMCIFData CIF, int & Signal )  {
-pstr F;
-int  i,RC;
-char c;
-  if ((!CIFCategory) || (!CIFTag))  {
-    Signal = -1;
-    return;
-  }
-  F = CIF->GetString ( CIFCategory,CIFTag,RC );
-  if (RC || (!F))  {
-    Signal = -1;
-    return;
-  }
-  if (Signal>=(int)strlen(F))  {
-    CIF->DeleteField ( CIFCategory,CIFTag );
-    Signal = -1;
-    return;
-  }
-  i = Signal;
-  while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
-  if ((Signal==0) && (i==0))  {
-    i++;
-    if (((F[Signal]=='\n') && (F[i]=='\r')) ||
-        ((F[Signal]=='\r') && (F[i]=='\n')))  i++;
-    Signal = i;
-    while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
-  }
-  c = F[i];
-  F[i] = char(0);
-  CreateCopy ( Line,&(F[Signal]) );
-  if (c)  {
-    F[i]   = c;
-    Signal = i+1;
-    if (((c=='\n') && (F[Signal]=='\r')) ||
-        ((c=='\r') && (F[Signal]=='\n')))  Signal++;
-  } else
-    CIF->DeleteField ( CIFCategory,CIFTag );
-}
-
-void  CContString::MakeCIF ( PCMMCIFData CIF, int N )  {
-pstr S;
-  if ((!CIFCategory) || (!CIFTag))  return;
-  S = new char[strlen(Line)+5];
-  strcpy ( S,"\n" );
-  strcat ( S,Line );
-  CIF->PutString ( S,CIFCategory,CIFTag,(N!=0) );
-  delete[] S;
-}
-
-Boolean  CContString::Append ( PCContainerClass CC )  {
-  if (CContainerClass::Append(CC))  {
-    if (!Line)  {
-      Line = PCContString(CC)->Line;
-      PCContString(CC)->Line = NULL;
-    } else
-      CreateConcat ( Line,pstr("\n"),PCContString(CC)->Line );
-    return True;
-  }
-  return False;
-}
-
-void  CContString::Copy ( PCContainerClass CString )  {
-  CreateCopy ( Line,PCContString(CString)->Line );
-}
-
-void  CContString::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte   ( &Version    );
-  f.CreateWrite ( Line        );
-  f.CreateWrite ( CIFCategory );
-  f.CreateWrite ( CIFTag      );
-}
-
-void  CContString::read ( RCFile f )  {
-byte Version;
-  f.ReadByte   ( &Version    );
-  f.CreateRead ( Line        );
-  f.CreateRead ( CIFCategory );
-  f.CreateRead ( CIFTag      );
-}
-
-MakeStreamFunctions(CContString)
-
-
-
-//  ==============  CClassContainer  ====================
-
-MakeStreamFunctions(CContainerClass)
-
-CClassContainer::CClassContainer() : CStream()  {
-  Init();
-}
-
-CClassContainer::CClassContainer ( RPCStream Object )
-                : CStream(Object)  {
-  Init();
-}
-
-void CClassContainer::Init()  {
-  length    = 0;
-  Container = NULL;
-}
-
-CClassContainer::~CClassContainer()  {
-  FreeContainer();
-}
-
-void  CClassContainer::FreeContainer()  {
-int i;
-  if (Container)  {
-    for (i=0;i<length;i++)
-      if (Container[i])
-        delete Container[i];
-    delete[] Container;
-  }
-  Container = NULL;
-  length    = 0;
-}
-
-void  CClassContainer::AddData ( PCContainerClass Data )  {
-int               i;
-PPCContainerClass C1;
-  if (!Data)  return;
-  if (length>0)  {
-    i = length-1;
-    while (i>=0)  {
-      if (!Container[i])  i--;
-      else if (Container[i]->GetClassID()!=Data->GetClassID())  i--;
-      else break;
-    }
-    if (i>=0)  {
-      if (Container[i]->Append(Data))  {
-        delete Data;
-        return;
-      }
-    }
-  }
-  C1 = new PCContainerClass[length+1];
-  for (i=0;i<length;i++)
-    C1[i] = Container[i];
-  C1[length] = Data;
-  if (Container)  delete[] Container;
-  Container = C1;
-  length++;
-}
-
-void  CClassContainer::PDBASCIIDump ( RCFile f )  {
-char S[500];
-int  i,j;
-  for (i=0;i<length;i++)
-    if (Container[i])  {
-      if (!Container[i]->PDBASCIIDump1(f))  {
-        Container[i]->PDBASCIIDump ( S,i );
-        j = strlen(S);
-        while (j<80)  S[j++] = ' ';
-        S[80] = char(0);
-        f.WriteLine ( S );
-      }
-    }
-}
-
-int  CClassContainer::GetCIF ( PCMMCIFData CIF, int ClassID )  {
-PCContainerClass ContainerClass;
-int              Signal;
-  Signal = 0;
-  do  {
-    ContainerClass = MakeContainerClass ( ClassID );
-    ContainerClass->GetCIF ( CIF,Signal );
-    if (Signal>=0)
-      AddData ( ContainerClass );
-  } while (Signal>=0);
-  delete ContainerClass;
-  return -(Signal+1);
-}
-
-void  CClassContainer::MakeCIF ( PCMMCIFData CIF )  {
-int i;
-  for (i=0;i<length;i++)
-    if (Container[i])
-      Container[i]->MakeCIF ( CIF,i );
-}
-
-void  CClassContainer::write ( RCFile f )  {
-int  i,ClassID;
-byte Version=1;
-  f.WriteByte ( &Version );
-  f.WriteInt  ( &length  );
-  for (i=0;i<length;i++)
-    if (Container[i])  {
-      ClassID = Container[i]->GetClassID();
-      f.WriteInt ( &ClassID );
-      Container[i]->write ( f );
-    } else  {
-      ClassID = -1;
-      f.WriteInt ( &ClassID );
-    }
-}
-
-PCContainerClass CClassContainer::MakeContainerClass ( int ClassID )  {
-  if (ClassID==ClassID_String)  return new CContString();
-  return new CContainerClass();
-}
-
-PCContainerClass CClassContainer::GetContainerClass (int ContClassNo) {
-  if ((ContClassNo<0) || (ContClassNo>=length))  return NULL;
-  return Container[ContClassNo];
-}
-
-void  CClassContainer::Copy ( PCClassContainer CContainer )  {
-int i;
-  FreeContainer();
-  if (CContainer)  {
-    length = CContainer->length;
-    if (length>0)  {
-      Container = new PCContainerClass[length];
-      for (i=0;i<length;i++)
-        if (CContainer->Container[i])  {
-          Container[i] = MakeContainerClass (
-                            CContainer->Container[i]->GetClassID() );
-          Container[i]->Copy ( CContainer->Container[i] );
-        } else
-          Container[i] = NULL;
-    }
-  }
-}
-
-void  CClassContainer::read ( RCFile f )  {
-int  i,ClassID;
-byte Version;
-  FreeContainer();
-  f.ReadByte ( &Version );
-  f.ReadInt  ( &length  );
-  if (length>0)  {
-    Container = new PCContainerClass[length];
-    for (i=0;i<length;i++)  {
-      f.ReadInt ( &ClassID );
-      if (ClassID>=0)  {
-        Container[i] = MakeContainerClass ( ClassID );
-        Container[i]->read ( f );
-      } else
-        Container[i] = NULL;
-    }
-  }
-}
-
-MakeStreamFunctions(CClassContainer)
-
-
-
-//  ======================  ID parsers  ==========================
-
-
-CAtomPath::CAtomPath() : CStream()  {
-  InitAtomPath();
-}
-
-CAtomPath::CAtomPath ( cpstr ID ) : CStream()  {
-  InitAtomPath();
-  SetPath ( ID );
-}
-
-CAtomPath::CAtomPath  ( RPCStream Object ) : CStream(Object) {
-  InitAtomPath();
-}
-
-CAtomPath::~CAtomPath() {}
-
-void CAtomPath::InitAtomPath()  {
-  modelNo     = 0;
-  chainID [0] = char(0);
-  seqNum      = MinInt4;
-  insCode [0] = char(0);
-  resName [0] = char(0);
-  atomName[0] = char(0);
-  element [0] = char(0);
-  altLoc  [0] = char(0);
-  isSet       = 0;
-}
-
-int CAtomPath::SetPath ( cpstr ID )  {
-//  1. If ID starts with '/':
-//   /mdl/chn/seq(res).i/atm[elm]:a
-//
-//  2. If ID starts with a letter:
-//        chn/seq(res).i/atm[elm]:a
-//
-//  3. If ID starts with a number:
-//            seq(res).i/atm[elm]:a
-//
-//  4. If ID contains colon ':' then
-//     it may be just
-//                       atm[elm]:a
-//
-//  All spaces are ignored. isSet
-// sets bit for each element present.
-// Any element may be a wildcard '*'.
-// Wildcard for model will set modelNo=0,
-// for sequence number will set
-// seqNum=MinInt4.
-//
-// Returns:
-//   0   <-> Ok
-//   -1  <-> wrong numerical format for model
-//   -2  <-> wrong numerical format for sequence number
-//
-char N[100];
-pstr p,p1;
-int  i,k;
-
-  isSet = 0;  // clear all bits.
-
-  p = pstr(ID);
-  while (*p==' ')  p++;
-
-  if (!(*p))  return 0;
-
-  if (*p=='/')  {
-    //  model number
-    p++;
-    i = 0;
-    while ((*p) && (*p!='/'))  {
-      if (*p!=' ')  N[i++] = *p;
-      p++;
-    }
-    N[i] = char(0);
-    if ((!N[0]) || (N[0]=='*'))  modelNo = 0;
-    else {
-      modelNo = mround(strtod(N,&p1));
-      if ((modelNo==0) && (p1==N))  return -1;
-    }
-    isSet |= APATH_ModelNo;
-    if (*p!='/')  return 0;
-    p++;
-    while (*p==' ')  p++;
-  }
-
-  if ((*p<'0') || (*p>'9'))  {
-    //  chain ID
-    i = 0;
-    k = sizeof(ChainID)-1;
-    while ((*p) && (*p!='/'))  {
-      if ((*p!=' ') && (i<k))  chainID[i++] = *p;
-      p++;
-    }
-    chainID[i] = char(0);
-    if (!chainID[0])  {
-      chainID[0] = '*';
-      chainID[1] = char(0);
-    }
-    isSet |= APATH_ChainID;
-    if (*p!='/')  return 0;
-    p++;
-    while (*p==' ')  p++;
-  }
-
-  if (((*p>='0') && (*p<='9')) || (*p=='-') ||
-       (*p=='(') || (*p=='.'))  {
-    //  sequence number, residue name and insertion code
-    i = 0;
-    while ((*p) && (*p!='/'))  {
-      if (*p!=' ')  N[i++] = *p;
-      p++;
-    }
-    N[i] = char(0);
-    i    = ParseResID ( N,seqNum,insCode,resName );
-    if (i==2)  return -2;
-    isSet |= APATH_SeqNum | APATH_InsCode | APATH_ResName;
-    if (*p!='/')  return 0;
-    p++;
-    while (*p==' ')  p++;
-  }
-
-  if (strchr(p,':') || strchr(p,'['))  {
-    // atom name, chemical element and alternative location
-    i = 0;
-    while (*p)  {
-      if (*p!=' ')  N[i++] = *p;
-      p++;
-    }
-    N[i] = char(0);
-    ParseAtomID ( N,atomName,element,altLoc );
-    isSet |= APATH_AtomName | APATH_Element | APATH_AltLoc;
-  }
-
-  return 0;
-
-}
-
-void CAtomPath::write ( RCFile f )  {
-byte Version=1;
-  f.WriteByte ( &Version );
-  CStream::write ( f );
-  f.WriteInt  ( &modelNo );
-  f.WriteInt  ( &seqNum  );
-  f.WriteInt  ( &isSet   );
-  f.WriteTerLine ( chainID ,False );
-  f.WriteTerLine ( insCode ,False );
-  f.WriteTerLine ( resName ,False );
-  f.WriteTerLine ( atomName,False );
-  f.WriteTerLine ( element ,False );
-  f.WriteTerLine ( altLoc  ,False );
-}
-
-void CAtomPath::read ( RCFile f )  {
-byte Version;
-  f.ReadByte ( &Version );
-  CStream::read ( f );
-  f.ReadInt  ( &modelNo );
-  f.ReadInt  ( &seqNum  );
-  f.ReadInt  ( &isSet   );
-  f.ReadTerLine ( chainID ,False );
-  f.ReadTerLine ( insCode ,False );
-  f.ReadTerLine ( resName ,False );
-  f.ReadTerLine ( atomName,False );
-  f.ReadTerLine ( element ,False );
-  f.ReadTerLine ( altLoc  ,False );
-}
-
-
-MakeStreamFunctions(CAtomPath)
-
-
-
-//  --------------------------------------------------------
-
-CQuickSort::CQuickSort() : CStream()  {
-  selSortLimit = 15;
-  data         = NULL;
-  dlen         = 0;
-}
-
-CQuickSort::CQuickSort ( RPCStream Object )
-          : CStream(Object)  {
-  selSortLimit = 15;
-  data         = NULL;
-  dlen         = 0;
-}
-
-int CQuickSort::Compare ( int i, int j )  {
-// sort by increasing data[i]
-  if (((ivector)data)[i]<((ivector)data)[j])  return -1;
-  if (((ivector)data)[i]>((ivector)data)[j])  return  1;
-  return 0;
-}
-
-void CQuickSort::Swap ( int i, int j )  {
-int b;
-  b = ((ivector)data)[i];
-  ((ivector)data)[i] = ((ivector)data)[j];
-  ((ivector)data)[j] = b;
-}
-
-void CQuickSort::SelectionSort ( int left, int right )  {
-int i,j,imin;
-  for (i=left;i<right;i++) {
-    imin = i;
-    for (j=i+1;j<=right;j++)
-      if (Compare(j,imin)<0)  imin = j;
-    Swap ( i,imin );
-  }
-}
-
-int CQuickSort::Partition ( int left, int right )  {
-int lv = left;
-int lm = left-1;
-int rm = right+1;
-  do  {
-    do
-      rm--;
-    while ((rm>0) && (Compare(rm,lv)>0));
-    do
-      lm++;
-    while ((lm<dlen) && (Compare(lm,lv)<0));
-    if (lm<rm)  {
-      if (lv==lm)  lv = rm;
-      else if (lv==rm)  lv = lm;
-      Swap ( lm,rm );
-    }
-  } while (lm<rm);
-  return rm;
-}
-
-void CQuickSort::Quicksort ( int left, int right )  {
-int split_pt;
-  if (left<(right-selSortLimit)) {
-    split_pt = Partition ( left,right );
-    Quicksort ( left,split_pt    );
-    Quicksort ( split_pt+1,right );
-  } else
-    SelectionSort ( left,right );
-}
-
-void CQuickSort::Sort ( void * sortdata, int data_len )  {
-  data = sortdata;
-  dlen = data_len-1;
-  if (data)  Quicksort ( 0,data_len-1 );
-}
-
-//  --------------------------------------------------------
-
-void  takeWord ( pstr & p, pstr wrd, cpstr ter, int l )  {
-pstr p1;
-int  i;
-  p1 = strpbrk ( p,ter );
-  if (!p1)
-    p1 = p + strlen(p);
-  i = 0;
-  while ((p!=p1) && (i<l))  {
-    wrd[i++] = *p;
-    p++;
-  }
-  if (i>=l)  i = l-1;
-  wrd[i] = char(0);
-  p      = p1;
-}
-
-
-void ParseAtomID ( cpstr ID, AtomName aname, Element elname,
-                             AltLoc   aloc )  {
-pstr p;
-
-  p = pstr(ID);
-  while (*p==' ')  p++;
-
-  strcpy ( aname ,"*" );
-  strcpy ( elname,"*" );
-  if (*p)  aloc[0] = char(0);
-     else  strcpy ( aloc,"*" );
-
-  takeWord ( p,aname,pstr("[: "),sizeof(AtomName) );
-
-  if (*p=='[')  {
-    p++;
-    takeWord ( p,elname,pstr("]: "),sizeof(Element) );
-    if (*p==']')  p++;
-  }
-
-  if (*p==':')  {
-    p++;
-    takeWord ( p,aloc,pstr(" "),sizeof(AltLoc) );
-  }
-
-}
-
-int ParseResID ( cpstr ID, int & sn, InsCode inscode,
-                                     ResName resname )  {
-int  RC;
-pstr p,p1;
-char N[100];
-
-  RC = 0;
-
-  p = pstr(ID);
-  while (*p==' ')  p++;
-
-  sn = ANY_RES;
-  strcpy ( inscode,"*" );
-  strcpy ( resname,"*" );
-
-  N[0] = char(0);
-  takeWord ( p,N,pstr("(./ "),sizeof(N) );
-  if ((!N[0]) || (N[0]=='*'))  {
-    sn = ANY_RES;
-    RC = 1;
-  }
-  if (!RC)  {
-    sn = mround(strtod(N,&p1));
-    if (p1==N)  RC = 2;
-          else  inscode[0] = char(0);
-  }
-
-  if (*p=='(')  {
-    p++;
-    takeWord ( p,resname,pstr(")./ "),sizeof(ResName) );
-    if (*p==')')  p++;
-  }
-
-  if (*p=='.')  {
-    p++;
-    takeWord ( p,inscode,pstr("/ "),sizeof(InsCode) );
-  }
-
-  return RC;
-
-}
-
-int ParseAtomPath ( cpstr      ID,
-                    int &      mdl,
-                    ChainID    chn,
-                    int &      sn,
-                    InsCode    ic,
-                    ResName    res,
-                    AtomName   atm,
-                    Element    elm,
-                    AltLoc     aloc,
-                    PCAtomPath DefPath )  {
-//   /mdl/chn/seq(res).i/atm[elm]:a, may be partial
-char    N[100];
-pstr    p,p1;
-int     i,RC;
-Boolean wasRes;
-
-  wasRes = False;
-
-  RC = 0;
-
-  p = pstr(ID);
-  while (*p==' ')  p++;
-
-  mdl = 0;
-  if (*p=='/')  {
-    p++;
-    N[0] = char(0);
-    takeWord ( p,N,pstr("/"),sizeof(N) );
-    if ((!N[0]) || (N[0]=='*'))  mdl = 0;
-    else {
-      mdl = mround(strtod(N,&p1));
-      if ((mdl==0) && (p1==N))  return -1;
-    }
-  } else if (DefPath)  {
-    if (DefPath->isSet & APATH_ModelNo)
-      mdl = DefPath->modelNo;
-  }
-
-  strcpy ( chn,"*" );
-  if (*p=='/')  p++;
-  if ((*p<'0') || (*p>'9'))  {
-    p1 = p;
-    chn[0] = char(0);
-    takeWord ( p,chn,pstr("/"),sizeof(ChainID) );
-    if (strpbrk(chn,"(.[:-"))  { // this was not a chain ID!
-      if (DefPath)  {
-        if (DefPath->isSet & APATH_ChainID)
-          strcpy ( chn,DefPath->chainID );
-      } else
-        strcpy ( chn,"*" );
-      p = p1;
-    }
-  } else if (DefPath)  {
-    if (DefPath->isSet & APATH_ChainID)
-      strcpy ( chn,DefPath->chainID );
-  }
-
-  if (*p=='/')  p++;
-  sn = ANY_RES;
-  strcpy ( ic ,"*" );
-  strcpy ( res,"*" );
-  if (((*p>='0') && (*p<='9')) || (*p=='-') ||
-       (*p=='(') || (*p=='.'))  {
-    wasRes = True;
-    N[0] = char(0);
-    takeWord ( p,N,pstr("/"),sizeof(N) );
-    i = ParseResID ( N,sn,ic,res );
-    if (i==2)  return -2;
-  } else if (DefPath)  {
-    wasRes = (*p=='/');
-    if (DefPath->isSet & APATH_SeqNum)
-      sn = DefPath->seqNum;
-    if (DefPath->isSet & APATH_InsCode)
-      strcpy ( ic,DefPath->insCode );
-    if (DefPath->isSet & APATH_ResName)
-      strcpy ( res,DefPath->resName );
-  }
-
-  if (*p=='/')  p++;
-  strcpy ( atm ,"*" );
-  strcpy ( elm ,"*" );
-  strcpy ( aloc,"*" );
-  if (wasRes || strchr(p,':') || strchr(p,'['))  {
-    ParseAtomID ( p,atm,elm,aloc );
-  } else if (DefPath)  {
-    if (DefPath->isSet & APATH_AtomName)
-      strcpy ( atm,DefPath->atomName );
-    if (DefPath->isSet & APATH_Element)
-      strcpy ( elm,DefPath->element );
-    if (DefPath->isSet & APATH_ResName)
-      strcpy ( aloc,DefPath->altLoc );
-  }
-
-  if (mdl<=0)       RC |= APATH_WC_ModelNo;
-  if (chn[0]=='*')  RC |= APATH_WC_ChainID;
-  if (sn==ANY_RES)  RC |= APATH_WC_SeqNum;
-  if (ic[0]=='*')   RC |= APATH_WC_InsCode;
-  if (res[0]=='*')  RC |= APATH_WC_ResName;
-  if (atm[0]=='*')  RC |= APATH_WC_AtomName;
-  if (elm[0]=='*')  RC |= APATH_WC_Element;
-  if (aloc[0]=='*') RC |= APATH_WC_AltLoc;
-
-  if (RC & (APATH_WC_ModelNo  | APATH_WC_ChainID |
-            APATH_WC_SeqNum   | APATH_WC_InsCode |
-            APATH_WC_AtomName | APATH_WC_AltLoc))
-    RC |= APATH_Incomplete;
-
-  return RC;
-
-}
-
-
-int  ParseSelectionPath (
-             cpstr   CID,
-             int &   iModel,
-             pstr    Chains,
-             int &   sNum1,
-             InsCode ic1,
-             int &   sNum2,
-             InsCode ic2,
-             pstr    RNames,
-             pstr    ANames,
-             pstr    Elements,
-             pstr    altLocs
-                        )  {
-int     l,j;
-pstr    p,p1;
-pstr    N;
-int     seqNum [2];
-InsCode insCode[2];
-pstr    ID;
-Boolean wasModel,wasChain,wasRes,haveNeg;
-
-  l  = IMax(10,strlen(CID))+1;
-  ID = new char[l];
-  N  = new char[l];
-
-  p  = pstr(CID);
-  p1 = ID;
-  while (*p)  {
-    if (*p!=' ')  {
-      *p1 = *p;
-      p1++;
-    }
-    p++;
-  }
-  *p1 = char(0);
-
-  p = ID;
-
-  iModel = 0;
-  strcpy ( Chains,"*" );
-  seqNum[0] = ANY_RES;
-  seqNum[1] = ANY_RES;
-  strcpy ( insCode[0],"*" );
-  strcpy ( insCode[1],"*" );
-  strcpy ( RNames    ,"*" );
-  strcpy ( ANames    ,"*" );
-  strcpy ( Elements  ,"*" );
-  strcpy ( altLocs   ,"*" );
-
-  wasModel = False;
-  wasChain = False;
-  wasRes   = False;
-
-  if (*p=='/')  {
-    //  CID starts with the slash -- take model number first
-    p++;
-    N[0] = char(0);
-    takeWord ( p,N,pstr("/"),l );
-    if ((!N[0]) || (N[0]=='*'))  iModel = 0;
-    else {
-      iModel = mround(strtod(N,&p1));
-      if ((iModel==0) && (p1==N))  return -1;
-    }
-    if (*p=='/')  p++;
-    wasModel = True;
-  }
-
-  if ((*p) && (wasModel || (*p<'0') || (*p>'9')))  {
-    p1 = p;
-    Chains[0] = char(0);
-    takeWord ( p,Chains,pstr("/"),l );
-    if (strpbrk(Chains,"(.[:-"))  {  // this was not a chain ID!
-      strcpy ( Chains,"*" );
-      p = p1;
-    } else
-      wasChain = True;
-    if (*p=='/')  p++;
-  }
-
-  if ((*p) && (wasChain  || ((*p>='0') && (*p<='9')) || (*p=='-') ||
-               (*p=='(') || (*p=='.')  || (*p=='*')))  {
-    j = 0;
-    do  {
-      // take the sequence number
-      haveNeg  = False;
-      if (*p=='-') {
-        haveNeg = True;
-        p++;
-      }
-      N[0] = char(0);
-      takeWord ( p,N,pstr("(.-/"),l );
-      if ((!N[0]) || (N[0]=='*'))
-        seqNum[j] = ANY_RES;
-      else  {
-        seqNum[j] = mround(strtod(N,&p1));
-        if (p1==N)   return -2;
-        if (haveNeg) seqNum[j] = - seqNum[j];
-      }
-      // take the residue list
-      if (*p=='(')  {
-        p++;
-        takeWord ( p,RNames,pstr(").-/"),l );
-        if (*p==')')  p++;
-      }
-      // take the insertion code
-      if (seqNum[j]!=ANY_RES)
-        insCode[j][0] = char(0);
-      if (*p=='.')  {
-        p++;
-        takeWord ( p,insCode[j],pstr("-/"),sizeof(InsCode) );
-      }
-      if (*p=='-')  {
-        p++;
-        j++;
-      } else  {
-        if (j==0)  {
-          seqNum[1] = seqNum[0];
-          strcpy ( insCode[1],insCode[0] );
-        }
-        j = 10;
-      }
-    } while (j<2);
-    wasRes = True;
-  } else
-    wasRes = (*p=='/');
-
-  if (*p=='/')  p++;
-  if ((*p) && (wasRes || strchr(p,':') || strchr(p,'[')))  {
-    if (*p)  altLocs[0] = char(0);
-    takeWord ( p,ANames,pstr("[:"),l );
-    if (!ANames[0])  strcpy ( ANames,"*" );
-    if (*p=='[')  {
-      p++;
-      takeWord ( p,Elements,pstr("]:"),l );
-      if (*p==']')  p++;
-    }
-    if (*p==':')  {
-      p++;
-      takeWord ( p,altLocs,pstr(" "),l );
-    }
-  }
-
-  /*
-  printf ( "  iModel   = %i\n"
-           "  Chains   = '%s'\n"
-           "  seqNum1  = %i\n"
-           "  insCode1 = '%s'\n"
-           "  seqNum2  = %i\n"
-           "  insCode2 = '%s'\n"
-           "  RNames   = '%s'\n"
-           "  ANames   = '%s'\n"
-           "  Elements = '%s'\n"
-           "  altLocs  = '%s'\n",
-           iModel,Chains,seqNum[0],insCode[0],
-           seqNum[1],insCode[1],RNames,ANames,
-           Elements,altLocs );
-  */
-
-  sNum1 = seqNum[0];
-  sNum2 = seqNum[1];
-  strcpy ( ic1,insCode[0] );
-  strcpy ( ic2,insCode[1] );
-
-  delete[] ID;
-  delete[] N;
-
-  return 0;
-
-}
-
-
-void MakeSelectionPath (
-             pstr       CID,
-             int        iModel,
-             cpstr      Chains,
-             int        sNum1,
-             const InsCode ic1,
-             int        sNum2,
-             const InsCode ic2,
-             cpstr      RNames,
-             cpstr      ANames,
-             cpstr      Elements,
-             cpstr      altLocs
-                        )  {
-char S[100];
-int  k;
-
-  if (iModel>0)  {
-    sprintf ( CID,"/%i",iModel );
-    k = 1;
-  } else  {
-    CID[0] = char(0);
-    k = 0;
-  }
-
-  if (Chains[0]!='*')  {
-    if (k>0)  strcat ( CID,"/"    );
-    strcat ( CID,Chains );
-    k = 2;
-  }
-
-  if ((sNum1!=-MaxInt4) || (ic1[0]!='*'))  {
-    if (k>0)  {
-      if (k<2)  strcat ( CID,"/*" );
-      strcat  ( CID,"/" );
-    }
-    if (sNum1>-MaxInt4)  sprintf ( S,"%i",sNum1 );
-                   else  strcpy  ( S,"*" );
-    if (ic1[0]!='*')  {
-      strcat ( S,"." );
-      strcat ( S,ic1 );
-    }
-    strcat ( CID,S );
-
-    if ((sNum2!=-MaxInt4) || (ic2[0]!='*'))  {
-      strcat ( CID,"-" );
-      if (sNum1>-MaxInt4)  sprintf ( S,"%i",sNum2 );
-                     else  strcpy  ( S,"*" );
-      if (ic2[0]!='*')  {
-        strcat ( S,"." );
-        strcat ( S,ic2 );
-      }
-      strcat ( CID,S );
-    }
-
-    k = 3;
-
-  }
-
-  if (RNames[0]!='*')  {
-    if      (k<1)  strcat ( CID,"("    );
-    else if (k<2)  strcat ( CID,"*/*(" );
-    else if (k<3)  strcat ( CID,"/*("  );
-    strcat ( CID,RNames );
-    strcat ( CID,")"    );
-    k = 4;
-  }
-
-  if (ANames[0]!='*')  {
-    if      (k<1)  strcat ( CID,"/*/*/*/" );  // full path
-    else if (k<2)  strcat ( CID,"/*/*/"   );  // /mdl + /*/*/
-    else if (k<3)  strcat ( CID,"/*/"     );  // /mdl/chn + /*/
-    else if (k<4)  strcat ( CID,"/"       );  // /mdl/chn/res + /
-    strcat ( CID,ANames );
-    strcat ( CID,")"    );
-    k = 5;
-  }
-
-  if (Elements[0]!='*')  {
-    if      (k<1)  strcat ( CID,"["       );
-    else if (k<2)  strcat ( CID,"/*/*/*[" );
-    else if (k<3)  strcat ( CID,"/*/*["   );
-    else if (k<4)  strcat ( CID,"/*["     );
-    else if (k<5)  strcat ( CID,"["       );
-    strcat ( CID,Elements );
-    strcat ( CID,"]"    );
-    k = 6;
-  }
-
-  if (altLocs[0]!='*')  {
-    if      (k<1)  strcat ( CID,":"       );
-    else if (k<2)  strcat ( CID,"/*/*/*:" );
-    else if (k<3)  strcat ( CID,"/*/*:"   );
-    else if (k<4)  strcat ( CID,"/*:"     );
-    else if (k<6)  strcat ( CID,":"       );
-    strcat ( CID,altLocs );
-  }
-
-}
diff --git a/mmdb/mmdb_utils.h b/mmdb/mmdb_utils.h
deleted file mode 100755
index d6083b8..0000000
--- a/mmdb/mmdb_utils.h
+++ /dev/null
@@ -1,639 +0,0 @@
-//  $Id: mmdb_utils.h,v 1.25 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or
-//    modify it under the terms of the GNU Lesser General Public
-//    License version 3, modified in accordance with the provisions
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser
-//    General Public License along with this library. If not, copies
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    14.06.13   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :   MMDBF_Utils <interface>
-//       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//
-//  **** Classes :   CContainerClass  ( containered class template    )
-//       ~~~~~~~~~   CContString      ( containered string            )
-//                   CClassContainer  ( container of classes          )
-//                   CAtomPath        ( atom path ID                  )
-//                   CQuickSort       ( quick sort of integers        )
-//
-//  **** Functions : Date9to11  ( DD-MMM-YY   -> DD-MMM-YYYY          )
-//       ~~~~~~~~~~~ Date11to9  ( DD-MMM-YYYY -> DD-MMM-YY            )
-//                   Date9toCIF ( DD-MMM-YY   -> YYYY-MM-DD           )
-//                   Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD           )
-//                   DateCIFto9 ( YYYY-MM-DD  -> DD-MMM-YY            )
-//                   DateCIFto11( YYYY-MM-DD  -> DD-MMM-YYYY          )
-//                   GetInteger ( reads integer from a string         )
-//                   GetReal    ( reads real from a string            )
-//                   GetIntIns  ( reads integer and insert code       )
-//                   PutInteger ( writes integer into a string        )
-//                   PutRealF   ( writes real in F-form into a string )
-//                   PutIntIns  ( writes integer and insert code      )
-//                   CIFGetInteger ( reads and deletes int from CIF   )
-//                   CIFGetReal    ( reads and deletes real from CIF  )
-//                   CIFGetString  ( reads and deletes string from CIF)
-//                   CIFGetInteger1 (reads and del-s int from CIF loop)
-//                   CIFGetReal1    (reads and del-s int from CIF loop)
-//                   Mat4Inverse    ( inversion of 4x4 matrices       )
-//                   GetErrorDescription (ascii line to an Error_XXXXX)
-//                   ParseAtomID    ( parses atom ID line             )
-//                   ParseResID     ( parses residue ID line          )
-//                   ParseAtomPath  ( parses full atom path           )
-//
-//   (C) E. Krissinel  2000-2013
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_Utils__
-#define __MMDB_Utils__
-
-
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-#ifndef __MMDB_Defs__
-#include "mmdb_defs.h"
-#endif
-
-#ifndef __MMDB_MMCIF__
-#include "mmdb_mmcif.h"
-#endif
-
-
-
-// ==================  Date functions  ===================
-
-// converts  DD-MMM-YY  to DD-MMM-YYYY; appends terminating zero
-extern void  Date9to11   ( cpstr Date9, pstr Date11 );
-
-// converts DD-MMM-YYYY to DD-MMM-YY;  does not append terminating zero
-extern void  Date11to9   ( cpstr Date11, pstr Date9 );
-
-// converts DD-MMM-YY   to YYYY-MM-DD;  appends terminating zero
-extern void  Date9toCIF  ( cpstr Date9, pstr DateCIF );
-
-// converts DD-MMM-YYYY to YYYY-MM-DD;  appends terminating zero
-extern void  Date11toCIF ( cpstr Date11, pstr DateCIF );
-
-// converts YYYY-MM-DD  to DD-MMM-YY;   appends terminating zero
-extern void  DateCIFto9  ( cpstr DateCIF, pstr Date9 );
-
-// converts YYYY-MM-DD  to DD-MMM-YYYY; appends terminating zero
-extern void  DateCIFto11 ( cpstr DateCIF, pstr Date11 );
-
-
-// =================  Format functions  ==================
-
-//   Returns True if S contains an integer number in its
-// first M characters. This number is returned in N.
-//   The return is False if no integer number may be
-// recognized. In this case, N is assigned MinInt4 value.
-extern Boolean GetInteger ( int & N, cpstr S, int M );
-
-//   Returns True if S contains a real number in its
-// first M characters. This number is returned in R.
-//   The return is False if no real number may be
-// recognized. In this case, R is assigned -MaxReal value.
-extern Boolean GetReal ( realtype & R, cpstr S, int M );
-
-//   Returns True if S contains an integer number in its
-// first M characters. This number is returned in N. In addition
-// to that, GetIntIns() retrieves the insertion code which may
-// follow the integer and returns it in "ins" (1 character +
-// terminating 0).
-//   The return is False if no integer number may be
-// recognized. In this case, N is assigned MinInt4 value,
-// "ins" just returns (M+1)th symbol of S (+terminating 0).
-extern Boolean  GetIntIns ( int & N, pstr ins, cpstr S, int M );
-
-//  Integer N is converted into ASCII string of length M
-// and pasted onto first M characters of string S. No
-// terminating zero is added.
-//  If N is set to MinInt4, then first M characters of
-// string S are set to space.
-extern void  PutInteger ( pstr S, int N, int M );
-
-//  Real R is converted into ASCII string of length M
-// and pasted onto first M characters of string S. No
-// terminating zero is added. The conversion is done
-// according to fixed format FM.L
-//  If R is set to -MaxReal, then first M characters of
-// string S are set to the space character.
-extern void  PutRealF ( pstr S, realtype R, int M, int L );
-
-//  Integer N is converted into ASCII string of length M
-// and pasted onto first M characters of string S. No
-// terminating zero is added. The insert code ins is put
-// immediately after the integer.
-//  If N is set to MinInt4, then first M+1 characters of
-// string S are set to space, and no insert code are
-// appended.
-extern void  PutIntIns ( pstr S, int N, int M, cpstr ins );
-
-
-//   CIFInteger(..), CIFReal(..) and CIFGetString(..) automate
-// extraction and analysis of data from CIF file. If the data
-// is erroneous or absent, they store an error message in
-// CIFErrorLocation string (below) and return non-zero.
-extern int CIFGetInteger  ( int & I, PCMMCIFStruct Struct,
-                                     cpstr Tag,
-                                     Boolean Remove=True );
-extern int CIFGetReal     ( realtype & R, PCMMCIFStruct Struct,
-                                     cpstr Tag,
-                                     Boolean Remove=True );
-extern int CIFGetString   ( pstr S, PCMMCIFStruct Struct,
-                                    cpstr Tag, int SLen,
-                                    cpstr DefS,
-                                    Boolean Remove=True );
-
-extern int CIFGetInteger  ( int & I, PCMMCIFLoop Loop, cpstr Tag,
-                            int & Signal );
-extern int CIFGetIntegerD ( int & I, PCMMCIFLoop Loop, cpstr Tag,
-                            int defValue=MinInt4 );
-extern int CIFGetInteger1 ( int & I, PCMMCIFLoop Loop, cpstr Tag,
-                            int nrow );
-
-extern int CIFGetReal     ( realtype & R, PCMMCIFLoop Loop,
-                            cpstr Tag, int & Signal );
-extern int CIFGetReal1    ( realtype & R, PCMMCIFLoop Loop,
-                            cpstr Tag, int nrow );
-
-extern int CIFGetString   ( pstr S, PCMMCIFLoop Loop, cpstr Tag,
-                            int row, int SLen, cpstr DefS );
-
-//  Calculates AI=A^{-1}
-extern void  Mat4Inverse ( mat44 & A, mat44 & AI );
-//  Calculates A=B*C
-extern void  Mat4Mult    ( mat44 & A, mat44 & B, mat44 & C );
-//  Calculates A=B^{-1}*C
-extern void  Mat4Div1    ( mat44 & A, mat44 & B, mat44 & C );
-//  Calculates A=B*C^{-1}
-extern void  Mat4Div2    ( mat44 & A, mat44 & B, mat44 & C );
-//  Calculates determinant of the rotation part
-extern realtype Mat4RotDet ( mat44 & T );
-
-//  Sets up a unit matrix
-extern void  Mat4Init     ( mat44 & A );
-extern void  Mat3Init     ( mat33 & A );
-
-//  Calculates AI=A^{-1}, returns determinant
-extern realtype Mat3Inverse ( mat33 & A, mat33 & AI );
-
-extern Boolean isMat4Unit ( mat44 & A, realtype eps, Boolean rotOnly );
-
-//  Copies A into AC
-extern void  Mat4Copy    ( mat44 & A, mat44 & AC );
-extern void  Mat3Copy    ( mat33 & A, mat33 & AC );
-extern Boolean isMat4Eq  ( mat44 & A, mat44 & B, realtype eps,
-                           Boolean rotOnly );
-
-extern void TransformXYZ   ( mat44 & T,
-                            realtype & X, realtype & Y, realtype & Z );
-extern realtype TransformX ( mat44 & T,
-                             realtype X, realtype Y, realtype Z );
-extern realtype TransformY ( mat44 & T,
-                             realtype X, realtype Y, realtype Z );
-extern realtype TransformZ ( mat44 & T,
-                             realtype X, realtype Y, realtype Z );
-
-
-extern char CIFErrorLocation[200];
-
-//  Returns ASCII string explaining the nature of
-// Error_xxxx error code.
-extern cpstr  GetErrorDescription ( int ErrorCode );
-
-
-
-//  ==============  CContainerClass  ====================
-
-DefineClass(CContainerClass)
-DefineStreamFunctions(CContainerClass)
-
-class CContainerClass : public CStream  {
-
-  friend class CClassContainer;
-
-  public :
-
-    CContainerClass ();
-    CContainerClass ( RPCStream Object );
-    ~CContainerClass() {}
-
-    //    ConvertPDBASCII(..) will return one of the Error_XXXXX
-    // constants, see <mmdb_defs.h>
-    virtual int     ConvertPDBASCII ( cpstr     ) { return 0;     }
-    virtual void    PDBASCIIDump    ( pstr, int ) {}
-    virtual Boolean PDBASCIIDump1   ( RCFile    ) { return False; }
-    virtual void    MakeCIF         ( PCMMCIFData, int ) {}
-
-    //   Append(..) should return True if CC is appended to this class.
-    // If this is not the case, CC is merely put on the top of
-    // container.
-    //   Note: Append(..) detects the necessity to append CC and
-    // performs all the necessary actions for that. The rest of CC
-    // will be disposed by Class Container.
-    //   Note: Class Container checks every new class, which is
-    // being added to it (see CClassContainer::AddData(..)), only
-    // against the top of container.
-    virtual Boolean Append ( PCContainerClass CC );
-
-    //  GetCIF(..) extracts any necessary information from CIF and
-    //  returns:
-    //    Signal>=0   : the information was successfully extracted,
-    //                  this instance of container class should be
-    //                  stored, and unchanged value of Signal should
-    //                  be passed to the next (newly created) instance
-    //                  of this container class.
-    //    Signal = -1 : there is no information for this type of
-    //                  containers to extract. This instance of
-    //                  container class should be deleted and input
-    //                  for this type of container class terminated.
-    //    Signal < -1 : error. The code of error is determined as
-    //                  -(Signal+1), then see Error_XXXXX constants
-    //                  in <mmdb_defs.h>. This instance of container
-    //                  class should be deleted and the whole input
-    //                  should be stopped.
-    virtual void GetCIF ( PCMMCIFData, int & Signal )
-                               { Signal = -1;  }
-    virtual int  GetClassID () { return ClassID_Template; }
-
-    virtual void Copy ( PCContainerClass ) {}
-
-    void write ( RCFile ) {}
-    void read  ( RCFile ) {}
-
-  protected :
-    int  ContinuationNo;
-
-};
-
-
-//  ==============  CContString  ====================
-
-DefineClass(CContString)
-DefineStreamFunctions(CContString)
-
-class CContString : public CContainerClass  {
-
-  public :
-
-    pstr Line;  // a string
-
-    CContString ();
-    CContString ( cpstr S );
-    CContString ( RPCStream Object );
-    ~CContString();
-
-    int   ConvertPDBASCII ( cpstr S );
-    void  PDBASCIIDump    ( pstr S, int N );
-    Boolean PDBASCIIDump1 ( RCFile f );
-    void  MakeCIF         ( PCMMCIFData CIF, int N );
-    void  GetCIF          ( PCMMCIFData CIF, int & Signal );
-    Boolean Append        ( PCContainerClass ContString   );
-
-    int   GetClassID      () { return ClassID_String; }
-
-    void  Copy  ( PCContainerClass CString );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    pstr CIFCategory,CIFTag;
-
-    void InitString();
-
-};
-
-
-//  ==============  CClassContainer  ====================
-
-DefineClass(CClassContainer)
-DefineStreamFunctions(CClassContainer)
-
-class CClassContainer : public CStream  {
-
-  public :
-
-    CClassContainer  ();
-    CClassContainer  ( RPCStream Object );
-    ~CClassContainer ();
-
-    void    FreeContainer     ();
-    void    AddData           ( PCContainerClass Data );
-    virtual void PDBASCIIDump ( RCFile f );
-    virtual void MakeCIF      ( PCMMCIFData CIF );
-    //  GetCIF(..) will return one of the Error_XXXXX constants,
-    //  see <mmdb_defs.h>
-    int     GetCIF            ( PCMMCIFData CIF, int ClassID );
-    virtual PCContainerClass MakeContainerClass ( int ClassID );
-
-    // Copy will empty the class if parameter is set to NULL
-    virtual void Copy         ( PCClassContainer CContainer );
-
-    int   Length() { return length; }
-    PCContainerClass  GetContainerClass ( int ContClassNo );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected :
-    int               length;
-    PPCContainerClass Container;
-
-    void Init();
-
-};
-
-
-//  ======================  ID parsers  ==========================
-
-DefineClass(CAtomPath)
-DefineStreamFunctions(CAtomPath)
-
-#define APATH_ModelNo     0x00000001
-#define APATH_ChainID     0x00000002
-#define APATH_SeqNum      0x00000004
-#define APATH_InsCode     0x00000008
-#define APATH_ResName     0x00000010
-#define APATH_AtomName    0x00000020
-#define APATH_Element     0x00000040
-#define APATH_AltLoc      0x00000080
-#define APATH_Incomplete  0x00000100
-#define APATH_WC_ModelNo  0x00001000
-#define APATH_WC_ChainID  0x00002000
-#define APATH_WC_SeqNum   0x00004000
-#define APATH_WC_InsCode  0x00008000
-#define APATH_WC_ResName  0x00010000
-#define APATH_WC_AtomName 0x00020000
-#define APATH_WC_Element  0x00040000
-#define APATH_WC_AltLoc   0x00080000
-
-class CAtomPath : public CStream  {
-
-  public :
-
-    int      modelNo;
-    ChainID  chainID;
-    int      seqNum;
-    InsCode  insCode;
-    ResName  resName;
-    AtomName atomName;
-    Element  element;
-    AltLoc   altLoc;
-    int      isSet;
-
-    CAtomPath  ();
-    CAtomPath  ( cpstr ID );
-    CAtomPath  ( RPCStream Object );
-    ~CAtomPath ();
-
-    //  SetPath(..) parses the Atom Path ID string, which
-    //  may be incomplete. Below {..} means blocks that
-    //  may be omitted; any elements within such blocks
-    //  may be omitted as well.
-    //
-    //  1. If ID starts with '/' then the ID must be of
-    //     the following form:
-    //   /mdl{/chn{/seq(res).i{/atm[elm]:a}}}
-    //
-    //  2. If ID starts with a letter:
-    //        chn{/seq(res).i{/atm[elm]:a}}
-    //
-    //  3. If ID starts with a number or '(':
-    //            seq(res).i{/atm[elm]:a}
-    //
-    //  4. If ID contains colon ':' or '[' then
-    //     it may be just
-    //                       atm[elm]:a
-    //
-    //  The following are valid samples of IDs:
-    //
-    //     /1      model number 1
-    //     /1/A/23(GLU).A/CA[C]:A  model number 1, chain A,
-    //             residue 23 GLU insertion code A, C-alpha
-    //             atom in alternative location A
-    //     A/23    residue 23 of chain A
-    //     CA[C]:  atom C-alpha
-    //     [C]     a carbon
-    //     *[C]:*  same as above
-    //     :A      an atom with insertion code A
-    //     5       residue number 5
-    //     (GLU)   residue GLU
-    //
-    //   All spaces are ignored. SetPath(..) sets bit of isSet
-    // for each element present. Any element may be a wildcard
-    // '*'. Wildcard for model will set modelNo=0, for sequence
-    // number will set seqNum=MinInt4.
-    //
-    // Returns:
-    //   0   <-> Ok
-    //   -1  <-> wrong numerical format for model
-    //   -2  <-> wrong numerical format for sequence number
-    int SetPath ( cpstr ID );
-
-    void write ( RCFile f );
-    void read  ( RCFile f );
-
-  protected :
-    void InitAtomPath();
-
-};
-
-
-//  --------------------------------------------------------------
-
-DefineClass(CQuickSort)
-
-class CQuickSort : public CStream  {
-
-  public :
-    CQuickSort ();
-    CQuickSort ( RPCStream Object );
-    ~CQuickSort() {}
-    virtual int  Compare ( int i, int j );
-    virtual void Swap    ( int i, int j );
-    void Sort ( void * sortdata, int data_len );
-
-  protected :
-    int    selSortLimit,dlen;
-    void * data;
-
-    void SelectionSort ( int left, int right );
-    int  Partition     ( int left, int right );
-    void Quicksort     ( int left, int right );
-
-};
-
-
-//  --------------------------------------------------------------
-
-void  takeWord ( pstr & p, pstr wrd, cpstr ter, int l );
-
-//   ParseAtomID(..) reads the atom ID of the following form:
-//    {name} {[element]} {:altcode}
-// (here {} means that the item may be omitted; any field may have
-// value of wildcard '*'), and returns the atom name in aname,
-// element name - in elname, and alternate location code - in aloc.
-// Except for the alternate location code, missing items are
-// replaced by wildcards. Missing alternate location code is
-// returned as empty string "".
-//   Leading spaces are allowed; any other space will terminate
-// the parsing.
-//   The followings are perfectly valid atom IDs:
-//        CA[C]:A     (carbon C_alpha in location A)
-//        CA[*]:A     (either C_alpha or Ca in location A)
-//        CA:A        (same as above)
-//        CA          (either C_alpha or Ca with no location indicator)
-//        CA[]        (same as above)
-//        CA[C]:      (C_alpha with no location indicator)
-//        [C]         (any carbon with no location indicator)
-//        [C]:*       (any carbon with any location indicator)
-//        *[C]:*      (same as above)
-//        :A          (any atom in location A)
-//        *[*]:A      (same as above)
-//        *[*]:*      (any atom)
-//        *           (any atom with no alternate location indicator)
-extern void ParseAtomID ( cpstr ID, AtomName aname,
-                          Element elname, AltLoc   aloc );
-
-//   ParseResID(..) reads the residue ID of the following form:
-//    {seqnum} {(name)} {.inscode}
-// (here {} means that the item may be omitted; any field may have
-// value of wildcard '*'), and returns the sequence number in sn,
-// insertion code - in inscode, and residue name - in resname.
-// If a wildcard was specified for the sequence number, then
-// ParseResID(..) returns 1. Missing residue name is replaced by
-// the wildcard '*', and misisng insertion code is returned as empty
-// string "".
-//   Leading spaces are allowed; any other space will terminate
-// the parsing.
-//   Return 0 means Ok, 1 - wildcard for the sequence number,
-// 2 - an error in numerical format of the sequence number
-// (other items are parsed).
-//   The followings are perfectly valid residue IDs:
-//        27(ALA).A   (residue 27A ALA)
-//        27().A      (residue 27A)
-//        27(*).A     (same as above)
-//        27.A        (same as above)
-//        27          (residue 27)
-//        27().       (same as above)
-//        (ALA)       (any ALA without insertion code)
-//        (ALA).      (same as above)
-//        (ALA).*     (any ALA)
-//        *(ALA).*    (any ALA)
-//        .A          (any residue with insertion code A)
-//        *(*).A      (same as above)
-//        *(*).*      (any residue)
-//        *           (any residue with no insertion code)
-extern int ParseResID ( cpstr ID, int & sn,
-                        InsCode inscode, ResName resname );
-
-
-//   ParseAtomPath(..) parses an atom path string of the following
-// structure:
-//   /mdl/chn/seq(res).i/atm[elm]:a
-// where all items may be represented by a wildcard '*' and
-//   mdl   - model number (mandatory); at least model #1 is always
-//           present; returned in mdl; on a wildcard mdl is set to 0
-//   chn   - chain identifier ( mandatory); returned in chn; on a
-//           wildcard chn is set to '*'
-//   seq   - residue sequence number (mandatory); returned in sn;
-//           on a wild card ParseAtomPath(..) returns 1
-//   (res) - residue name in round brackets (may be omitted);
-//           returnded in res; on a wildcard res is set to '*'
-//   .i    - insert code after a dot; if '.i' or 'i' is missing
-//           then a residue without an insertion code is looked for;
-//           returned in ic; on a wildcard (any insertion code would
-//           do) ic is set to '*'
-//   atm   - atom name (mandatory); returned in atm; on a wildcard
-//           atm is set to '*'
-//   [elm] - chemical element code in square brackets; it may
-//           be omitted but could be helpful for e.g.
-//           distinguishing C_alpha and CA; returned in elm;
-//           in a wildcard elm is set to '*'
-//   :a    - alternate location indicator after colon; if
-//           ':a' or 'a' is missing then an atom without
-//           alternate location indicator is looked for; returned
-//           in aloc; on a wildcard (any alternate code would do)
-//           aloc is set to '*'.
-// All spaces are ignored, all identifiers should be in capital
-// letters (comparisons are case-sensitive).
-//   The atom path string may be incomplete. If DefPath is supplied,
-// the function will try to get missing elements from there. If
-// missing items may not be found in DefPath, they are replaced by
-// wildcards.
-//   ParseAtomPath(..) returns the following bits:
-//      0                 - Ok
-//      APATH_Incomplete  - if path contains wildcards. Wildcards for
-//                          residue name and chemical element will be
-//                          ignored here if sequence number and
-//                          atom name, correspondingly, are provided.
-//      APATH_WC_XXXXX    - wildcard for different elements
-//      -1                - wrong numerical format for model (fatal)
-//      -2                - wrong numerical format for seqNum (fatal)
-
-extern int ParseAtomPath ( cpstr      ID,
-                           int &      mdl,
-                           ChainID    chn,
-                           int &      sn,
-                           InsCode    ic,
-                           ResName    res,
-                           AtomName   atm,
-                           Element    elm,
-                           AltLoc     aloc,
-                           PCAtomPath DefPath=NULL );
-
-
-
-extern int ParseSelectionPath ( cpstr   CID,
-                                int &   iModel,
-                                pstr    Chains,
-                                int &   sNum1,
-                                InsCode ic1,
-                                int &   sNum2,
-                                InsCode ic2,
-                                pstr    RNames,
-                                pstr    ANames,
-                                pstr    Elements,
-                                pstr    altLocs );
-
-
-
-extern void MakeSelectionPath ( pstr       CID,
-                                int        iModel,
-                                cpstr      Chains,
-                                int        sNum1,
-                                const InsCode ic1,
-                                int        sNum2,
-                                const InsCode ic2,
-                                cpstr      RNames,
-                                cpstr      ANames,
-                                cpstr      Elements,
-                                cpstr      altLocs );
-
-#endif
-
diff --git a/mmdb/mmdb_xml.cpp b/mmdb/mmdb_xml.cpp
deleted file mode 100755
index 55bda48..0000000
--- a/mmdb/mmdb_xml.cpp
+++ /dev/null
@@ -1,954 +0,0 @@
-//  $Id: mmdb_xml.cpp,v 1.25 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_XML <implementation>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CXMLObject
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2010
-//
-//  =================================================================
-//
-
-#ifndef  __STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef  __STRING_H
-#include <string.h>
-#endif
-
-
-#ifndef  __MMDB_XML__
-#include "mmdb_xml.h"
-#endif
-
-
-//  ======================  CXMLObject  ==========================
-
-CXMLObject::CXMLObject() : CStream()  {
-  InitXMLObject();
-}
-
-CXMLObject::CXMLObject ( cpstr Tag ) : CStream()  {
-  InitXMLObject();
-  SetTag  ( Tag );
-}
-
-CXMLObject::CXMLObject ( cpstr Tag, cpstr Data )
-          : CStream()  {
-  InitXMLObject();
-  SetTag  ( Tag  );
-  SetData ( Data );
-}
-
-CXMLObject::CXMLObject ( cpstr Tag, realtype V, int length )
-          : CStream()  {
-  InitXMLObject();
-  SetTag  ( Tag      );
-  SetData ( V,length );
-}
-
-CXMLObject::CXMLObject ( cpstr Tag, int iV, int length )
-          : CStream()  {
-  InitXMLObject();
-  SetTag  ( Tag       );
-  SetData ( iV,length );
-}
-
-CXMLObject::CXMLObject ( cpstr Tag, Boolean bV ) : CStream()  {
-  InitXMLObject();
-  SetTag  ( Tag );
-  SetData ( bV  );
-}
-
-CXMLObject::CXMLObject ( cpstr Tag, PCXMLObject XMLObject )
-          : CStream()  {
-  InitXMLObject();
-  SetTag    ( Tag       );
-  AddObject ( XMLObject );
-}
-
-
-CXMLObject::CXMLObject ( RPCStream Object ) : CStream(Object)  {
-  InitXMLObject();
-}
-
-CXMLObject::~CXMLObject()  {
-  FreeMemory();
-}
-
-void  CXMLObject::InitXMLObject()  {
-  parent      = NULL;
-  objTag      = NULL;
-  objData     = NULL;
-  nObjects    = 0;
-  nAlloc      = 0;
-  object      = NULL;
-  nAttributes = 0;
-  nAttrAlloc  = 0;
-  attr_name   = NULL;
-  attr_value  = NULL;
-}
-
-void  CXMLObject::FreeMemory()  {
-int i;
-
-  if (objTag)   delete[] objTag;
-  if (objData)  delete[] objData;
-
-  objTag   = NULL;
-  objData  = NULL;
-
-  if (object)  {
-    for (i=0;i<nAlloc;i++)
-      if (object[i])  delete object[i];
-    delete[] object;
-  }
-
-  nObjects = 0;
-  nAlloc   = 0;
-  object   = NULL;
-
-  if (attr_name)  {
-    for (i=0;i<nAttrAlloc;i++)  {
-      if (attr_name [i])  delete[] attr_name [i];
-      if (attr_value[i])  delete[] attr_value[i];
-    }
-    FreeVectorMemory ( attr_name ,0 );
-    FreeVectorMemory ( attr_value,0 );
-  }
-
-  nAttributes = 0;
-  nAttrAlloc  = 0;
-  attr_name   = NULL;
-  attr_value  = NULL;
-
-}
-
-void  CXMLObject::SetTag ( cpstr Tag )  {
-pstr p,t;
-int  n;
-
-  // count ampersands
-  p = pstr(Tag);
-  n = 0;
-  while (*p)  {
-    if (*p=='&')  n++;
-    p++;
-  }
-  // calculate the tag length
-  n = n*4 + strlen(Tag) + 1;
-  // substract leading underscores
-  p = pstr(Tag);
-  while (*p=='_')  {
-    p++;
-    n--;
-  }
-  // allocate tag space
-  if (objTag)  delete[] objTag;
-  objTag = new char[n];
-  // copy tag, replacing square brackets and ampersands
-  t = objTag;
-  while (*p)  {
-    if (*p=='[')  {
-      *t = '-';
-      t++;
-    } else if (*p==']')  {
-      if ((p[1]) && (p[1]!='['))  {
-        *t = '-';
-        t++;
-      }
-    } else if (*p=='&')  {
-      strcpy ( t,"_and_" );
-      if (p[1])  t += 5;
-           else  t += 4;
-    } else  {
-      *t = *p;
-      t++;
-    }
-    p++;
-  }
-  *t = char(0);
-}
-
-void  CXMLObject::AddAttribute ( cpstr name, cpstr value )  {
-psvector an,av;
-int      i;
-
-  if (nAttributes>=nAttrAlloc)  {
-    nAttrAlloc = nAttributes + 10;
-    GetVectorMemory ( an,nAttrAlloc,0 );
-    GetVectorMemory ( av,nAttrAlloc,0 );
-    for (i=0;i<nAttrAlloc;i++)  {
-      an[i] = NULL;
-      av[i] = NULL;
-    }
-    for (i=0;i<nAttributes;i++)  {
-      CreateCopy ( an[i],attr_name [i] );
-      CreateCopy ( av[i],attr_value[i] );
-      if (attr_name [i])  delete[] attr_name [i];
-      if (attr_value[i])  delete[] attr_value[i];
-    }
-    FreeVectorMemory ( attr_name ,0 );
-    FreeVectorMemory ( attr_value,0 );
-    attr_name  = an;
-    attr_value = av;
-  }
-
-  CreateCopy ( attr_name [nAttributes],name  );
-  CreateCopy ( attr_value[nAttributes],value );
-  nAttributes++;
-
-}
-
-void  CXMLObject::AddAttribute ( cpstr name, const int iV )  {
-char S[100];
-  sprintf ( S,"%i",iV );
-  AddAttribute ( name,S );
-}
-
-void  CXMLObject::AddAttribute ( cpstr name, const Boolean bV )  {
-  if (bV)  AddAttribute ( name,"Yes" );
-     else  AddAttribute ( name,"No"  );
-}
-
-void  CXMLObject::SetData ( cpstr Data )  {
-pstr p,d;
-int  n;
-  // count ampersands
-  p = pstr(Data);
-  n = 0;
-  while (*p)  {
-    if (*p=='&')  n += 4;
-    p++;
-  }
-  // calculate the Data length
-  n += strlen(Data) + 1;  // eugene
-  // allocate data space
-  if (objData)  delete[] objData;
-  objData = new char[n];
-  // copy data, preceeding ampersands with the escape
-  p = pstr(Data);
-  d = objData;
-  while (*p)  {
-    if (*p=='&')  {
-      d[0] = '&';
-      d[1] = 'a';
-      d[2] = 'm';
-      d[3] = 'p';
-      d[4] = ';';
-      d += 5;
-    } else  {
-      *d = *p;
-      d++;
-    }
-    p++;
-  }
-  *d = char(0);
-}
-
-void  CXMLObject::AddData ( cpstr Data )  {
-pstr d1,d2;
-  d1      = objData;
-  objData = NULL;
-  SetData ( Data );
-  d2      = objData;
-  objData = NULL;
-  CreateConcat ( objData,d1,d2 );
-}
-
-void  CXMLObject::SetData ( const realtype V, const int length )  {
-char N[500];
-  sprintf    ( N,"%-.*g",length,V );
-  CreateCopy ( objData,N );
-}
-
-void  CXMLObject::SetData ( const int iV, const int length )  {
-char N[500];
-  sprintf    ( N,"%*i",length,iV );
-  CreateCopy ( objData,N );
-}
-
-void  CXMLObject::SetData ( const Boolean bV )  {
-  if (bV)  CreateCopy ( objData,pstr("Yes") );
-     else  CreateCopy ( objData,pstr("No")  );
-}
-
-
-int CXMLObject::AddMMCIFCategory ( PCMMCIFCategory mmCIFCat )  {
-  if (mmCIFCat->GetCategoryID()==MMCIF_Loop)
-    return AddMMCIFLoop ( PCMMCIFLoop(mmCIFCat) );
-  if (mmCIFCat->GetCategoryID()==MMCIF_Struct)
-    return AddMMCIFStruct ( PCMMCIFStruct(mmCIFCat) );
-  return -1;
-}
-
-pstr getCCIFTag ( pstr & ccifTag, cpstr Tag )  {
-  if (Tag[0]=='_')  return CreateCopCat ( ccifTag,pstr("ccif") ,Tag );
-              else  return CreateCopCat ( ccifTag,pstr("ccif_"),Tag );
-}
-
-int CXMLObject::AddMMCIFStruct ( PCMMCIFStruct mmCIFStruct )  {
-PCXMLObject XMLObject1,XMLObject2;
-pstr        SName,Tag,Field, ccifTag;
-int         nTags,i,k;
-
-  XMLObject1 = this;
-
-  ccifTag = NULL;
-
-  SName = mmCIFStruct->GetCategoryName();
-  if (SName)  {
-    if (SName[0]!=char(1))
-      XMLObject1 = new CXMLObject ( getCCIFTag(ccifTag,SName) );
-  }
-
-  k = 0;
-  nTags = mmCIFStruct->GetNofTags();
-  for (i=0;i<nTags;i++)  {
-    Tag = mmCIFStruct->GetTag ( i );
-    if (Tag)  {
-      XMLObject2 = new CXMLObject ( getCCIFTag(ccifTag,Tag) );
-      Field = mmCIFStruct->GetField ( i );
-      if (Field)  {
-        if (Field[0]!=char(2))  XMLObject2->SetData ( Field );
-                          else  XMLObject2->SetData ( &(Field[1]) );
-      }
-      XMLObject1->AddObject ( XMLObject2 );
-      k++;
-    }
-  }
-  
-  if (SName)  {
-    if (SName[0]!=char(1))
-      AddObject ( XMLObject1 );
-  }
-
-  if (ccifTag)  delete[] ccifTag;
-
-  return k;
-
-}
-
-int CXMLObject::AddMMCIFLoop ( PCMMCIFLoop mmCIFLoop )  {
-PCXMLObject XMLObject1,XMLObject2,XMLObject3;
-pstr        SName,Tag,Field,ccifTag;
-int         nTags,nRows,i,j,k;
-
-  XMLObject1 = this;
-
-  ccifTag = NULL;
-
-  SName = mmCIFLoop->GetCategoryName();
-  if (SName)  {
-    if (SName[0]!=char(1))
-      XMLObject1 = new CXMLObject ( getCCIFTag(ccifTag,SName) );
-  }
-
-  k = 0;
-  nTags = mmCIFLoop->GetNofTags   ();
-  nRows = mmCIFLoop->GetLoopLength();
-  for (i=0;i<nRows;i++)  {
-    XMLObject2 = new CXMLObject ( pstr("row"),
-                      new CXMLObject(pstr("_sernum_"),i+1) );
-    for (j=0;j<nTags;j++)  {
-      Tag = mmCIFLoop->GetTag ( j );
-      if (Tag)  {
-        XMLObject3 = new CXMLObject ( getCCIFTag(ccifTag,Tag) );
-        Field = mmCIFLoop->GetField ( i,j );
-        if (Field)  {
-          if (Field[0]!=char(2))  XMLObject3->SetData ( Field );
-                            else  XMLObject3->SetData ( &(Field[1]) );
-        }
-        XMLObject2->AddObject ( XMLObject3 );
-        k++;
-      }
-    }
-    XMLObject1->AddObject ( XMLObject2 );
-  }
-  
-  if (SName)  {
-    if (SName[0]!=char(1))
-      AddObject ( XMLObject1 );
-  }
-
-  if (ccifTag)  delete[] ccifTag;
-
-  return k;
-
-}
-
-int  CXMLObject::AddMMCIFData ( PCMMCIFData mmCIFData )  {
-PCMMCIFCategory mmCIFCat;
-int             nCats,i,k,n;
-  nCats = mmCIFData->GetNumberOfCategories();
-  k     = 0;
-  n     = 0;
-  for (i=0;(i<nCats) && (n>=0);i++)  {
-    mmCIFCat = mmCIFData->GetCategory ( i );
-    if (mmCIFCat)  {
-      if (mmCIFCat->GetCategoryID()==MMCIF_Loop)
-        n = AddMMCIFLoop ( PCMMCIFLoop(mmCIFCat) );
-      else if (mmCIFCat->GetCategoryID()==MMCIF_Struct)
-        n = AddMMCIFStruct ( PCMMCIFStruct(mmCIFCat) );
-      else
-        n = -1;
-      if (n>=0)  k += n;
-    }
-  }
-  if (n<0)  return -(k+1);
-  return k;
-}
-
-pstr  CXMLObject::GetData ( cpstr Tag, int objNo )  {
-PCXMLObject XMLObject;
-  XMLObject = GetObject ( Tag,objNo );
-  if (XMLObject)  return XMLObject->objData;
-  return NULL;
-}
-
-int  CXMLObject::GetData ( pstr & Data, cpstr Tag, int objNo )  {
-PCXMLObject XMLObject;
-  XMLObject = GetObject ( Tag,objNo );
-  if (XMLObject)  {
-    Data = XMLObject->objData;
-    return 0;
-  } else  {
-    Data = NULL;
-    return 1;
-  }
-}
-
-int  CXMLObject::GetData ( realtype & V, cpstr Tag, int objNo )  {
-int  rc;
-pstr d,p;
-  rc = GetData ( d,Tag,objNo );
-  if (d)  {
-    V = strtod(d,&p);
-    if ((V==0.0) && (p==d))  rc = 2;
-                       else  rc = 0;
-  } else if (!rc)
-    rc = -1;
-  return rc;
-}
-
-int  CXMLObject::GetData ( int & iV, cpstr Tag, int objNo )  {
-int  rc;
-pstr d,p;
-  rc = GetData ( d,Tag,objNo );
-  if (d)  {
-    iV = mround(strtod(d,&p));
-    if ((iV==0) && (p==d))  rc = 2;
-                      else  rc = 0;
-  } else if (!rc)
-    rc = -1;
-  return rc;
-}
-
-int  CXMLObject::GetData ( Boolean & bV, cpstr Tag, int objNo )  {
-int  rc;
-pstr d;
-  rc = GetData ( d,Tag,objNo );
-  if (d)  {
-    if (!strcasecmp(d,"Yes"))
-      bV = True;
-    else {
-      bV = False;
-      if (strcasecmp(d,"No"))  rc = 2;
-    }
-  } else if (!rc)
-    rc = -1;
-  return rc;
-}
-
-PCXMLObject CXMLObject::GetObject ( cpstr Tag, int objNo )  {
-// allow for "tag1>tag2>tag3>..."
-PCXMLObject XMLObject;
-int         i,j,k,l;
-pstr        p,p1;
-  XMLObject = this;
-  if (Tag)  {
-    p = pstr(Tag);
-    do  {
-      p1 = p;
-      l  = 0;
-      while (*p1 && (*p1!='>'))  {
-        p1++;
-        l++;
-      }
-      if (l>0)  {
-        k = -1;
-        j = 0;
-        for (i=0;(i<XMLObject->nObjects) && (k<0);i++)
-          if (XMLObject->object[i])  {
-            if (!strncmp(XMLObject->object[i]->objTag,p,l))  {
-              j++;
-              if (j==objNo)  k = i;
-            }
-          }
-        if (k<0)  {
-          XMLObject = NULL;
-          l = 0;
-        } else  {
-          XMLObject = XMLObject->object[k];
-          if (*p1)  p = p1 + 1;
-              else  l = 0;
-        }
-      }
-    } while (l>0);
-  }
-  return XMLObject;
-}
-
-PCXMLObject CXMLObject::GetFirstObject()  {
-  if (nObjects>0)  return object[0];
-  return NULL;
-}
-
-PCXMLObject CXMLObject::GetLastObject()  {
-  if (nObjects>0)  return object[nObjects-1];
-  return NULL;
-}
-
-PCXMLObject CXMLObject::GetObject ( int objectNo )  {
-  if ((0<=objectNo) && (objectNo<nObjects))
-    return object[objectNo];
-  return NULL;
-}
-
-
-void  CXMLObject::AddObject ( PCXMLObject XMLObject, int lenInc )  {
-PPCXMLObject obj1;
-int          i;
-
-  if (!XMLObject)  return;
-
-  if (nObjects>=nAlloc)  {
-    nAlloc += lenInc;
-    obj1 = new PCXMLObject[nAlloc];
-    for (i=0;i<nObjects;i++)
-      obj1[i] = object[i];
-    for (i=nObjects;i<nAlloc;i++)
-      obj1[i] = NULL;
-    if (object)  delete[] object;
-    object = obj1;
-  }
-
-  if (object[nObjects])  delete object[nObjects];
-  object[nObjects] = XMLObject;
-  XMLObject->SetParent ( this );
-  nObjects++;
-
-}
-
-int  CXMLObject::WriteObject ( cpstr FName, int pos, int indent )  {
-CFile f;
-  f.assign ( FName,True );
-  if (f.rewrite())  {
-    WriteObject ( f,pos,indent );
-    f.shut();
-    return 0;
-  }
-  return 1;
-}
-
-void  CXMLObject::WriteObject ( RCFile f, int pos, int indent )  {
-int     i,pos1,lm,rm,tl;
-pstr    indstr,p,p1,q;
-Boolean sngline;
-
-  if (objTag)  {
-
-    pos1   = pos + indent;
-    indstr = new char[pos1+1];
-    for (i=0;i<pos1;i++)  indstr[i] = ' ';
-    indstr[pos1] = char(0);
-
-    indstr[pos]  = char(0);
-    f.Write ( indstr    );
-    f.Write ( pstr("<") );
-    f.Write ( objTag    );
-    for (i=0;i<nAttributes;i++)  {
-      f.Write ( " " );
-      f.Write ( attr_name[i] );
-      f.Write ( "=\"" );
-      f.Write ( attr_value[i] );
-      f.Write ( "\"" );
-    }
-    if ((!objData) && (nObjects<=0))  {
-      f.WriteLine ( pstr("/>") );
-      delete[] indstr;
-      return;
-    }
-    f.Write ( pstr(">") );
-
-    sngline = False;
-    if (objData)  {
-      rm = 72;               // right margin
-      lm = IMin ( pos1,36 ); // left margin
-      tl = strlen(objTag);
-      if ((pos+tl+2+(int)strlen(objData)<rm-tl-2) &&
-          (nObjects<=0))  {
-        // single-line output
-        sngline = True;
-        f.Write ( objData );
-      } else  {
-        // multiple-line output with indentation
-        indstr[pos] = ' ';
-        indstr[lm]  = char(0);
-        f.LF();
-        p = objData;
-        do  {
-          p1 = p;
-          i  = lm;
-          q  = NULL;
-          while ((*p1) && ((i<rm) || (!q)))  {
-            if (*p1==' ')  q = p1;
-            p1++;
-            i++;
-          }
-          f.Write ( indstr );
-          if (*p1)  {  // wrap data
-            *q = char(0);
-            f.WriteLine ( p );
-            *q = ' ';
-            p  = q;
-            while (*p==' ')  p++;
-            if (*p==char(0))  p = NULL;
-
-          } else {  // data exchausted
-            f.WriteLine ( p );
-            p = NULL;
-          }
-        } while (p);
-        indstr[lm]  = ' ';
-        indstr[pos] = char(0);
-      }
-    } else
-      f.LF();
-
-    for (i=0;i<nObjects;i++)
-      if (object[i])
-        object[i]->WriteObject ( f,pos+indent,indent );
-
-    if (!sngline)  f.Write ( indstr );
-    f.Write ( pstr("</") );
-    f.Write ( objTag  );
-    f.WriteLine ( pstr(">") );
-
-    delete[] indstr;
-
-  }
-
-}
-
-
-int  CXMLObject::ReadObject ( cpstr FName )  {
-CFile f;
-char  S[500];
-int   i,rc;
-
-  f.assign ( FName,True );
-  if (f.reset(True))  {
-    S[0] = char(0);
-    i    = 0;
-    rc   = ReadObject ( f,S,i,sizeof(S) );
-    f.shut();
-  } else
-    rc = XMLR_NoFile;
-
-  if (rc)  FreeMemory();
-
-  return rc;
-
-}
-
-int  CXMLObject::ReadObject ( RCFile f, pstr S, int & pos, int slen )  {
-PCXMLObject XMLObject;
-pstr        S1;
-int         k,k1,k2,rc;
-Boolean     Done;
-
-  FreeMemory();
-
-  rc = XMLR_Ok;
-
-  k1 = -1;
-  k2 = -1;
-  while ((!f.FileEnd()) && (k1<0))  {
-    k = strlen(S);
-    while ((pos<k) && (k1<0))
-      if (S[pos]=='<')  {
-        if (S[pos+1]=='?') // in this version, ignore <?xxx ?>
-                           //   constructions
-             pos++;
-        else if (S[pos+1]!='<')
-             k1 = pos;
-        else pos += 2;
-      } else
-        pos++;
-    if (k1>=0)  {
-      k2 = -1;
-      while ((pos<k) && (k2<0))
-        if (S[pos]=='>')  {
-          if (S[pos+1]!='>')  k2 = pos;
-                        else  pos += 2;
-        } else
-          pos++;
-      if (k2<0)  rc = XMLR_BrokenTag;
-    }
-    if (k1<0)  {
-      f.ReadLine ( S,slen );
-      pos = 0;
-    }
-  }
-
-  if (k1<0)        return XMLR_NoTag;
-  if (rc!=XMLR_Ok) return rc;
-
-  pos++;
-  if (S[k2-1]=='/')  {  // <Tag/>
-    S[k2-1] = char(0);
-    CreateCopy ( objTag,&(S[k1+1]) );
-    return XMLR_Ok;
-  }
-
-  S[k2] = char(0);
-  CreateCopy ( objTag,&(S[k1+1]) );
-  S[k2] = '>';
-
-  S1   = new char[slen+1];
-  Done = False;
-  while ((!f.FileEnd()) && (!Done))  {
-    k = strlen(S);
-    while ((pos<k) && (!Done))  {
-      k1 = pos;
-      k2 = -1;
-      while ((pos<k) && (k2<0))
-        if (S[pos]=='<')  {
-          if (S[pos+1]!='<')  k2 = pos;
-                        else  pos +=2;
-        } else
-          pos++;
-      if (k2>=0)  S[k2] = char(0);
-      strcpy_des   ( S1,&(S[k1]) );
-      if (S1[0])  {
-        if (objData)  CreateConcat ( objData,pstr(" "),S1 );
-                else  CreateConcat ( objData,S1 );
-      }
-      if (k2>=0)  {
-        S[k2] = '<';
-        if (S[k2+1]!='/')  {
-          XMLObject = new CXMLObject();
-          AddObject ( XMLObject );
-          rc   = XMLObject->ReadObject ( f,S,pos,slen );
-          Done = (rc!=XMLR_Ok);
-        } else  {
-          Done = True;
-          k1   = k2+2;
-          k2   = -1;
-          while ((pos<k) && (k2<0))
-            if (S[pos]=='>')  {
-              if (S[pos+1]!='>')  k2 = pos;
-                            else  pos += 2;
-              } else
-                pos++;
-          if (k2<0)
-            rc = XMLR_BrokenTag;
-          else  {
-            S[k2] = char(0);
-            if (strcmp(objTag,&(S[k1])))  rc = XMLR_UnclosedTag;
-                                    else  pos++;
-          }
-        }
-      }
-    }
-    if (!Done)  {
-      f.ReadLine ( S,slen );
-      pos = 0;
-    }
-  }
-
-  delete[] S1;
-
-  // this keeps pairs <tag></tag> instead of replacing them for <tag/>
-  // on output
-  if ((!objData) && (nObjects<=0))
-    CreateCopy ( objData,pstr("") );
-
-  if (rc!=XMLR_Ok)  FreeMemory();
-  return rc;
-   
-}
-
-
-void  CXMLObject::Copy ( PCXMLObject XMLObject )  {
-int i;
-
-  FreeMemory();
-
-  CreateCopy ( objTag ,XMLObject->objTag  );
-  CreateCopy ( objData,XMLObject->objData );
-
-  nObjects = XMLObject->nObjects;
-  nAlloc   = nObjects;
-  if (nObjects>0)  {
-    object = new PCXMLObject[nObjects];
-    for (i=0;i<nObjects;i++)
-      if (XMLObject->object[i])  {
-        object[i] = new CXMLObject();
-        object[i]->Copy ( XMLObject->object[i] );
-      } else
-        object[i] = NULL;
-  }
-
-  nAttributes = XMLObject->nAttributes;
-  nAttrAlloc  = nAttributes;
-  if (nAttributes>0)  {
-    GetVectorMemory ( attr_name ,nAttrAlloc,0 );
-    GetVectorMemory ( attr_value,nAttrAlloc,0 );
-    for (i=0;i<nAttributes;i++)  {
-      attr_name [i] = NULL;
-      attr_value[i] = NULL;
-      CreateCopy ( attr_name [i],XMLObject->attr_name [i] );
-      CreateCopy ( attr_value[i],XMLObject->attr_value[i] );
-    }
-  }
-
-}
-
-
-void  CXMLObject::write ( RCFile f )  {
-int i;
-  f.CreateWrite ( objTag       );
-  f.CreateWrite ( objData      );
-  f.WriteInt    ( &nObjects    );
-  for (i=0;i<nObjects;i++)
-    StreamWrite ( f,object[i] );
-  f.WriteInt    ( &nAttributes );
-  for (i=0;i<nAttributes;i++)  {
-    f.CreateWrite ( attr_name [i] );
-    f.CreateWrite ( attr_value[i] );
-  }
-}
-
-void  CXMLObject::read ( RCFile f )  {
-int i;
-
-  FreeMemory();
-
-  f.CreateRead ( objTag    );
-  f.CreateRead ( objData   );
-
-  f.ReadInt    ( &nObjects );
-  nAlloc = nObjects;
-  if (nObjects>0)  {
-    object = new PCXMLObject[nObjects];
-    for (i=0;i<nObjects;i++)  {
-      object[i] = NULL;
-      StreamRead ( f,object[i] );
-    }
-  }
-
-  f.ReadInt    ( &nAttributes );
-  nAttrAlloc = nAttributes;
-  if (nAttributes>0)  {
-    GetVectorMemory ( attr_name ,nAttrAlloc,0 );
-    GetVectorMemory ( attr_value,nAttrAlloc,0 );
-    for (i=0;i<nAttributes;i++)  {
-      attr_name [i] = NULL;
-      attr_value[i] = NULL;
-      f.CreateRead ( attr_name [i] );
-      f.CreateRead ( attr_value[i] );
-    }
-  }
-
-}
-
-
-MakeStreamFunctions(CXMLObject)
-
-
-
-PCXMLObject mmCIF2XML ( PCMMCIFData mmCIFData, int * rc )  {
-PCXMLObject XMLObject;
-pstr        dataName;
-int         k;
-  XMLObject = NULL;
-  if (rc) *rc = -2;
-  if (mmCIFData)  {
-    dataName = mmCIFData->GetDataName();
-    if (dataName)  {
-      if (dataName[0])
-        XMLObject = new CXMLObject ( dataName );
-    }
-    if (!XMLObject)
-      XMLObject = new CXMLObject ( pstr("no_data_name") );
-    k = XMLObject->AddMMCIFData ( mmCIFData );
-    if (rc)  *rc = k;
-  }
-  return XMLObject;
-}
-
-PCXMLObject mmCIF2XML ( cpstr XMLName, PCMMCIFFile mmCIFFile,
-                        int * rc )  {
-PCXMLObject XMLObject1,XMLObject2;
-PCMMCIFData mmCIFData;
-int         nData,i,k,rc1;
-  XMLObject1 = new CXMLObject ( XMLName );
-  if (rc) *rc = -1;
-  if (mmCIFFile)  {
-    nData = mmCIFFile->GetNofData();
-    k   = 0;
-    rc1 = 0;
-    for (i=0;(i<nData) && (rc1>=0);i++)  {
-      mmCIFData = mmCIFFile->GetCIFData ( i );
-      if (mmCIFData)  {
-        XMLObject2 = mmCIF2XML ( mmCIFData,&rc1 );
-        if (XMLObject2)  {
-          if (rc1>=0)  {
-            XMLObject1->AddObject ( XMLObject2 );
-            k += rc1;
-          } else
-            delete XMLObject2;
-        }
-      }
-    }
-    if (rc1<0)  {
-      delete XMLObject1;
-      if (rc)  *rc = -2;
-    } else if (rc)
-      *rc = k;
-  }
-  return XMLObject1;
-}
-
diff --git a/mmdb/mmdb_xml.h b/mmdb/mmdb_xml.h
deleted file mode 100755
index 944dd5d..0000000
--- a/mmdb/mmdb_xml.h
+++ /dev/null
@@ -1,148 +0,0 @@
-//  $Id: mmdb_xml.h,v 1.20 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    08.07.08   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  MMDB_XML <interface>
-//       ~~~~~~~~~
-//  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~
-//  **** Classes :  CXMLObject
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 2000-2008
-//
-//  =================================================================
-//
-
-#ifndef __MMDB_XML__
-#define __MMDB_XML__
-
-
-#ifndef __MMDB_MMCIF__
-#include "mmdb_mmcif.h"
-#endif
-
-
-
-//  ======================  CXMLObject  ==========================
-
-#define XMLR_Ok           0
-#define XMLR_NoFile       1
-#define XMLR_NoTag        2
-#define XMLR_BrokenTag    3
-#define XMLR_UnclosedTag  4
-
-DefineClass(CXMLObject);
-DefineStreamFunctions(CXMLObject);
-
-class CXMLObject : public CStream  {
-
-  public :
-
-    CXMLObject ();
-    CXMLObject ( cpstr Tag );
-    CXMLObject ( cpstr Tag, cpstr Data );
-    CXMLObject ( cpstr Tag, realtype V, int length=11 );
-    CXMLObject ( cpstr Tag, int     iV, int length=0  );
-    CXMLObject ( cpstr Tag, Boolean bV );
-    CXMLObject ( cpstr Tag, PCXMLObject XMLObject );
-    CXMLObject ( RPCStream Object );
-    ~CXMLObject();
-
-    void  SetTag       ( cpstr Tag                             );
-    void  AddAttribute ( cpstr name, cpstr         value       );
-    void  AddAttribute ( cpstr name, const int     iV          );
-    void  AddAttribute ( cpstr name, const Boolean bV          );
-    void  SetData      ( cpstr Data                            );
-    void  AddData      ( cpstr Data                            );
-    void  SetData      ( const realtype V, const int length=11 );
-    void  SetData      ( const int     iV, const int length=0  );
-    void  SetData      ( const Boolean bV                      );
-
-    int   AddMMCIFCategory ( PCMMCIFCategory mmCIFCat    );
-    int   AddMMCIFStruct   ( PCMMCIFStruct   mmCIFStruct );
-    int   AddMMCIFLoop     ( PCMMCIFLoop     mmCIFLoop   );
-    int   AddMMCIFData     ( PCMMCIFData     mmCIFData   );
-
-    pstr  GetTag  () { return objTag; }
-
-    //   Here and below the functions allow for "tag1>tag2>tag3>..."
-    // as a composite multi-level tag, e.g. the above may stand for
-    // <tag1><tag2><tag3>data</tag3></tag2></tag1>. NULL tag
-    // corresponds to "this" object.
-    //   objNo counts same-tag objects of the *highest* level used
-    // (e.g. level tag3 for composite tag  tag1>tag2>tag3 ).
-    //   GetData ( pstr& ... ) only copies a pointer to data.
-    pstr  GetData ( cpstr Tag=NULL, int objNo=1 );
-    int   GetData ( pstr   & Data, cpstr Tag=NULL, int objNo=1 );
-    int   GetData ( realtype &  V, cpstr Tag=NULL, int objNo=1 );
-    int   GetData ( int      & iV, cpstr Tag=NULL, int objNo=1 );
-    int   GetData ( Boolean  & bV, cpstr Tag=NULL, int objNo=1 );
-
-    PCXMLObject GetObject     ( cpstr Tag, int objNo=1 );
-    PCXMLObject GetFirstObject();
-    PCXMLObject GetLastObject ();
-    inline int  GetNumberOfObjects() { return nObjects; }
-    PCXMLObject GetObject     ( int objectNo );  // 0,1,...
-
-    inline PCXMLObject GetParent() { return parent; }
-
-    void  AddObject   ( PCXMLObject XMLObject , int lenInc=10 );
-    int   WriteObject ( cpstr FName, int pos=0, int ident=2   );
-    void  WriteObject ( RCFile    f, int pos=0, int ident=2   );
-    int   ReadObject  ( cpstr FName );
-    int   ReadObject  ( RCFile f, pstr S, int & pos, int slen );
-
-    virtual void Copy ( PCXMLObject XMLObject );
-
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
-
-  protected:
-    PCXMLObject  parent;
-    pstr         objTag;
-    pstr         objData;
-    int          nObjects,nAlloc;
-    PPCXMLObject object;
-    int          nAttributes,nAttrAlloc;
-    psvector     attr_name,attr_value;
-
-    void         InitXMLObject();
-    virtual void FreeMemory   ();
-
-    inline void SetParent ( PCXMLObject p ) { parent = p; }
-
-};
-
-
-extern  PCXMLObject mmCIF2XML ( PCMMCIFData mmCIFData, int * rc=NULL );
-extern  PCXMLObject mmCIF2XML ( cpstr XMLName, PCMMCIFFile mmCIFFile,
-                                                       int * rc=NULL );
-
-#endif
-
-
diff --git a/mmdb/random_n.cpp b/mmdb/random_n.cpp
deleted file mode 100755
index a32759d..0000000
--- a/mmdb/random_n.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-//  $Id: random_n.cpp,v 1.19 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    05.02.03   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  Random_N  <implementation>
-//       ~~~~~~~~~
-//  **** Classes :  CRandomNimber ( random number generator )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel'  1997-2008
-//
-//  =================================================================
-//
-
-#ifndef  __MATH_H
-#include <math.h>
-#endif
-
-#ifndef  __Random_N__
-#include "random_n.h"
-#endif
-
-
-//  ===================  CRandomNumber  ==========================
-
-CRandomNumber::CRandomNumber ( long IJ, long KL ) {
-  Init ( IJ,KL );
-}
-
-void  CRandomNumber::Init ( long IJ, long KL )  {
-long      i,j,k,l,m, ii,jj;
-realtype  s,t;
-
-  iset = 0;
-  gset = 0.0;
-
-  if ((IJ<0) || (IJ>_RN_MAX_IJ) ||
-      (KL<0) || (KL>_RN_MAX_KL))  return;
-
-  i = mod(IJ/177,177) + 2;
-  j = mod(IJ,177)     + 2;
-  k = mod(KL/169,178) + 1;
-  l = mod(KL,169);
-
-  for (ii=0;ii<97;ii++)  {
-    s = 0.0;
-    t = 0.5;
-    for (jj=1;jj<=24;jj++)  {
-      m = mod(mod(i*j,179)*k,179);
-      i = j;
-      j = k;
-      k = m;
-      l = mod(53*l+1,169);
-      if (mod(l*m,64)>=32)  s += t;
-      t *= 0.5;
-    }
-    U[ii] = s;
-  }
-
-  C  = 362436.0   / 16777216.0;
-  CD = 7654321.0  / 16777216.0;
-  CM = 16777213.0 / 16777216.0;
-
-  I97 = 96;
-  J97 = 32;
-
-}
-
-
-// uniform [0..1] random number generator
-realtype CRandomNumber::random()  {
-realtype uni;
-
-  uni = U[I97] - U[J97];
-  if (uni<0.0) uni += 1.0;
-  U[I97] = uni;
-  I97--;
-  if (I97<0) I97 = 96;
-  J97--;
-  if (J97<0) J97 = 96;
-  C -= CD;
-  if (C<0.0)  C += CM;
-  uni -= C;
-  if (uni<0.0) uni += 1.0;
-
-  return uni;
-
-}
-
-
-// uniform [-1..1] random number generator
-realtype CRandomNumber::srandom()  {
-realtype uni;
-
-  uni = U[I97] - U[J97];
-  if (uni<0.0) uni += 1.0;
-  U[I97] = uni;
-  I97--;
-  if (I97<0) I97 = 96;
-  J97--;
-  if (J97<0) J97 = 96;
-  C -= CD;
-  if (C<0.0)  C += CM;
-  uni -= C;
-  if (uni<0.0) uni += 1.0;
-
-  return 2.0*uni - 1.0;
-
-}
-
-// gaussian random numbers
-realtype CRandomNumber::gauss_rnd()  {
-realtype  v1,v2,r,fac;
-  if (iset==0)  {
-    do {
-      v1 = srandom();
-      v2 = srandom();
-      r  = v1*v1 + v2*v2;
-    } while ((r>=1.0) || (r==0.0));
-    fac  = sqrt(-2.0*log(r)/r);
-    gset = v1*fac;
-    iset = 1;
-    return v2*fac;
-  } else  {
-    iset  = 0;
-    return gset;
-  }
-}
-
-void  CRandomNumber::write ( RCFile f )  {
-int Version=1;
-  f.WriteFile ( &Version,sizeof(Version) );
-  f.WriteFile ( &I97    ,sizeof(I97)     );
-  f.WriteFile ( &J97    ,sizeof(J97)     );
-  f.WriteFile ( U       ,sizeof(U)       );
-  f.WriteFile ( &C      ,sizeof(C)       );
-  f.WriteFile ( &CD     ,sizeof(CD)      );
-  f.WriteFile ( &CM     ,sizeof(CM)      );
-  f.WriteFile ( &gset   ,sizeof(gset)    );
-  f.WriteFile ( &iset   ,sizeof(iset)    );
-}
-
-void  CRandomNumber::read ( RCFile f )  {
-int Version;
-  f.ReadFile ( &Version,sizeof(Version) );
-  f.ReadFile ( &I97    ,sizeof(I97)     );
-  f.ReadFile ( &J97    ,sizeof(J97)     );
-  f.ReadFile ( U       ,sizeof(U)       );
-  f.ReadFile ( &C      ,sizeof(C)       );
-  f.ReadFile ( &CD     ,sizeof(CD)      );
-  f.ReadFile ( &CM     ,sizeof(CM)      );
-  f.ReadFile ( &gset   ,sizeof(gset)    );
-  f.ReadFile ( &iset   ,sizeof(iset)    );
-}
-
-/*
-
-static int m1       = 259200;
-static int ia1      = 7141;
-static int ic1      = 54773;
-static realtype rm1 = 1.0/259200.0;
-
-static int m2       = 134456;
-static int ia2      = 8121;
-static int ic2      = 28411;
-static realtype rm2 = 1.0/134456.0;
-
-static int m3       = 243000;
-static int ia3      = 4561;
-static int ic3      = 51349;
-
-static int ix1 = 0;
-static int ix2 = 0;
-static int ix3 = 0;
-
-static realtype R[97];
-
-void  randomize ( int iseed )  {
-int  j;
-  RndInit = True;
-  ix1 = mod(ic1-iseed,m1);
-  ix1 = mod(ia1*ix1+ic1,m1);
-  ix2 = mod(ix1,m2);
-  ix1 = mod(ia1*ix1+ic1,m1);
-  ix3 = mod(ix1,m3);
-  for (j=0;j<97;j++)  {
-    ix1  = mod(ia1*ix1+ic1,m1);
-    ix2  = mod(ia2*ix2+ic2,m2);
-    R[j] = (ix1+ix2*rm2)*rm1;
-  }
-}
-
-realtype  rand()  {
-int      j;
-realtype rnd;
-  if (!RndInit)  randomize();
-  ix1 = mod(ia1*ix1+ic1,m1);
-  ix2 = mod(ia2*ix2+ic2,m2);
-  ix3 = mod(ia3*ix3+ic3,m3);
-  j = 1 + (97*ix3)/m3;
-  j = IMax(j,1);
-  j = IMin(j,97);
-  rnd = R[j-1];
-  R[j] = (ix1+ix2*rm2)*rm1;
-  return rnd;
-}
-*/
-
-//  ===========================================================
-
-// End of  Random_N
diff --git a/mmdb/stream_.cpp b/mmdb/stream_.cpp
deleted file mode 100755
index 7abf662..0000000
--- a/mmdb/stream_.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-//  $Id: stream_.cpp,v 1.20 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  CStream_ <interface>
-//       ~~~~~~~~~
-//  **** Classes :  CStream  ( Basic Stream Class )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 1995-2010
-//
-//  =================================================================
-//
-
-#ifndef  __Stream__
-#include "stream_.h"
-#endif
-
-//  ==========================  CStream  ===========================
-
-//     Each streamable class should be derived from CStream
-//  and have constructor CClass(PCStream & Object), which should
-//  initialize all memory of the class, and virtual functions
-//  read(..) and write(..) (see below). Constructor CClass(PCStream&)
-//  must not touch the Object variable. This constructor is used
-//  only once just before read(..) function. It is assumed that
-//  read/write functions of CClass provide storage/reading of
-//  all vital data. Function read(..) must read data in exactly
-//  the same way as function write(..) stores it.
-//     For using CClass in streams, three following functions should
-//  be supplied:
-//
-//     1.
-//     void StreamWrite ( RCFile f, RPCClass Object )  {
-//       StreamWrite ( f,(PCStream)PCClass );
-//     }
-//
-//     2.
-//     PCStream CClassInit ( RPCStream Object )  {
-//       return (PCStream)(new CClass(Object));
-//     }
-//
-//     3.
-//     void StreamRead ( RCFile f, RPCClass Object )  {
-//       StreamRead_ ( f,(PCStream)Object,CClassInit );
-//     }
-//
-//    All these functions are automatically generated by macros
-//  DefineStreamFunctions(CClass) -- in the header -- and
-//  MakeStreamFunctions(CClass) -- in the implementation body.
-//  Then CClass may be streamed in/out using functions #1 and #3.
-//    StreamRead will return NULL for Object if it was not
-//  in the stream. If Object existed before StreamRead(..) but
-//  was not found in the stream, it will be disposed.
-
-void StreamRead_ ( RCFile f, RPCStream Object,
-                   InitStreamObject Init )  {
-int i;
-  f.ReadInt ( &i );
-  if (i)  {
-    if (!Object)
-      Object = Init(Object); //Object = new CStream ( Object );
-    Object->read ( f );
-  } else  {
-    if (Object)  delete Object;
-    Object = NULL;
-  }
-}
-
-void StreamWrite_ ( RCFile f, RPCStream Object )  {
-int i;
-  if (Object)  {
-    i = 1;
-    f.WriteInt ( &i );
-    Object->write ( f );
-  } else  {
-    i = 0;
-    f.WriteInt ( &i );
-  }
-}
-
-MakeStreamFunctions(CStream)
diff --git a/mmdb/stream_.h b/mmdb/stream_.h
deleted file mode 100755
index 9e788d7..0000000
--- a/mmdb/stream_.h
+++ /dev/null
@@ -1,192 +0,0 @@
-//  $Id: stream_.h,v 1.20 2012/01/26 17:52:21 ekr Exp $
-//  =================================================================
-//
-//   CCP4 Coordinate Library: support of coordinate-related
-//   functionality in protein crystallography applications.
-//
-//   Copyright (C) Eugene Krissinel 2000-2008.
-//
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
-//    of the license to address the requirements of UK law.
-//
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
-//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU Lesser General Public License for more details.
-//
-//  =================================================================
-//
-//    29.01.10   <--  Date of Last Modification.
-//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//  -----------------------------------------------------------------
-//
-//  **** Module  :  CStream_ <interface>
-//       ~~~~~~~~~
-//  **** Classes :  CStream ( Basic Stream Class )
-//       ~~~~~~~~~
-//
-//   (C) E. Krissinel 1995-2010
-//
-//  =================================================================
-//
-
-#ifndef __Stream__
-#define __Stream__
-
-#ifndef  __File__
-#include "file_.h"
-#endif
-
-//  *******************************************************************
-
-#ifndef __ClassMacros
-
-# define __ClassMacros
-
- //  A Class definition macros
-# define DefineClass(ClassName)             \
-   class ClassName;                         \
-   typedef ClassName    * P##ClassName;     \
-   typedef ClassName    & R##ClassName;     \
-   typedef P##ClassName * PP##ClassName;    \
-   typedef P##ClassName & RP##ClassName;
-
- //  A Structure definition macros
-# define DefineStructure(StructureName)             \
-   struct StructureName;                            \
-   typedef StructureName    * P##StructureName;     \
-   typedef StructureName    & R##StructureName;     \
-   typedef P##StructureName * PP##StructureName;    \
-   typedef P##StructureName & RP##StructureName;
-
-#endif
-
-
-#define  DefineStreamFunctions(ClassName)                      \
-  extern void StreamWrite ( RCFile f, RP##ClassName Object );  \
-  extern void StreamRead  ( RCFile f, RP##ClassName Object );
-
-
-#define  MakeStreamFunctions(ClassName)                        \
-  void StreamWrite ( RCFile f, RP##ClassName Object )  {       \
-    StreamWrite_ ( f,(RPCStream)Object );                      \
-  }                                                            \
-  PCStream StreamInit##ClassName ( RPCStream Object )  {       \
-    return (PCStream)(new ClassName(Object));                  \
-  }                                                            \
-  void StreamRead ( RCFile f, RP##ClassName Object )  {        \
-    StreamRead_ ( f,(RPCStream)Object,StreamInit##ClassName ); \
-  }
-
-
-
-#define  DefineFactoryFunctions(ClassName)                              \
-  typedef P##ClassName      Make##ClassName();                          \
-  typedef Make##ClassName * PMake##ClassName;                           \
-  typedef P##ClassName      StreamMake##ClassName ( RPCStream Object ); \
-  P##ClassName  new##ClassName ();                                      \
-  P##ClassName  streamNew##ClassName ( RPCStream Object );              \
-  typedef StreamMake##ClassName * PStreamMake##ClassName;               \
-  extern void SetMakers##ClassName ( void * defMk, void * streamMk );   \
-  extern void StreamWrite ( RCFile f, RP##ClassName Object );           \
-  extern void StreamRead  ( RCFile f, RP##ClassName Object );
-
-
-#define  MakeFactoryFunctions(ClassName)                         \
-  static PMake##ClassName       make##ClassName       = NULL;    \
-  static PStreamMake##ClassName streamMake##ClassName = NULL;    \
-  P##ClassName new##ClassName()  {                               \
-    if (make##ClassName)  return (*make##ClassName)();           \
-                    else  return new ClassName();                \
-  }                                                              \
-  P##ClassName streamNew##ClassName ( RPCStream Object )  {      \
-    if (streamMake##ClassName)                                   \
-          return (*streamMake##ClassName)(Object);               \
-    else  return new ClassName(Object);                          \
-  }                                                              \
-  void SetMakers##ClassName ( void * defMk, void * streamMk ) {  \
-    make##ClassName       = PMake##ClassName(defMk);             \
-    streamMake##ClassName = PStreamMake##ClassName(streamMk);    \
-  }                                                              \
-  void StreamWrite ( RCFile f, RP##ClassName Object )  {         \
-    StreamWrite_ ( f,(RPCStream)Object );                        \
-  }                                                              \
-  PCStream StreamInit##ClassName ( RPCStream Object )  {         \
-    return (PCStream)(streamNew##ClassName(Object));             \
-  }                                                              \
-  void StreamRead ( RCFile f, RP##ClassName Object )  {          \
-    StreamRead_ ( f,(RPCStream)Object,StreamInit##ClassName );   \
-  }
-
-
-
-
-//  ==========================  CStream  ===========================
-
-//     Each streamable class should be derived from CStream
-//  and have constructor CClass(PCStream & Object), which should
-//  initialize all memory of the class, and virtual functions
-//  read(..) and write(..) (see below). Constructor CClass(PCStream&)
-//  must not touch the Object variable. This constructor is used
-//  only once just before the read(..) function. It is assumed that
-//  read(..)/write(..) functions of the CClass provide storage/reading
-//  of  all vital data. Function read(..) must read data in exactly
-//  the same way as function write(..) stores it.
-//     For using CClass in streams, three following functions should
-//  be supplied:
-//
-//     1.
-//     void StreamWrite ( CFile & f, PCClass & Object )  {
-//       StreamWrite ( f,(PCStream)Object );
-//     }
-//
-//     2.
-//     PCStream CClassInit ( PCStream & Object )  {
-//       return (PCStream)(new CClass(Object));
-//     }
-//
-//     3.
-//     void StreamRead ( CFile & f, PCClass & Object )  {
-//       StreamRead_ ( f,(PCStream)Object,CClassInit );
-//     }
-//
-//    All these functions are automatically generated by macros
-//  DefineStreamFunctions(CClass) -- in the header -- and
-//  MakeStreamFunctions(CClass) -- in the implementation body. Note
-//  that macro DefineClass(CClass) should always be issued for
-//  streamable classes prior to the stream-making macros. Then
-//  CClass may be streamed using functions #1 and #3.
-//    StreamRead will return NULL for Object if it was not in
-//  the stream. If Object existed before calling StreamRead(..)
-//  but was not found in the stream, it will be disposed (NULL
-//  assigned).
-
-
-DefineClass(CStream);
-DefineStreamFunctions(CStream);
-
-class CStream  {
-  public :
-    CStream            ()            {}
-    CStream            ( RPCStream ) {}
-    virtual ~CStream   ()            {}
-    virtual void read  ( RCFile )    {}
-    virtual void write ( RCFile )    {}
-};
-
-
-typedef PCStream InitStreamObject(RPCStream Object);
-
-extern  void StreamRead_  ( RCFile f, RPCStream Object,
-                                      InitStreamObject Init );
-
-extern  void StreamWrite_ ( RCFile f, RPCStream Object );
-
-
-#endif
diff --git a/mmdb.pc.in b/mmdb2.pc.in
similarity index 81%
rename from mmdb.pc.in
rename to mmdb2.pc.in
index dd654a4..567b1dd 100644
--- a/mmdb.pc.in
+++ b/mmdb2.pc.in
@@ -3,8 +3,9 @@ exec_prefix=@exec_prefix@
 libdir=@libdir@
 includedir=@includedir@
 
-Name: mmdb
+Name: mmdb2
 Description: Macromolecular coordinate library
 Version: @VERSION@
-Libs: -L${libdir} -lmmdb
+Libs: -L${libdir} -lmmdb2
 Cflags: -I${includedir}
+
diff --git a/mmdb/hybrid_36.cpp b/mmdb2/hybrid_36.cpp
old mode 100755
new mode 100644
similarity index 100%
rename from mmdb/hybrid_36.cpp
rename to mmdb2/hybrid_36.cpp
diff --git a/mmdb/hybrid_36.h b/mmdb2/hybrid_36.h
old mode 100755
new mode 100644
similarity index 100%
rename from mmdb/hybrid_36.h
rename to mmdb2/hybrid_36.h
diff --git a/mmdb2/mmdb_atom.cpp b/mmdb2/mmdb_atom.cpp
new file mode 100644
index 0000000..0dcc986
--- /dev/null
+++ b/mmdb2/mmdb_atom.cpp
@@ -0,0 +1,3486 @@
+//  $Id: mmdb_atom.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    18.10.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Atom <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Atom     ( atom class    )
+//       ~~~~~~~~~  mmdb::Residue  ( residue class )
+//  **** Functions: mmdb::BondAngle
+//       ~~~~~~~~~~
+//
+//  Copyright (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_chain.h"
+#include "mmdb_model.h"
+#include "mmdb_root.h"
+#include "mmdb_tables.h"
+#include "mmdb_cifdefs.h"
+#include "hybrid_36.h"
+
+
+namespace mmdb  {
+
+  //  ================================================================
+
+  #define  ASET_ShortBinary   0x10000000
+  #define  ASET_ShortTer      0x20000000
+  #define  ASET_ShortHet      0x40000000
+
+  bool  ignoreSegID            = false;
+  bool  ignoreElement          = false;
+  bool  ignoreCharge           = false;
+  bool  ignoreNonCoorPDBErrors = false;
+  bool  ignoreUnmatch          = false;
+
+
+  //  ==========================  Atom  =============================
+
+  Atom::Atom() : UDData()  {
+    InitAtom();
+  }
+
+  Atom::Atom ( PResidue res ) : UDData()  {
+    InitAtom();
+    if (res)
+      res->AddAtom ( this );
+  }
+
+  Atom::Atom ( io::RPStream Object ) : UDData(Object)  {
+    InitAtom();
+  }
+
+  Atom::~Atom()  {
+  PPAtom A;
+  int    nA;
+    FreeMemory();
+    if (residue)  {
+      A  = NULL;
+      nA = 0;
+      if (residue->chain)  {
+        if (residue->chain->model)  {
+          A  = residue->chain->model->GetAllAtoms();
+          nA = residue->chain->model->GetNumberOfAllAtoms();
+        }
+      }
+      residue->_ExcludeAtom ( index );
+      if ((0<index) && (index<=nA))  A[index-1] = NULL;
+    }
+  }
+
+  void  Atom::InitAtom()  {
+    serNum     = -1;         // serial number
+    index      = -1;         // index in the file
+    name[0]    = char(0);    // atom name
+    label_atom_id[0] = char(0); // assigned atom name (not aligned)
+    altLoc[0]  = char(0);    // alternate location indicator
+    residue    = NULL;       // reference to residue
+    x          = 0.0;        // orthogonal x-coordinate in angstroms
+    y          = 0.0;        // orthogonal y-coordinate in angstroms
+    z          = 0.0;        // orthogonal z-coordinate in angstroms
+    occupancy  = 0.0;        // occupancy
+    tempFactor = 0.0;        // temperature factor
+    segID[0]   = char(0);    // segment identifier
+    strcpy ( element,"  " ); // chemical element symbol - RIGHT JUSTIFIED
+    energyType[0] = char(0); // chemical element symbol - RIGHT JUSTIFIED
+    charge     = 0.0;        // charge on the atom
+    sigX       = 0.0;        // standard deviation of the stored x-coord
+    sigY       = 0.0;        // standard deviation of the stored y-coord
+    sigZ       = 0.0;        // standard deviation of the stored z-coord
+    sigOcc     = 0.0;        // standard deviation of occupancy
+    sigTemp    = 0.0;        // standard deviation of temperature factor
+    u11        = 0.0;        //
+    u22        = 0.0;        // anisotropic
+    u33        = 0.0;        //
+    u12        = 0.0;        //    temperature
+    u13        = 0.0;        //
+    u23        = 0.0;        //        factors
+    su11       = 0.0;        //
+    su22       = 0.0;        // standard
+    su33       = 0.0;        //    deviations of
+    su12       = 0.0;        //       anisotropic
+    su13       = 0.0;        //          temperature
+    su23       = 0.0;        //             factors
+    Het        = false;      // indicator of atom in non-standard groups
+    Ter        = false;      // chain terminator
+    WhatIsSet  = 0x00000000; // nothing is set
+    nBonds     = 0;          // no bonds
+    Bond       = NULL;       // empty array of bonds
+  }
+
+  void  Atom::FreeMemory()  {
+    FreeBonds();
+  }
+
+  void  Atom::FreeBonds()  {
+    if (Bond)  delete[] Bond;
+    Bond   = NULL;
+    nBonds = 0;
+  }
+
+  int Atom::GetNBonds()  {
+    return nBonds & 0x000000FF;
+  }
+
+  void Atom::GetBonds ( RPAtomBond atomBond, int & nAtomBonds )  {
+  //    This GetBonds(..) returns pointer to the Atom's
+  //  internal Bond structure, IT MUST NOT BE DISPOSED.
+    nAtomBonds = nBonds & 0x000000FF;
+    atomBond   = Bond;
+  }
+
+  void Atom::GetBonds ( RPAtomBondI atomBondI, int & nAtomBonds )  {
+  //    This GetBonds(..) disposes AtomBondI, if it was not set
+  //  to NULL, allocates AtomBondI[nAtomBonds] and returns its
+  //  pointer. AtomBondI MUST BE DISPOSED BY APPLICATION.
+  int i;
+
+    if (atomBondI)  delete[] atomBondI;
+
+    nAtomBonds = nBonds & 0x000000FF;
+
+    if (nAtomBonds<=0)
+      atomBondI = NULL;
+    else  {
+      atomBondI = new AtomBondI[nAtomBonds];
+      for (i=0;i<nAtomBonds;i++) {
+        if (Bond[i].atom)
+              atomBondI[i].index = Bond[i].atom->index;
+        else  atomBondI[i].index = -1;
+        atomBondI[i].order = Bond[i].order;
+      }
+
+    }
+
+  }
+
+  void Atom::GetBonds ( PAtomBondI AtomBondI, int & nAtomBonds,
+                         int maxlength )  {
+  //    This GetBonds(..) does not dispose or allocate AtomBond.
+  //  It is assumed that length of AtomBond is sufficient to
+  //  accomodate all bonded atoms.
+  int  i;
+
+    nAtomBonds = IMin(maxlength,nBonds & 0x000000FF);
+
+    for (i=0;i<nAtomBonds;i++)  {
+      if (Bond[i].atom)
+            AtomBondI[i].index = Bond[i].atom->index;
+      else  AtomBondI[i].index = -1;
+      AtomBondI[i].order = Bond[i].order;
+    }
+
+  }
+
+
+  int  Atom::AddBond ( PAtom bond_atom, int bond_order,
+                        int nAdd_bonds )  {
+  PAtomBond B1;
+  int        i,k,nb,nballoc;
+
+    nb = nBonds & 0x000000FF;
+    k  = -1;
+    for (i=0;(i<nb) && (k<0);i++)
+      if (Bond[i].atom==bond_atom)  k = i;
+    if (k>=0)  return -k;
+
+    nballoc = (nBonds >> 8) & 0x000000FF;
+    if (nBonds>=nballoc)  {
+      nballoc += nAdd_bonds;
+      B1 = new AtomBond[nballoc];
+      for (i=0;i<nb;i++)  {
+        B1[i].atom  = Bond[i].atom;
+        B1[i].order = Bond[i].order;
+      }
+      if (Bond)  delete[] Bond;
+      Bond = B1;
+    }
+    Bond[nb].atom  = bond_atom;
+    Bond[nb].order = bond_order;
+    nb++;
+
+    nBonds = nb | (nballoc << 8);
+
+    return nb;
+
+  }
+
+  void  Atom::SetResidue ( PResidue res )  {
+    residue = res;
+  }
+
+  void  Atom::StandardPDBOut ( cpstr Record, pstr S )  {
+  char N[10];
+    strcpy    ( S,Record );
+    PadSpaces ( S,80     );
+    if (serNum>99999)  {
+      hy36encode ( 5,serNum,N );
+      strcpy_n   ( &(S[6]),N,5 );
+    } else if (serNum>0)
+      PutInteger ( &(S[6]),serNum,5 );
+    else if (index<=99999)
+      PutInteger ( &(S[6]),index,5 );
+    else {
+      hy36encode ( 5,index,N );
+      strcpy_n   ( &(S[6]),N,5 );
+    }
+    if (!Ter)  {
+      if (altLoc[0])  S[16] = altLoc[0];
+      strcpy_n  ( &(S[12]),name   ,4 );
+      strcpy_n  ( &(S[72]),segID  ,4 );
+      strcpy_nr ( &(S[76]),element,2 );
+      if (WhatIsSet & ASET_Charge)  {
+        if (charge>0)       sprintf ( N,"%1i+",mround(charge)  );
+        else if (charge<0)  sprintf ( N,"%1i-",mround(-charge) );
+                      else  strcpy  ( N,"  " );
+        strcpy_n ( &(S[78]),N,2 );
+      } else
+        strcpy_n ( &(S[78]),"  ",2 );
+    }
+    strcpy_nr ( &(S[17]),residue->name,3 );
+    strcpy_nr ( &(S[20]),residue->chain->chainID,2 );
+    if (residue->seqNum>MinInt4)  {
+      if ((-999<=residue->seqNum) && (residue->seqNum<=9999))
+        PutIntIns  ( &(S[22]),residue->seqNum,4,residue->insCode );
+      else  {
+        hy36encode ( 4,residue->seqNum,N );
+        strcpy_n   ( &(S[22]),N,4 );
+      }
+    }
+  }
+
+  void  Atom::PDBASCIIDump ( io::RFile f )  {
+  // makes the ASCII PDB  ATOM, HETATM, SIGATOM, ANISOU
+  // SIGUIJ and TER lines from the class' data
+  char S[100];
+    if (Ter)  {
+      if (WhatIsSet & ASET_Coordinates)  {
+        StandardPDBOut ( pstr("TER"),S );
+        f.WriteLine ( S );
+      }
+    } else  {
+      if (WhatIsSet & ASET_Coordinates)  {
+        if (Het)  StandardPDBOut ( pstr("HETATM"),S );
+            else  StandardPDBOut ( pstr("ATOM")  ,S );
+        PutRealF ( &(S[30]),x,8,3 );
+        PutRealF ( &(S[38]),y,8,3 );
+        PutRealF ( &(S[46]),z,8,3 );
+        if (WhatIsSet & ASET_Occupancy)
+          PutRealF ( &(S[54]),occupancy ,6,2 );
+        if (WhatIsSet & ASET_tempFactor)
+          PutRealF ( &(S[60]),tempFactor,6,2 );
+        f.WriteLine ( S );
+      }
+      if (WhatIsSet & ASET_CoordSigma)  {
+        StandardPDBOut ( pstr("SIGATM"),S );
+        PutRealF ( &(S[30]),sigX,8,3 );
+        PutRealF ( &(S[38]),sigY,8,3 );
+        PutRealF ( &(S[46]),sigZ,8,3 );
+        if ((WhatIsSet & ASET_OccSigma) &&
+            (WhatIsSet & ASET_Occupancy))
+          PutRealF ( &(S[54]),sigOcc,6,2 );
+        if ((WhatIsSet & ASET_tFacSigma) &&
+            (WhatIsSet & ASET_tempFactor))
+          PutRealF ( &(S[60]),sigTemp,6,2 );
+        f.WriteLine ( S );
+      }
+      if (WhatIsSet & ASET_Anis_tFac)  {
+        StandardPDBOut ( pstr("ANISOU"),S );
+        PutInteger  ( &(S[28]),mround(u11*1.0e4),7 );
+        PutInteger  ( &(S[35]),mround(u22*1.0e4),7 );
+        PutInteger  ( &(S[42]),mround(u33*1.0e4),7 );
+        PutInteger  ( &(S[49]),mround(u12*1.0e4),7 );
+        PutInteger  ( &(S[56]),mround(u13*1.0e4),7 );
+        PutInteger  ( &(S[63]),mround(u23*1.0e4),7 );
+        f.WriteLine ( S );
+        if (WhatIsSet & ASET_Anis_tFSigma)  {
+          StandardPDBOut ( pstr("SIGUIJ"),S );
+          PutInteger  ( &(S[28]),mround(su11*1.0e4),7 );
+          PutInteger  ( &(S[35]),mround(su22*1.0e4),7 );
+          PutInteger  ( &(S[42]),mround(su33*1.0e4),7 );
+          PutInteger  ( &(S[49]),mround(su12*1.0e4),7 );
+          PutInteger  ( &(S[56]),mround(su13*1.0e4),7 );
+          PutInteger  ( &(S[63]),mround(su23*1.0e4),7 );
+          f.WriteLine ( S );
+        }
+      }
+    }
+  }
+
+  void  Atom::MakeCIF ( mmcif::PData CIF )  {
+  mmcif::PLoop Loop;
+  AtomName     AtName;
+  Element      el;
+  char         N[10];
+  int          i,j,RC;
+  PChain       chain       = NULL;
+  PModel       model       = NULL;
+  //bool      singleModel = true;
+
+    if (residue)  chain = residue->chain;
+    if (chain)    model = PModel(chain->model);
+  //  if (model)  {
+  //    if (model->manager)
+  //      singleModel = PRoot(model->manager)->nModels<=1;
+  //  }
+
+  /*
+
+  loop_
+  *0  _atom_site.group_PDB
+  *1  _atom_site.id
+  *2  _atom_site.type_symbol         <- chem elem
+  -3  _atom_site.label_atom_id       <- atom name
+  *4  _atom_site.label_alt_id        <- alt code
+  =5  _atom_site.label_comp_id       <- res name ???
+  =6  _atom_site.label_asym_id       <- chain id ???
+  =7  _atom_site.label_entity_id     < ???
+  =8  _atom_site.label_seq_id        <- poly seq id
+  +9  _atom_site.pdbx_PDB_ins_code   <- ins code
+  -10 _atom_site.segment_id          <- segment id
+  *11 _atom_site.Cartn_x
+  *12 _atom_site.Cartn_y
+  *13 _atom_site.Cartn_z
+  *14 _atom_site.occupancy
+  *15 _atom_site.B_iso_or_equiv
+  *16 _atom_site.Cartn_x_esd
+  *17 _atom_site.Cartn_y_esd
+  *18 _atom_site.Cartn_z_esd
+  *19 _atom_site.occupancy_esd
+  *20 _atom_site.B_iso_or_equiv_esd
+  *21 _atom_site.pdbx_formal_charge
+  +22 _atom_site.auth_seq_id          <- seq id we want
+  +23 _atom_site.auth_comp_id         <- res name we want
+  +24 _atom_site.auth_asym_id         <- ch id we want ?
+  *25 _atom_site.auth_atom_id         <- atom name we want ?
+  +26 _atom_site.pdbx_PDB_model_num   <- model no
+
+  '+' is read in Root::CheckAtomPlace()
+  '=' new in residue
+  '-' new in atom
+
+
+  */
+
+    RC = CIF->AddLoop ( CIFCAT_ATOM_SITE,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+
+      Loop->AddLoopTag ( CIFTAG_GROUP_PDB          ); // ATOM, TER etc.
+      Loop->AddLoopTag ( CIFTAG_ID                 ); // serial number
+
+      Loop->AddLoopTag ( CIFTAG_TYPE_SYMBOL        ); // element symbol
+      Loop->AddLoopTag ( CIFTAG_LABEL_ATOM_ID      ); // atom name
+      Loop->AddLoopTag ( CIFTAG_LABEL_ALT_ID       ); // alt location
+      Loop->AddLoopTag ( CIFTAG_LABEL_COMP_ID      ); // residue name
+      Loop->AddLoopTag ( CIFTAG_LABEL_ASYM_ID      ); // chain ID
+      Loop->AddLoopTag ( CIFTAG_LABEL_ENTITY_ID    ); // entity ID
+      Loop->AddLoopTag ( CIFTAG_LABEL_SEQ_ID       ); // res seq number
+      Loop->AddLoopTag ( CIFTAG_PDBX_PDB_INS_CODE  ); // insertion code
+      Loop->AddLoopTag ( CIFTAG_SEGMENT_ID         ); // segment ID
+
+      Loop->AddLoopTag ( CIFTAG_CARTN_X            ); // x-coordinate
+      Loop->AddLoopTag ( CIFTAG_CARTN_Y            ); // y-coordinate
+      Loop->AddLoopTag ( CIFTAG_CARTN_Z            ); // z-coordinate
+      Loop->AddLoopTag ( CIFTAG_OCCUPANCY          ); // occupancy
+      Loop->AddLoopTag ( CIFTAG_B_ISO_OR_EQUIV     ); // temp factor
+
+      Loop->AddLoopTag ( CIFTAG_CARTN_X_ESD        ); // x-sigma
+      Loop->AddLoopTag ( CIFTAG_CARTN_Y_ESD        ); // y-sigma
+      Loop->AddLoopTag ( CIFTAG_CARTN_Z_ESD        ); // z-sigma
+      Loop->AddLoopTag ( CIFTAG_OCCUPANCY_ESD      ); // occupancy-sigma
+      Loop->AddLoopTag ( CIFTAG_B_ISO_OR_EQUIV_ESD ); // t-factor-sigma
+
+      Loop->AddLoopTag ( CIFTAG_PDBX_FORMAL_CHARGE ); // charge on atom
+
+      Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID        ); // res seq number
+      Loop->AddLoopTag ( CIFTAG_AUTH_COMP_ID       ); // residue name
+      Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID       ); // chain id
+      Loop->AddLoopTag ( CIFTAG_AUTH_ATOM_ID       ); // atom name
+
+      Loop->AddLoopTag ( CIFTAG_PDBX_PDB_MODEL_NUM ); // model number
+
+    }
+
+    if (Ter)  {   // ter record
+
+      if (!(WhatIsSet & ASET_Coordinates))
+        return;
+
+      // (0)
+      Loop->AddString  ( pstr("TER") );
+      // (1)
+      if (serNum>0)  Loop->AddInteger ( serNum );
+               else  Loop->AddInteger ( index  );
+      // (2,3,4)
+      Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );  // no element symbol
+      Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );  // no atom name
+      Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );  // no alt code
+      if (residue)  {
+        // (5)
+        Loop->AddString ( residue->label_comp_id );
+        // (6)
+        Loop->AddString ( residue->label_asym_id );
+        // (7)
+        if (residue->label_entity_id>0)
+             Loop->AddInteger ( residue->label_entity_id );
+        else Loop->AddNoData  ( mmcif::CIF_NODATA_DOT           );
+        // (8)
+        if (residue->label_seq_id>MinInt4)
+             Loop->AddInteger ( residue->label_seq_id );
+        else Loop->AddNoData  ( mmcif::CIF_NODATA_DOT        );
+        // (9)
+        Loop->AddString ( residue->insCode,true );
+      } else  {
+        // (5,6,7,8,9)
+        Loop->AddString ( NULL );
+        Loop->AddString ( NULL );
+        Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+        Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+        Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+      }
+
+      // (10-21)
+      for (i=10;i<=21;i++)
+        Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+      // (22,23)
+      if (residue)  {
+        if (residue->seqNum>MinInt4)
+             Loop->AddInteger ( residue->seqNum  );
+        else Loop->AddNoData  ( mmcif::CIF_NODATA_DOT   );
+        Loop->AddString ( residue->name );
+      } else  {
+        Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+        Loop->AddString ( NULL           );
+      }
+
+      // (24)
+      if (chain)  Loop->AddString ( chain->chainID,true );
+            else  Loop->AddString ( NULL                );
+
+      // (25)
+      Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );  // no atom name
+
+    } else if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma))  {
+      // normal atom record
+
+      if (!WhatIsSet)  return;
+
+      // (0)
+      if (Het)  Loop->AddString ( pstr("HETATM") );
+          else  Loop->AddString ( pstr("ATOM")   );
+      // (1)
+      if (serNum>0)  Loop->AddInteger ( serNum );
+               else  Loop->AddInteger ( index  );
+
+
+      if (WhatIsSet & ASET_Coordinates)  {
+
+        // (2)
+        strcpy_css ( el,element );
+        Loop->AddString ( el,true );
+        // (3)
+        Loop->AddString ( label_atom_id  );  // assigned atom name
+        // (4)
+        Loop->AddString  ( altLoc,true );  // alt code
+
+        if (residue)  {
+          // (5)
+          Loop->AddString ( residue->label_comp_id );
+          // (6)
+          Loop->AddString ( residue->label_asym_id );
+          // (7)
+          if (residue->label_entity_id>0)
+               Loop->AddInteger ( residue->label_entity_id );
+          else Loop->AddNoData  ( mmcif::CIF_NODATA_DOT           );
+          // (8)
+          if (residue->label_seq_id>MinInt4)
+               Loop->AddInteger ( residue->label_seq_id );
+          else Loop->AddNoData  ( mmcif::CIF_NODATA_DOT        );
+          // (9)
+          Loop->AddString ( residue->insCode,true );
+        } else  {
+          // (5,6,7,8,9)
+          Loop->AddString ( NULL );
+          Loop->AddString ( NULL );
+          Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+          Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+          Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+        }
+
+        // (10)
+        Loop->AddString ( segID ,true );
+        // (11,12,13)
+        Loop->AddReal ( x );
+        Loop->AddReal ( y );
+        Loop->AddReal ( z );
+        // (14)
+        if (WhatIsSet & ASET_Occupancy)
+              Loop->AddReal   ( occupancy );
+        else  Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+        // (15)
+        if (WhatIsSet & ASET_tempFactor)
+              Loop->AddReal   ( tempFactor );
+        else  Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+        // (16,17,18)
+        if (WhatIsSet & ASET_CoordSigma)  {
+          Loop->AddReal ( sigX );
+          Loop->AddReal ( sigY );
+          Loop->AddReal ( sigZ );
+        } else  {
+          Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+          Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+          Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+        }
+        // (19)
+        if ((WhatIsSet & ASET_OccSigma) && (WhatIsSet & ASET_Occupancy))
+              Loop->AddReal   ( sigOcc  );
+        else  Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+        // (20)
+        if ((WhatIsSet & ASET_tFacSigma) && (WhatIsSet & ASET_tempFactor))
+              Loop->AddReal   ( sigTemp );
+        else  Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+      } else
+        for (i=0;i<18;i++)
+          Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+      // (21)
+      if (WhatIsSet & ASET_Charge)  {
+        sprintf ( N,"%+2i",mround(charge) );
+        Loop->AddString ( N,true );
+      } else
+        Loop->AddNoData ( mmcif::CIF_NODATA_QUESTION );
+
+      if (residue)  {
+        // (22)
+        if (residue->seqNum>MinInt4)
+             Loop->AddInteger ( residue->seqNum  );
+        else Loop->AddNoData  ( mmcif::CIF_NODATA_DOT   );
+        // (23)
+        Loop->AddString ( residue->name );
+      } else  {
+        Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+        Loop->AddNoData ( mmcif::CIF_NODATA_DOT );
+      }
+
+      // (24)
+      if (chain)  Loop->AddString ( chain->chainID,true );
+            else  Loop->AddNoData ( mmcif::CIF_NODATA_DOT      );
+      // (25)
+      strcpy_css      ( AtName,name );
+      Loop->AddString ( AtName      );  // atom name
+
+    }
+
+    // (26)
+    if (!model)                Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
+    else if (model->serNum>0)  Loop->AddInteger ( model->serNum       );
+                         else  Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
+
+
+    if (WhatIsSet & ASET_Anis_tFac)  {
+
+      RC = CIF->AddLoop ( CIFCAT_ATOM_SITE_ANISOTROP,Loop );
+      if (RC!=mmcif::CIFRC_Ok)  {
+        // the category was (re)created, provide tags
+        Loop->AddLoopTag ( CIFTAG_ID      ); // serial number
+        Loop->AddLoopTag ( CIFTAG_U11     ); // component u11
+        Loop->AddLoopTag ( CIFTAG_U22     ); // component u22
+        Loop->AddLoopTag ( CIFTAG_U33     ); // component u33
+        Loop->AddLoopTag ( CIFTAG_U12     ); // component u12
+        Loop->AddLoopTag ( CIFTAG_U13     ); // component u13
+        Loop->AddLoopTag ( CIFTAG_U23     ); // component u23
+        Loop->AddLoopTag ( CIFTAG_U11_ESD ); // component u11 sigma
+        Loop->AddLoopTag ( CIFTAG_U22_ESD ); // component u22 sigma
+        Loop->AddLoopTag ( CIFTAG_U33_ESD ); // component u33 sigma
+        Loop->AddLoopTag ( CIFTAG_U12_ESD ); // component u12 sigma
+        Loop->AddLoopTag ( CIFTAG_U13_ESD ); // component u13 sigma
+        Loop->AddLoopTag ( CIFTAG_U23_ESD ); // component u23 sigma
+        for (i=1;i<index;i++)  {
+          Loop->AddInteger ( i );
+          for (j=0;j<12;j++)
+            Loop->AddString ( NULL );
+        }
+      }
+
+      if (serNum>0)  Loop->AddInteger ( serNum );
+               else  Loop->AddInteger ( index  );
+
+      Loop->AddReal ( u11 );
+      Loop->AddReal ( u22 );
+      Loop->AddReal ( u33 );
+      Loop->AddReal ( u12 );
+      Loop->AddReal ( u13 );
+      Loop->AddReal ( u23 );
+      if (WhatIsSet & ASET_Anis_tFSigma)  {
+        Loop->AddReal ( su11 );
+        Loop->AddReal ( su22 );
+        Loop->AddReal ( su33 );
+        Loop->AddReal ( su12 );
+        Loop->AddReal ( su13 );
+        Loop->AddReal ( su23 );
+      }
+
+    }
+
+  }
+
+  ERROR_CODE Atom::ConvertPDBATOM ( int ix, cpstr S )  {
+  //   Gets data from the PDB ASCII ATOM record.
+  //   This function DOES NOT check the "ATOM" keyword and
+  // does not decode the chain and residue parameters! These
+  // must be treated by calling process, see
+  // Chain::ConvertPDBASCII().
+
+    index = ix;
+
+    if (WhatIsSet & ASET_Coordinates)
+      return Error_ATOM_AlreadySet;
+
+    if (!(GetReal(x,&(S[30]),8) &&
+          GetReal(y,&(S[38]),8) &&
+          GetReal(z,&(S[46]),8)))
+      return Error_ATOM_Unrecognized;
+
+    WhatIsSet |= ASET_Coordinates;
+    Het = false;
+    Ter = false;
+
+    if (GetReal(occupancy ,&(S[54]),6))  WhatIsSet |= ASET_Occupancy;
+    if (GetReal(tempFactor,&(S[60]),6))  WhatIsSet |= ASET_tempFactor;
+
+    if (WhatIsSet & (ASET_CoordSigma | ASET_Anis_tFac |
+                     ASET_Anis_tFSigma))
+      // something was already submitted. check complience
+      return CheckData ( S );
+    else
+      // first data submission. just take the data
+      GetData ( S );
+
+    return Error_NoError;
+
+  }
+
+  void  Atom::SetAtomName ( int            ix,
+                             int            sN,
+                             const AtomName aName,
+                             const AltLoc   aLoc,
+                             const SegID    sID,
+                             const Element  eName )  {
+    index   = ix;
+    serNum  = sN;
+    strcpy     ( name         ,aName      );
+    strcpy     ( label_atom_id,aName      );
+    strcpy_css ( altLoc       ,pstr(aLoc) );
+    strcpy_css ( segID        ,pstr(sID)  );
+    if (!eName[0])  element[0] = char(0);
+    else if (!eName[1])  {
+      element[0] = ' ';
+      strcpy ( &(element[1]),eName );
+    } else
+      strcpy   ( element,eName );
+    WhatIsSet = 0;
+  }
+
+  ERROR_CODE Atom::ConvertPDBSIGATM ( int ix, cpstr S )  {
+  //   Gets data from the PDB ASCII SIGATM record.
+  //   This function DOES NOT check the "SIGATM" keyword and
+  // does not decode the chain and residue parameters! These
+  // must be treated by the calling process, see
+  // Chain::ConvertPDBASCII().
+
+    index = ix;
+
+    if (WhatIsSet & ASET_CoordSigma)
+      return Error_ATOM_AlreadySet;
+
+    if (!(GetReal(sigX,&(S[30]),8) &&
+          GetReal(sigY,&(S[38]),8) &&
+          GetReal(sigZ,&(S[46]),8)))
+      return Error_ATOM_Unrecognized;
+
+    WhatIsSet |= ASET_CoordSigma;
+
+    if (GetReal(sigOcc ,&(S[54]),6))  WhatIsSet |= ASET_OccSigma;
+    if (GetReal(sigTemp,&(S[60]),6))  WhatIsSet |= ASET_tFacSigma;
+
+    if (WhatIsSet & (ASET_Coordinates | ASET_Anis_tFac |
+                     ASET_Anis_tFSigma))
+      // something was already submitted. check complience
+      return CheckData ( S );
+    else
+      // first data submission. just take the data
+      GetData ( S );
+
+    return Error_NoError;
+
+  }
+
+  ERROR_CODE Atom::ConvertPDBANISOU ( int ix, cpstr S )  {
+  //   Gets data from the PDB ASCII ANISOU record.
+  //   This function DOES NOT check the "ANISOU" keyword and
+  // does not decode chain and residue parameters! These must
+  // be treated by the calling process, see
+  // Chain::ConvertPDBASCII().
+
+    index = ix;
+
+    if (WhatIsSet & ASET_Anis_tFac)
+      return Error_ATOM_AlreadySet;
+
+    if (!(GetReal(u11,&(S[28]),7) &&
+          GetReal(u22,&(S[35]),7) &&
+          GetReal(u33,&(S[42]),7) &&
+          GetReal(u12,&(S[49]),7) &&
+          GetReal(u13,&(S[56]),7) &&
+          GetReal(u23,&(S[63]),7)))
+      return Error_ATOM_Unrecognized;
+
+    u11 /= 1.0e4;
+    u22 /= 1.0e4;
+    u33 /= 1.0e4;
+    u12 /= 1.0e4;
+    u13 /= 1.0e4;
+    u23 /= 1.0e4;
+
+    WhatIsSet |= ASET_Anis_tFac;
+
+    if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma |
+                     ASET_Anis_tFSigma))
+      // something was already submitted. check complience
+      return CheckData ( S );
+    else
+      // first data submission. just take the data
+      GetData ( S );
+
+    return Error_NoError;
+
+  }
+
+  ERROR_CODE Atom::ConvertPDBSIGUIJ ( int ix, cpstr S )  {
+  //   Gets data from the PDB ASCII SIGUIJ record.
+  //   This function DOES NOT check the "SIGUIJ" keyword and
+  // does not decode the chain and residue parameters! These
+  // must be treated by the calling process, see
+  // Chain::ConvertPDBASCII().
+
+    index = ix;
+
+    if (WhatIsSet & ASET_Anis_tFSigma)
+      return Error_ATOM_AlreadySet;
+
+    if (!(GetReal(su11,&(S[28]),7) &&
+          GetReal(su22,&(S[35]),7) &&
+          GetReal(su33,&(S[42]),7) &&
+          GetReal(su12,&(S[49]),7) &&
+          GetReal(su13,&(S[56]),7) &&
+          GetReal(su23,&(S[63]),7)))
+      return Error_ATOM_Unrecognized;
+
+    su11 /= 1.0e4;
+    su22 /= 1.0e4;
+    su33 /= 1.0e4;
+    su12 /= 1.0e4;
+    su13 /= 1.0e4;
+    su23 /= 1.0e4;
+
+    WhatIsSet |= ASET_Anis_tFSigma;
+
+    if (WhatIsSet & (ASET_Coordinates | ASET_CoordSigma |
+                     ASET_Anis_tFac))
+      // something was already submitted. check complience
+      return CheckData ( S );
+    else
+      // first data submission. just take the data
+      GetData ( S );
+
+    return Error_NoError;
+
+  }
+
+  ERROR_CODE Atom::ConvertPDBTER ( int ix, cpstr S )  {
+  //   Gets data from the PDB ASCII TER record.
+  //   This function DOES NOT check the "TER" keyword and
+  // does not decode the chain and residue parameters! These
+  // must be treated by the calling process, see
+  // Chain::ConvertPDBASCII().
+
+    index = ix;
+
+    if (((S[6]>='0') && (S[6]<='9')) || (S[6]==' '))  {
+      //   Although against strict PDB format, 'TER' is
+      // actually allowed not to have a serial number.
+      // This negative value implies that the number is
+      // not set.
+      if (!(GetInteger(serNum,&(S[6]),5)))  serNum = -1;
+    } else
+      hy36decode ( 5,&(S[6]),5,&serNum );
+
+  //  if (!(GetInteger(serNum,&(S[6]),5)))  serNum = -1;
+
+    if (WhatIsSet & ASET_Coordinates)
+      return Error_ATOM_AlreadySet;
+
+    WhatIsSet       |= ASET_Coordinates;
+    Het              = false;
+    Ter              = true;
+    name[0]          = char(0);
+    label_atom_id[0] = char(0);
+    element[0]       = char(0);
+
+    return Error_NoError;
+
+  }
+
+
+  int Atom::GetModelNum()  {
+    if (residue) {
+      if (residue->chain)
+        if (residue->chain->model)
+          return residue->chain->model->GetSerNum();
+    }
+    return 0;
+  }
+
+  pstr Atom::GetChainID()  {
+    if (residue) {
+      if (residue->chain)  return residue->chain->chainID;
+    }
+    return  pstr("");
+  }
+
+  pstr Atom::GetLabelAsymID()  {
+    if (residue)  return residue->label_asym_id;
+            else  return pstr("");
+  }
+
+  pstr  Atom::GetResName()  {
+    if (residue)  return residue->name;
+            else  return pstr("");
+  }
+
+  pstr  Atom::GetLabelCompID()  {
+    if (residue)  return residue->label_comp_id;
+            else  return pstr("");
+  }
+
+  int   Atom::GetAASimilarity ( const ResName resName )  {
+    if (residue)
+          return  mmdb::GetAASimilarity ( pstr(residue->name),
+                                          pstr(resName) );
+    else  return -3;
+  }
+
+  int   Atom::GetAASimilarity ( PAtom A )  {
+    if (residue)  {
+      if (A->residue)
+            return mmdb::GetAASimilarity ( pstr(residue->name),
+                                           pstr(A->residue->name) );
+      else  return -4;
+    } else
+      return -3;
+  }
+
+  realtype Atom::GetAAHydropathy()  {
+    if (residue)
+          return  mmdb::GetAAHydropathy ( pstr(residue->name) );
+    else  return  MaxReal;
+  }
+
+  realtype Atom::GetOccupancy()  {
+    if (WhatIsSet & ASET_Occupancy)  return occupancy;
+                               else  return 0.0;
+  }
+
+  int   Atom::GetSeqNum()  {
+    if (residue)  return residue->seqNum;
+            else  return ATOM_NoSeqNum;
+  }
+
+  int   Atom::GetLabelSeqID()  {
+    if (residue)  return residue->label_seq_id;
+            else  return ATOM_NoSeqNum;
+  }
+
+  int   Atom::GetLabelEntityID()  {
+    if (residue)  return residue->label_entity_id;
+            else  return -1;
+  }
+
+  pstr  Atom::GetInsCode()  {
+    if (residue)  return residue->insCode;
+            else  return pstr("");
+  }
+
+  int   Atom::GetSSEType()  {
+  // works only after SSE calculations
+    if (residue)  return residue->SSE;
+            else  return SSE_None;
+  }
+
+  pstr  Atom::GetAtomCharge ( pstr chrg )  {
+    if (WhatIsSet & ASET_Charge)  sprintf ( chrg,"%+2i",mround(charge) );
+                            else  strcpy  ( chrg,"  " );
+    return chrg;
+  }
+
+  PResidue Atom::GetResidue()  {
+    return residue;
+  }
+
+  PChain  Atom::GetChain()  {
+    if (residue)  return residue->chain;
+            else  return NULL;
+  }
+
+  PModel  Atom::GetModel()  {
+    if (residue)  {
+      if (residue->chain)  return (PModel)residue->chain->model;
+    }
+    return NULL;
+  }
+
+  int  Atom::GetResidueNo()  {
+    if (residue)  {
+      if (residue->chain)
+           return  residue->chain->GetResidueNo (
+                            residue->seqNum,residue->insCode );
+      else  return -2;
+    } else
+      return -1;
+  }
+
+
+  void * Atom::GetCoordHierarchy()  {
+    if (residue)  return residue->GetCoordHierarchy();
+    return NULL;
+  }
+
+
+  void  Atom::GetStat ( realtype   v,
+                         realtype & v_min, realtype & v_max,
+                         realtype & v_m,   realtype & v_m2 )  {
+    if (v<v_min)  v_min = v;
+    if (v>v_max)  v_max = v;
+    v_m  += v;
+    v_m2 += v*v;
+  }
+
+
+
+  void  Atom::GetChainCalphas ( PPAtom & Calphas, int & nCalphas,
+                                 cpstr altLoc )  {
+  //   GetChainCalphas(...) is a specialized function for quick
+  // access to C-alphas of chain which includes given atom.
+  // This function works faster than an equivalent implementation
+  // through MMDB's selection procedures.
+  //    Parameters:
+  //       Calphas   - array to accept pointers on C-alpha atoms
+  //                  If Calphas!=NULL, then the function will
+  //                  delete and re-allocate it. When the array
+  //                  is no longer needed, the application MUST
+  //                  delete it:  delete[] Calphas; Deleting
+  //                  Calphas does not delete atoms from MMDB.
+  //       nCalphas   - integer to accept number of C-alpha atoms
+  //                  and the length of Calphas array.
+  //       altLoc     - alternative location indicator. By default
+  //                  (""), maximum-occupancy locations are taken.
+  PChain    chain;
+  PPResidue res;
+  PPAtom    atom;
+  int        nResidues, nAtoms, i,j,k;
+
+    if (Calphas)  {
+      delete[] Calphas;
+      Calphas = NULL;
+    }
+    nCalphas = 0;
+
+    if (residue)  chain = residue->chain;
+            else  chain = NULL;
+
+    if (chain)  {
+
+      chain->GetResidueTable ( res,nResidues );
+
+      if (nResidues>0)  {
+
+        Calphas = new PAtom[nResidues];
+
+        if ((!altLoc[0]) || (altLoc[0]==' '))  {  // main conformation
+
+          for (i=0;i<nResidues;i++)  {
+            nAtoms = res[i]->nAtoms;
+            atom   = res[i]->atom;
+            for (j=0;j<nAtoms;j++)
+              if (!strcmp(atom[j]->name," CA "))  {
+                Calphas[nCalphas++] = atom[j];
+                break;
+              }
+          }
+
+        } else  {  // specific conformation
+
+          for (i=0;i<nResidues;i++)  {
+            nAtoms = res[i]->nAtoms;
+            atom   = res[i]->atom;
+            k      = 0;
+            for (j=0;j<nAtoms;j++)
+              if (!strcmp(atom[j]->name," CA "))  {
+                k = 1;
+                if (!atom[j]->altLoc[0])  {
+                  // take main conformation now as we do not know if
+                  // the specific one is in the file
+                  Calphas[nCalphas] = atom[j];
+                  k = 2;
+                } else if (atom[j]->altLoc[0]==altLoc[0])  {
+                  // get specific conformation and quit
+                  Calphas[nCalphas] = atom[j];
+                  k = 2;
+                  break;
+                }
+              } else if (k)
+                break;
+            if (k==2)  nCalphas++;
+          }
+
+        }
+
+      }
+
+    } else if (residue)  {  // check just this atom's residue
+
+      Calphas = new PAtom[1]; // can't be more than 1 C-alpha!
+
+      nAtoms = residue->nAtoms;
+      atom   = residue->atom;
+
+      if ((!altLoc[0]) || (altLoc[0]==' '))  {  // main conformation
+
+        for (j=0;j<nAtoms;j++)
+          if (!strcmp(atom[j]->name," CA "))  {
+            Calphas[nCalphas++] = atom[j];
+            break;
+          }
+
+      } else  {  // specific conformation
+
+        k = 0;
+        for (j=0;j<nAtoms;j++)
+          if (!strcmp(atom[j]->name," CA "))  {
+            k = 1;
+            if (!atom[j]->altLoc[0])  {
+              Calphas[nCalphas] = atom[j];
+              k = 2;
+            } else if (atom[j]->altLoc[0]==altLoc[0])  {
+              Calphas[nCalphas] = atom[j];
+              k = 2;
+              break;
+            }
+          } else if (k)
+            break;
+        if (k==2)  nCalphas++;
+
+      }
+
+    }
+
+    if (Calphas && (!nCalphas))  {
+      delete[] Calphas;
+      Calphas = NULL;
+    }
+
+  }
+
+  bool Atom::isMetal()  {
+    return  mmdb::isMetal ( element );
+  }
+
+  bool Atom::isSolvent()  {
+    if (residue)  return  residue->isSolvent();
+    return false;
+  }
+
+  bool Atom::isInSelection ( int selHnd )  {
+  PRoot  manager = (PRoot)GetCoordHierarchy();
+  PMask  mask;
+    if (manager)  {
+      mask = manager->GetSelMask ( selHnd );
+      if (mask)  return CheckMask ( mask );
+    }
+    return false;
+  }
+
+  bool Atom::isNTerminus()  {
+    if (residue)  return  residue->isNTerminus();
+    return false;
+  }
+
+  bool Atom::isCTerminus()  {
+    if (residue)  return  residue->isCTerminus();
+    return false;
+  }
+
+  void  Atom::CalAtomStatistics ( RAtomStat AS )  {
+  //   AS must be initialized. The function only accumulates
+  // the statistics.
+
+    if (!Ter)  {
+
+      AS.nAtoms++;
+
+      if (AS.WhatIsSet & WhatIsSet & ASET_Coordinates)  {
+        GetStat ( x,AS.xmin,AS.xmax,AS.xm,AS.xm2 );
+        GetStat ( y,AS.ymin,AS.ymax,AS.ym,AS.ym2 );
+        GetStat ( z,AS.zmin,AS.zmax,AS.zm,AS.zm2 );
+      } else
+        AS.WhatIsSet &= ~ASET_Coordinates;
+
+      if (AS.WhatIsSet & WhatIsSet & ASET_Occupancy)
+            GetStat(occupancy,AS.occ_min,AS.occ_max,AS.occ_m,AS.occ_m2);
+      else  AS.WhatIsSet &= ~ASET_Occupancy;
+
+      if (AS.WhatIsSet & WhatIsSet & ASET_tempFactor)
+            GetStat ( tempFactor,AS.tFmin,AS.tFmax,AS.tFm,AS.tFm2 );
+      else  AS.WhatIsSet &= ~ASET_tempFactor;
+
+      if (AS.WhatIsSet & WhatIsSet & ASET_Anis_tFac)  {
+        GetStat ( u11,AS.u11_min,AS.u11_max,AS.u11_m,AS.u11_m2 );
+        GetStat ( u22,AS.u22_min,AS.u22_max,AS.u22_m,AS.u22_m2 );
+        GetStat ( u33,AS.u33_min,AS.u33_max,AS.u33_m,AS.u33_m2 );
+        GetStat ( u12,AS.u12_min,AS.u12_max,AS.u12_m,AS.u12_m2 );
+        GetStat ( u13,AS.u13_min,AS.u13_max,AS.u13_m,AS.u13_m2 );
+        GetStat ( u23,AS.u23_min,AS.u23_max,AS.u23_m,AS.u23_m2 );
+      } else
+        AS.WhatIsSet &= ~ASET_Anis_tFac;
+
+    }
+
+  }
+
+
+  realtype Atom::GetDist2 ( PAtom a )  {
+  realtype dx,dy,dz;
+    dx = a->x - x;
+    dy = a->y - y;
+    dz = a->z - z;
+    return  dx*dx + dy*dy + dz*dz;
+  }
+
+  realtype Atom::GetDist2 ( PAtom a, mat44 & tm )  {
+  realtype dx,dy,dz;
+    dx = tm[0][0]*a->x + tm[0][1]*a->y + tm[0][2]*a->z + tm[0][3] - x;
+    dy = tm[1][0]*a->x + tm[1][1]*a->y + tm[1][2]*a->z + tm[1][3] - y;
+    dz = tm[2][0]*a->x + tm[2][1]*a->y + tm[2][2]*a->z + tm[2][3] - z;
+    return  dx*dx + dy*dy + dz*dz;
+  }
+
+  realtype Atom::GetDist2 ( PAtom a, mat33 & r, vect3 & t )  {
+  realtype dx,dy,dz;
+    dx = r[0][0]*a->x + r[0][1]*a->y + r[0][2]*a->z + t[0] - x;
+    dy = r[1][0]*a->x + r[1][1]*a->y + r[1][2]*a->z + t[1] - y;
+    dz = r[2][0]*a->x + r[2][1]*a->y + r[2][2]*a->z + t[2] - z;
+    return  dx*dx + dy*dy + dz*dz;
+  }
+
+  realtype Atom::GetDist2 ( realtype ax, realtype ay, realtype az )  {
+  realtype dx,dy,dz;
+    dx = ax - x;
+    dy = ay - y;
+    dz = az - z;
+    return  dx*dx + dy*dy + dz*dz;
+  }
+
+  realtype Atom::GetCosine ( PAtom a1, PAtom a2 )  {
+  // Calculates cosing of angle a1-this-a2, i.e. that between
+  // bond [a1,this] and [this,a2].
+  realtype dx1,dy1,dz1, dx2,dy2,dz2,r;
+
+    dx1 = a1->x - x;
+    dy1 = a1->y - y;
+    dz1 = a1->z - z;
+    r   = dx1*dx1 + dy1*dy1 + dz1*dz1;
+
+    dx2 = a2->x - x;
+    dy2 = a2->y - y;
+    dz2 = a2->z - z;
+    r  *= dx2*dx2 + dy2*dy2 + dz2*dz2;
+
+    if (r>0.0)  return (dx1*dx2 + dy1*dy2 + dz1*dz2)/sqrt(r);
+          else  return 0.0;
+
+  }
+
+
+  void  Atom::MakeTer()  {
+    WhatIsSet |= ASET_Coordinates;
+    Het        = false;
+    Ter        = true;
+  }
+
+
+  void  Atom::SetAtomName ( const AtomName atomName )  {
+    strcpy ( name,atomName );
+  }
+
+
+  void  Atom::SetElementName ( const Element elName )  {
+    strcpy ( element,elName );
+    if (!element[0])  strcpy ( element,"  " );
+    else if ((!element[1]) || (element[1]==' '))  {
+      element[2] = char(0);
+      element[1] = element[0];
+      element[0] = ' ';
+    }
+  }
+
+  void  Atom::SetCharge ( cpstr chrg )  {
+  pstr p;
+    charge = strtod ( chrg,&p );
+    if (p!=chrg)  {
+      WhatIsSet |= ASET_Charge;
+      if ((charge>0.0) && (*p=='-'))
+        charge = -charge;
+    }
+  }
+
+  void  Atom::SetCharge ( realtype chrg )  {
+    if (chrg<MaxReal)  {
+      charge = chrg;
+      WhatIsSet |= ASET_Charge;
+    }
+  }
+
+  void  Atom::SetAtomIndex ( int ix )  {
+  // don't use in your applications!
+    index = ix;
+  }
+
+  pstr  Atom::GetAtomID ( pstr AtomID )  {
+  char  S[50];
+    AtomID[0] = char(0);
+    if (residue)  {
+      if (residue->chain)  {
+        if (residue->chain->model)
+              sprintf (AtomID,"/%i/",residue->chain->model->GetSerNum());
+        else  strcpy  ( AtomID,"/-/" );
+        strcat ( AtomID,residue->chain->chainID );
+      } else
+        strcpy ( AtomID,"/-/-" );
+      ParamStr ( AtomID,pstr("/"),residue->seqNum );
+      if (residue->name[0])  {
+        strcat ( AtomID,"(" );
+        strcat ( AtomID,residue->name );
+        strcat ( AtomID,")" );
+      }
+      if (residue->insCode[0])  {
+        strcat ( AtomID,"." );
+        strcat ( AtomID,residue->insCode );
+      }
+      strcat ( AtomID,"/" );
+    } else
+      strcpy ( AtomID,"/-/-/-/" );
+    strcpy_css ( S,name );
+    if (!S[0])  strcpy ( S,"-" );
+    strcat     ( AtomID,S );
+    strcpy_css ( S,element );
+    if (S[0])  {
+      strcat ( AtomID,"[" );
+      strcat ( AtomID,S   );
+      strcat ( AtomID,"]" );
+    }
+    if (altLoc[0])  {
+      strcat ( AtomID,":" );
+      strcat ( AtomID,altLoc );
+    }
+    return AtomID;
+  }
+
+  pstr  Atom::GetAtomIDfmt ( pstr AtomID )  {
+  int  n;
+  char S[50];
+    AtomID[0] = char(0);
+    if (residue)  {
+      if (residue->chain)  {
+        if (residue->chain->model)  {
+          n = residue->chain->model->GetNumberOfModels();
+      if      (n<10)   strcpy ( S,"/%1i/" );
+      else if (n<100)  strcpy ( S,"/%2i/" );
+      else if (n<1000) strcpy ( S,"/%3i/" );
+                      else strcpy ( S,"/%i/"  );
+          sprintf ( AtomID,S,residue->chain->model->GetSerNum() );
+        } else
+          strcpy  ( AtomID,"/-/" );
+        strcat ( AtomID,residue->chain->chainID );
+      } else
+        strcpy ( AtomID,"/-/-" );
+      if ((-999<=residue->seqNum) && (residue->seqNum<=9999))
+            sprintf ( S,"/%4i",residue->seqNum );
+      else  sprintf ( S,"/%i" ,residue->seqNum );
+      strcat  ( AtomID,S );
+      sprintf ( S,"(%3s).%1s/",residue->name,residue->insCode );
+      strcat  ( AtomID,S );
+    } else
+      strcpy ( AtomID,"/-/-/----(---).-/" );
+    sprintf ( S,"%4s[%2s]:%1s",name,element,altLoc );
+    strcat  ( AtomID,S );
+    return AtomID;
+  }
+
+
+
+  ERROR_CODE Atom::ConvertPDBHETATM ( int ix, cpstr S )  {
+  //   Gets data from the PDB ASCII HETATM record.
+  //   This function DOES NOT check the "HETATM" keyword and
+  // does not decode the chain and residue parameters! These
+  // must be treated by the calling process, see
+  // Chain::ConvertPDBASCII().
+  ERROR_CODE RC;
+    RC  = ConvertPDBATOM ( ix,S );
+    Het = true;
+    return RC;
+  }
+
+  void Atom::GetData ( cpstr S )  {
+  pstr p;
+
+    if (((S[6]>='0') && (S[6]<='9')) || (S[6]==' '))  {
+      //   Here we forgive cards with unreadable serial numbers
+      // as we always have index (ix) for the card. For the sake
+      // of strict PDB syntax we would have to return
+      // Error_UnrecognizedInteger here.
+      if (!(GetInteger(serNum,&(S[6]),5)))  serNum = -1;
+    } else
+      hy36decode ( 5,&(S[6]),5,&serNum );
+
+  //  if (!(GetInteger(serNum,&(S[6]),5)))  serNum = index;
+
+    altLoc[0] = S[16];
+    if (altLoc[0]==' ')  altLoc[0] = char(0);
+                   else  altLoc[1] = char(0);
+    GetString   ( name   ,&(S[12]),4 );
+    strcpy_ncss ( segID  ,&(S[72]),4 );
+    GetString   ( element,&(S[76]),2 );
+    charge = strtod ( &(S[78]),&p );
+    if ((charge!=0.0) && (p!=&(S[78])))  {
+      WhatIsSet |= ASET_Charge;
+      if ((charge>0.0) && (*p=='-'))
+        charge = -charge;
+    }
+
+    RestoreElementName();
+    strcpy ( label_atom_id,name );
+
+  }
+
+  ERROR_CODE Atom::CheckData ( cpstr S )  {
+  int      sN;
+  AltLoc   aloc;
+  SegID    sID;
+  Element  elmnt;
+  pstr     p;
+  realtype achrg;
+
+    aloc[0] = S[16];
+    if (aloc[0]==' ')  aloc[0] = char(0);
+                 else  aloc[1] = char(0);
+
+    strcpy_ncss ( sID  ,&(S[72]),4 );
+    GetString   ( elmnt,&(S[76]),2 );
+
+    if (ignoreCharge)
+      achrg = charge;
+    else  {
+      achrg = strtod ( &(S[78]),&p );
+      if ((achrg!=0.0) && (p!=&(S[78])))  {
+        if ((achrg>0.0) && (*p=='-'))
+          achrg = -achrg;
+      }
+    }
+
+  //  if (!(GetInteger(sN,&(S[6]),5)))
+  //    sN = index;
+
+    if (hy36decode(5,&(S[6]),5,&sN))
+      sN = index;
+
+    if (ignoreSegID)  {
+      if (segID[0])  strcpy ( sID,segID );
+               else  strcpy ( segID,sID );
+    }
+
+    if (ignoreElement)  {
+      if (element[0])  strcpy ( elmnt,element );
+                 else  strcpy ( element,elmnt );
+    }
+
+    if (ignoreUnmatch)  return Error_NoError;
+
+    //   Here we forgive cards with unreadable serial numbers
+    // as we always have index (ix) for the card. For the sake
+    // of strict PDB syntax we would have to return
+    // Error_UnrecognizedInteger .
+    if ((sN!=serNum)                  ||
+        (strcmp (altLoc ,aloc      )) ||
+        (strncmp(name   ,&(S[12]),4)) ||
+        (strcmp (segID  ,sID       )) ||
+        (strcmp (element,elmnt     )) ||
+        (charge!=achrg))  {
+      /*
+  char name1[100];
+  strncpy ( name1,&(S[12]),4 );  name1[4] = char(0);
+      printf ( "\n  serNum   %5i  %5i\n"
+               "  residue  '%s' '%s'\n"
+               "  altLoc   '%s' '%s'\n"
+               "  name     '%s' '%s'\n"
+               "  segId    '%s' '%s'\n"
+               "  element  '%s' '%s'\n"
+               "  charge   '%s' '%s'\n",
+               sN,serNum, res->name,residue->name,
+               altLoc ,aloc,  name,name1,
+           segID  ,sID,
+        element,elmnt,
+           charge ,achrg );
+      if (res!=residue)  printf (" it's a residue\n" );
+      */
+      return Error_ATOM_Unmatch;
+    }
+
+    return Error_NoError;
+
+  }
+
+
+  ERROR_CODE Atom::GetCIF ( int ix, mmcif::PLoop Loop,
+                            mmcif::PLoop LoopAnis )  {
+  char        PDBGroup[30];
+  int         k;
+  ERROR_CODE  RC;
+
+    index = ix;
+
+    if (WhatIsSet & ASET_Coordinates)
+      return Error_ATOM_AlreadySet;
+
+  /*
+
+  loop_
+  *0  _atom_site.group_PDB
+  *1  _atom_site.id
+  *2  _atom_site.type_symbol         <- chem elem
+  -3  _atom_site.label_atom_id       <- atom name
+  *4  _atom_site.label_alt_id        <- alt code
+  =5  _atom_site.label_comp_id       <- res name ???
+  =6  _atom_site.label_asym_id       <- chain id ???
+  =7  _atom_site.label_entity_id     < ???
+  =8  _atom_site.label_seq_id        <- poly seq id
+  +9  _atom_site.pdbx_PDB_ins_code   <- ins code
+  -10 _atom_site.segment_id          <- segment id
+  *11 _atom_site.Cartn_x
+  *12 _atom_site.Cartn_y
+  *13 _atom_site.Cartn_z
+  *14 _atom_site.occupancy
+  *15 _atom_site.B_iso_or_equiv
+  *16 _atom_site.Cartn_x_esd
+  *17 _atom_site.Cartn_y_esd
+  *18 _atom_site.Cartn_z_esd
+  *19 _atom_site.occupancy_esd
+  *20 _atom_site.B_iso_or_equiv_esd
+  *21 _atom_site.pdbx_formal_charge
+  +22 _atom_site.auth_seq_id          <- seq id we want
+  +23 _atom_site.auth_comp_id         <- res name we want
+  +24 _atom_site.auth_asym_id         <- ch id we want ?
+  *25 _atom_site.auth_atom_id         <- atom name we want ?
+  +26 _atom_site.pdbx_PDB_model_num   <- model no
+
+  '+' read in Root::CheckAtomPlace()
+  '=' new in residue, read in Root::CheckAtomPlace()
+  '-' new in atom
+
+  */
+
+
+    // (0)
+    k = ix-1;
+    CIFGetString ( PDBGroup,Loop,CIFTAG_GROUP_PDB,k,
+                   sizeof(PDBGroup),pstr("") );
+
+    Ter = !strcmp(PDBGroup,pstr("TER")   );
+    Het = !strcmp(PDBGroup,pstr("HETATM"));
+
+    // (1)
+    RC = CIFGetInteger1 ( serNum,Loop,CIFTAG_ID,k );
+    if (RC)  {
+      if (Ter)                    serNum = -1;
+      else if (RC==Error_NoData)  serNum = index;
+      else
+        return RC;
+    }
+
+    if (Ter)  {
+      Loop->DeleteRow ( k );
+      WhatIsSet |= ASET_Coordinates;
+      return Error_NoError;
+    }
+
+    // (25)
+    CIFGetString ( name,Loop,CIFTAG_AUTH_ATOM_ID,k,
+                          sizeof(name)  ,pstr("") );
+    // (3)
+    CIFGetString ( label_atom_id,Loop,CIFTAG_LABEL_ATOM_ID,k,
+                          sizeof(label_atom_id),pstr("") );
+    if (!name[0])
+      strcpy ( name,label_atom_id );
+    // (4)
+    CIFGetString ( altLoc,Loop,CIFTAG_LABEL_ALT_ID ,k,
+                          sizeof(altLoc),pstr("") );
+
+    // (11,12,13)
+    RC = CIFGetReal1 ( x,Loop,CIFTAG_CARTN_X,k );
+    if (!RC) RC = CIFGetReal1 ( y,Loop,CIFTAG_CARTN_Y,k );
+    if (!RC) RC = CIFGetReal1 ( z,Loop,CIFTAG_CARTN_Z,k );
+    if (RC)  return Error_ATOM_Unrecognized;
+    WhatIsSet |= ASET_Coordinates;
+
+    // (14)
+    if (!CIFGetReal1(occupancy,Loop,CIFTAG_OCCUPANCY,k))
+      WhatIsSet |= ASET_Occupancy;
+    // (15)
+    if (!CIFGetReal1(tempFactor,Loop,CIFTAG_B_ISO_OR_EQUIV,k))
+      WhatIsSet |= ASET_tempFactor;
+
+    // (10)
+    CIFGetString ( segID,Loop,CIFTAG_SEGMENT_ID,k,
+                         sizeof(segID) ,pstr("") );
+    // (21)
+    if (!CIFGetReal1(charge,Loop,CIFTAG_PDBX_FORMAL_CHARGE,k))
+      WhatIsSet |= ASET_Charge;
+    // (2)
+    RC = CIFGetString ( element,Loop,CIFTAG_TYPE_SYMBOL,k,
+                                sizeof(element),pstr("") );
+    if (RC)
+      CIFGetString ( element,Loop,CIFTAG_ATOM_TYPE_SYMBOL,k,
+                          sizeof(element),pstr("") );
+
+    RestoreElementName();
+    MakePDBAtomName();
+
+    // (16,17,18)
+    RC = CIFGetReal1 ( sigX,Loop,CIFTAG_CARTN_X_ESD,k );
+    if (!RC) RC = CIFGetReal1 ( sigY,Loop,CIFTAG_CARTN_Y_ESD,k );
+    if (!RC) RC = CIFGetReal1 ( sigZ,Loop,CIFTAG_CARTN_Z_ESD,k );
+    if (RC==Error_UnrecognizedReal)
+      return RC;
+    if (!RC) WhatIsSet |= ASET_CoordSigma;
+
+    // (19)
+    if (!CIFGetReal1(sigOcc,Loop,CIFTAG_OCCUPANCY_ESD,k))
+      WhatIsSet |= ASET_OccSigma;
+    // (20)
+    if (!CIFGetReal1(sigTemp,Loop,CIFTAG_B_ISO_OR_EQUIV_ESD,k))
+      WhatIsSet |= ASET_tFacSigma;
+
+    Loop->DeleteRow ( k );
+
+    if (LoopAnis)  {
+
+      RC = CIFGetReal1 ( u11,LoopAnis,CIFTAG_U11,k );
+      if (!RC) RC = CIFGetReal1 ( u22,LoopAnis,CIFTAG_U22,k );
+      if (!RC) RC = CIFGetReal1 ( u33,LoopAnis,CIFTAG_U33,k );
+      if (!RC) RC = CIFGetReal1 ( u13,LoopAnis,CIFTAG_U13,k );
+      if (!RC) RC = CIFGetReal1 ( u12,LoopAnis,CIFTAG_U12,k );
+      if (!RC) RC = CIFGetReal1 ( u23,LoopAnis,CIFTAG_U23,k );
+      if (RC==Error_UnrecognizedReal)
+        return RC;
+      if (!RC) WhatIsSet |= ASET_Anis_tFac;
+
+      RC = CIFGetReal1 ( su11,LoopAnis,CIFTAG_U11_ESD,k );
+      if (!RC) RC = CIFGetReal1 ( su22,LoopAnis,CIFTAG_U22_ESD,k );
+      if (!RC) RC = CIFGetReal1 ( su33,LoopAnis,CIFTAG_U33_ESD,k );
+      if (!RC) RC = CIFGetReal1 ( su13,LoopAnis,CIFTAG_U13_ESD,k );
+      if (!RC) RC = CIFGetReal1 ( su12,LoopAnis,CIFTAG_U12_ESD,k );
+      if (!RC) RC = CIFGetReal1 ( su23,LoopAnis,CIFTAG_U23_ESD,k );
+      if (RC==Error_UnrecognizedReal)
+        return RC;
+      if (!RC) WhatIsSet |= ASET_Anis_tFSigma;
+
+      LoopAnis->DeleteRow ( k );
+
+    }
+
+    return Error_NoError;
+
+  }
+
+  bool Atom::RestoreElementName()  {
+  //  This function works only if element name is not given.
+
+    if (Ter)  {
+      name[0]    = char(0);
+      element[0] = char(0);
+      return false;
+    }
+    if ((!element[0]) ||
+        ((element[0]==' ') && ((!element[1]) || (element[1]==' '))))  {
+      if (strlen(name)==4)  {
+        if ((name[0]>='A') && (name[0]<='Z'))  {
+          element[0] = name[0];
+          element[1] = name[1];
+        } else  {
+          element[0] = ' ';
+          element[1] = name[1];
+        }
+      } else  {  // nasty hack for mmcif files without element column
+        element[0] = ' ';
+        element[1] = name[0];
+      }
+      element[2] = char(0);
+      return false;
+    } else if (!element[1])  {
+      // not aligned element name, possibly coming from mmCIF
+      element[1] = element[0];
+      element[0] = ' ';
+      element[2] = char(0);
+      return false;
+    }
+    return true;
+  }
+
+  bool Atom::MakePDBAtomName()  {
+  int     i,k;
+
+    if (Ter)  {
+      name   [0] = char(0);
+      element[0] = char(0);
+      return false;
+    }
+    UpperCase ( name    );
+    UpperCase ( element );
+    if ((element[0]==' ') && (element[1]==' '))  {
+      // element name not given, make one from the atom name
+      if ((name[0]>='A') && (name[0]<='Z'))  {
+        if (!name[1])  {
+          name[4] = char(0);
+          name[3] = ' ';
+          name[2] = ' ';
+          name[1] = name[0];
+          name[0] = ' ';
+        }
+        /* the commented part looks like a wrong inheritance
+           from FORTRAN RWBrook. Commented on 04.03.2004,
+           to be removed.
+        else if ((name[0]=='C') && (name[1]=='A'))  {
+          name[4] = char(0);
+          name[3] = name[2];
+          name[2] = name[1];
+          name[1] = name[0];
+          name[0] = ' ';
+        }
+        */
+        element[0] = name[0];
+        element[1] = name[1];
+      } else  {
+        element[0] = ' ';
+        element[1] = name[1];
+      }
+      element[2] = char(0);
+      return false;
+    } else if ((name[0]>='A') && (name[0]<='Z'))  {
+      if (!element[1])  {
+        element[2] = char(0);
+        element[1] = element[0];
+        element[0] = ' ';
+        k = strlen(name);
+        if (k<4)  {
+          for (i=3;i>0;i--)
+            name[i] = name[i-1];
+          name[0] = ' ';
+          k++;
+          while (k<4)
+            name[k++] = ' ';
+          name[k] = char(0);
+        }
+      } else if ((element[0]==' ') && (element[1]!=name[1]))  {
+        for (i=3;i>0;i--)
+          name[i] = name[i-1];
+        name[0] = ' ';
+        name[4] = char(0);
+        k = strlen(name);
+        while (k<4)
+          name[k++] = ' ';
+        name[k] = char(0);
+      } else  {
+        k = strlen(name);
+        while (k<4)
+          name[k++] = ' ';
+        name[k] = char(0);
+      }
+    }
+    return true;
+  }
+
+  void  Atom::SetCoordinates ( realtype xx,  realtype yy, realtype zz,
+                               realtype occ, realtype tFac )  {
+    x = xx;
+    y = yy;
+    z = zz;
+    occupancy  = occ;
+    tempFactor = tFac;
+    WhatIsSet |= ASET_Coordinates | ASET_Occupancy | ASET_tempFactor;
+  }
+
+  void  Atom::Transform ( mat33 & tm, vect3 & v ) {
+  realtype  x1,y1,z1;
+    x1 = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + v[0];
+    y1 = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + v[1];
+    z1 = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + v[2];
+    x = x1;
+    y = y1;
+    z = z1;
+  }
+
+  void  Atom::Transform ( mat44 & tm ) {
+  realtype  x1,y1,z1;
+    x1 = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3];
+    y1 = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3];
+    z1 = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3];
+    x = x1;
+    y = y1;
+    z = z1;
+  }
+
+  void  Atom::TransformCopy ( mat44    & tm,
+                               realtype & xx,
+                               realtype & yy,
+                               realtype & zz )  {
+    xx = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3];
+    yy = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3];
+    zz = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3];
+  }
+
+  void  Atom::TransformSet ( mat44  & tm,
+                              realtype xx,
+                              realtype yy,
+                              realtype zz ) {
+    x = tm[0][0]*xx + tm[0][1]*yy + tm[0][2]*zz + tm[0][3];
+    y = tm[1][0]*xx + tm[1][1]*yy + tm[1][2]*zz + tm[1][3];
+    z = tm[2][0]*xx + tm[2][1]*yy + tm[2][2]*zz + tm[2][3];
+  }
+
+
+  // -------  user-defined data handlers
+
+  int  Atom::PutUDData ( int UDDhandle, int iudd )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::putUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Atom::PutUDData ( int UDDhandle, realtype rudd )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::putUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Atom::PutUDData ( int UDDhandle, cpstr sudd )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::putUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Atom::GetUDData ( int UDDhandle, int & iudd )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::getUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Atom::GetUDData ( int UDDhandle, realtype & rudd )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::getUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Atom::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::getUDData ( UDDhandle,sudd,maxLen );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Atom::GetUDData ( int UDDhandle, pstr & sudd )  {
+    if (UDDhandle & UDRF_ATOM)
+          return  UDData::getUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+
+  void  Atom::Copy ( PAtom atom )  {
+  // this does not make any references in residues and does
+  // not change indices!! it does change serial numbers, though.
+
+    serNum     = atom->serNum;
+    x          = atom->x;
+    y          = atom->y;
+    z          = atom->z;
+    occupancy  = atom->occupancy;
+    tempFactor = atom->tempFactor;
+    sigX       = atom->sigX;
+    sigY       = atom->sigY;
+    sigZ       = atom->sigZ;
+    sigOcc     = atom->sigOcc;
+    sigTemp    = atom->sigTemp;
+    u11        = atom->u11;
+    u22        = atom->u22;
+    u33        = atom->u33;
+    u12        = atom->u12;
+    u13        = atom->u13;
+    u23        = atom->u23;
+    su11       = atom->su11;
+    su22       = atom->su22;
+    su33       = atom->su33;
+    su12       = atom->su12;
+    su13       = atom->su13;
+    su23       = atom->su23;
+    Het        = atom->Het;
+    Ter        = atom->Ter;
+    WhatIsSet  = atom->WhatIsSet;
+
+    strcpy ( name         ,atom->name          );
+    strcpy ( label_atom_id,atom->label_atom_id );
+    strcpy ( altLoc       ,atom->altLoc        );
+    strcpy ( segID        ,atom->segID         );
+    strcpy ( element      ,atom->element       );
+    strcpy ( energyType   ,atom->energyType    );
+    charge = atom->charge;
+
+  }
+
+  int Atom::CheckID ( const AtomName aname, const Element elname,
+                       const AltLoc aloc )  {
+  pstr p1,p2;
+    if (aname)  {
+      if (aname[0]!='*')  {
+        p1 = name;
+        while (*p1==' ') p1++;
+        p2 = pstr(aname);
+        while (*p2==' ') p2++;
+        while ((*p2) && (*p1) && (*p1!=' ') && (*p2!=' '))  {
+          if (*p1!=*p2)  return 0;
+          p1++;
+          p2++;
+        }
+        if (*p1!=*p2)  {
+          if (((*p1) && (*p1!=' ')) ||
+              ((*p2) && (*p2!=' ')))  return 0;
+        }
+      }
+    }
+    if (elname)  {
+      if (elname[0]!='*')  {
+        p1 = element;
+        while (*p1==' ')  p1++;
+        p2 = pstr(elname);
+        while (*p2==' ')  p2++;
+        while ((*p2) && (*p1) && (*p1!=' ') && (*p2!=' '))  {
+          if (*p1!=*p2)  return 0;
+          p1++;
+          p2++;
+        }
+        if (*p1!=*p2)  return 0;
+      }
+    }
+    if (aloc)  {
+      if ((aloc[0]!='*') && (strcmp(aloc,altLoc)))   return 0;
+    }
+    return 1;
+  }
+
+  int Atom::CheckIDS ( cpstr ID )  {
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+  pstr     p;
+    p = strrchr ( ID,'/' );
+    if (p)  p++;
+      else  p = pstr(ID);
+    ParseAtomID ( p,aname,elname,aloc );
+    return  CheckID ( aname,elname,aloc );
+  }
+
+  void  Atom::SetShortBinary()  {
+    WhatIsSet |= ASET_ShortBinary;
+  }
+
+  void  Atom::write ( io::RFile f )  {
+  int  i,k;
+  byte Version=2;
+  byte nb;
+
+    f.WriteWord ( &WhatIsSet );
+    if (WhatIsSet & ASET_ShortBinary)  {
+      if (Ter)  WhatIsSet |= ASET_ShortTer;
+      if (Het)  WhatIsSet |= ASET_ShortHet;
+      f.WriteInt     ( &index        );
+      f.WriteTerLine ( name   ,false );
+      f.WriteTerLine ( altLoc ,false );
+      f.WriteTerLine ( element,false );
+      if (WhatIsSet & ASET_Coordinates)  {
+        f.WriteFloat ( &x );
+        f.WriteFloat ( &y );
+        f.WriteFloat ( &z );
+      }
+      return;
+    }
+
+    f.WriteByte  ( &Version );
+
+    UDData::write ( f );
+
+    f.WriteInt     ( &serNum );
+    f.WriteInt     ( &index  );
+    f.WriteTerLine ( name         ,false );
+    f.WriteTerLine ( label_atom_id,false );
+    f.WriteTerLine ( altLoc       ,false );
+    f.WriteTerLine ( segID        ,false );
+    f.WriteTerLine ( element      ,false );
+    f.WriteTerLine ( energyType   ,false );
+    f.WriteFloat   ( &charge );
+    f.WriteBool    ( &Het    );
+    f.WriteBool    ( &Ter    );
+
+    if (WhatIsSet & ASET_Coordinates)  {
+      f.WriteFloat ( &x );
+      f.WriteFloat ( &y );
+      f.WriteFloat ( &z );
+      if (WhatIsSet & ASET_Occupancy)
+        f.WriteFloat ( &occupancy  );
+      if (WhatIsSet & ASET_tempFactor)
+        f.WriteFloat ( &tempFactor );
+    }
+
+    if (WhatIsSet & ASET_CoordSigma)  {
+      f.WriteFloat ( &sigX );
+      f.WriteFloat ( &sigY );
+      f.WriteFloat ( &sigZ );
+      if ((WhatIsSet & ASET_Occupancy) &&
+          (WhatIsSet & ASET_OccSigma))
+        f.WriteFloat ( &sigOcc );
+      if ((WhatIsSet & ASET_tempFactor) &&
+          (WhatIsSet & ASET_tFacSigma))
+        f.WriteFloat ( &sigTemp );
+    }
+
+    if (WhatIsSet & ASET_Anis_tFac)  {
+      f.WriteFloat ( &u11 );
+      f.WriteFloat ( &u22 );
+      f.WriteFloat ( &u33 );
+      f.WriteFloat ( &u12 );
+      f.WriteFloat ( &u13 );
+      f.WriteFloat ( &u23 );
+      if (WhatIsSet & ASET_Anis_tFSigma)  {
+        f.WriteFloat ( &su11 );
+        f.WriteFloat ( &su22 );
+        f.WriteFloat ( &su33 );
+        f.WriteFloat ( &su12 );
+        f.WriteFloat ( &su13 );
+        f.WriteFloat ( &su23 );
+      }
+    }
+
+    nb = byte(nBonds & 0x000000FF);
+    f.WriteByte ( &nb );
+    for (i=0;i<nb;i++)
+      if (Bond[i].atom)  {
+        f.WriteInt  ( &(Bond[i].atom->index) );
+        f.WriteByte ( &(Bond[i].order)       );
+      } else  {
+        k = -1;
+        f.WriteInt  ( &k );
+      }
+
+  }
+
+  void  Atom::read ( io::RFile f ) {
+  int  i,k;
+  byte nb,Version;
+
+    FreeMemory();
+
+    f.ReadWord ( &WhatIsSet );
+    if (WhatIsSet & ASET_ShortBinary)  {
+      f.ReadInt     ( &index        );
+      f.ReadTerLine ( name   ,false );
+      f.ReadTerLine ( altLoc ,false );
+      f.ReadTerLine ( element,false );
+      if (WhatIsSet & ASET_Coordinates)  {
+        f.ReadFloat ( &x );
+        f.ReadFloat ( &y );
+        f.ReadFloat ( &z );
+      }
+      serNum     = index;
+      Ter        = WhatIsSet & ASET_ShortTer;
+      Het        = WhatIsSet & ASET_ShortHet;
+      name   [4] = char(0);
+      altLoc [1] = char(0);
+      element[2] = char(0);
+      segID  [0] = char(0);
+      charge     = 0.0;
+      WhatIsSet &= ASET_All;
+      return;
+    }
+
+    f.ReadByte  ( &Version );
+
+    UDData::read ( f );
+
+    f.ReadInt     ( &serNum );
+    f.ReadInt     ( &index  );
+    f.ReadTerLine ( name      ,false );
+    if (Version>1)
+      f.ReadTerLine ( label_atom_id,false );
+    f.ReadTerLine ( altLoc    ,false );
+    f.ReadTerLine ( segID     ,false );
+    f.ReadTerLine ( element   ,false );
+    f.ReadTerLine ( energyType,false );
+    f.ReadFloat   ( &charge );
+    f.ReadBool    ( &Het    );
+    f.ReadBool    ( &Ter    );
+
+    if (WhatIsSet & ASET_Coordinates)  {
+      f.ReadFloat ( &x );
+      f.ReadFloat ( &y );
+      f.ReadFloat ( &z );
+      if (WhatIsSet & ASET_Occupancy)  f.ReadFloat ( &occupancy  );
+                                 else  occupancy = 0.0;
+      if (WhatIsSet & ASET_tempFactor) f.ReadFloat ( &tempFactor );
+                                 else  tempFactor = 0.0;
+    } else  {
+      x          = 0.0;
+      y          = 0.0;
+      z          = 0.0;
+      occupancy  = 0.0;
+      tempFactor = 0.0;
+    }
+
+    if (WhatIsSet & ASET_CoordSigma)  {
+      f.ReadFloat ( &sigX );
+      f.ReadFloat ( &sigY );
+      f.ReadFloat ( &sigZ );
+      if ((WhatIsSet & ASET_Occupancy) &&
+          (WhatIsSet & ASET_OccSigma))
+            f.ReadFloat ( &sigOcc );
+      else  sigOcc = 0.0;
+      if ((WhatIsSet & ASET_tempFactor) &&
+          (WhatIsSet & ASET_tFacSigma))
+            f.ReadFloat ( &sigTemp );
+      else  sigTemp = 0.0;
+    } else  {
+      sigX    = 0.0;
+      sigY    = 0.0;
+      sigZ    = 0.0;
+      sigOcc  = 0.0;
+      sigTemp = 0.0;
+    }
+
+    if (WhatIsSet & ASET_Anis_tFac)  {
+      f.ReadFloat ( &u11 );
+      f.ReadFloat ( &u22 );
+      f.ReadFloat ( &u33 );
+      f.ReadFloat ( &u12 );
+      f.ReadFloat ( &u13 );
+      f.ReadFloat ( &u23 );
+      if (WhatIsSet & ASET_Anis_tFSigma)  {
+        f.ReadFloat ( &su11 );
+        f.ReadFloat ( &su22 );
+        f.ReadFloat ( &su33 );
+        f.ReadFloat ( &su12 );
+        f.ReadFloat ( &su13 );
+        f.ReadFloat ( &su23 );
+      } else  {
+        su11 = 0.0;
+        su22 = 0.0;
+        su33 = 0.0;
+        su12 = 0.0;
+        su13 = 0.0;
+        su23 = 0.0;
+      }
+    } else  {
+      u11  = 0.0;
+      u22  = 0.0;
+      u33  = 0.0;
+      u12  = 0.0;
+      u13  = 0.0;
+      u23  = 0.0;
+      su11 = 0.0;
+      su22 = 0.0;
+      su33 = 0.0;
+      su12 = 0.0;
+      su13 = 0.0;
+      su23 = 0.0;
+    }
+
+    f.ReadByte ( &nb );
+    if (nb>0)  {
+      Bond = new AtomBond[nb];
+      for (i=0;i<nb;i++)  {
+        f.ReadInt  ( &k );
+        if (k>0)  f.ReadByte ( &(Bond[i].order) );
+            else  Bond[i].order = 0;
+        // we place *index* of bonded atom temporary on the place
+        // of its pointer, and the pointer will be calculated
+        // after Residue::read calls _setBonds(..).
+        memcpy ( &(Bond[i].atom),&k,4 );
+      }
+    }
+    nBonds = nb;
+    nBonds = nBonds | (nBonds << 8);
+
+  }
+
+  void Atom::_setBonds ( PPAtom A )  {
+  int i,k,nb;
+    nb = nBonds & 0x000000FF;
+    for (i=0;i<nb;i++)  {
+      memcpy ( &k,&(Bond[i].atom),4 );
+      if (k>0)  Bond[i].atom = A[k];
+          else  Bond[i].atom = NULL;
+    }
+  }
+
+
+  MakeFactoryFunctions(Atom)
+
+
+
+  //  ===========================  Residue  ===========================
+
+
+  void  AtomStat::Init()  {
+
+    nAtoms = 0;
+
+    xmin = MaxReal;   xmax = MinReal;    xm = 0.0;  xm2 = 0.0;
+    ymin = MaxReal;   ymax = MinReal;    ym = 0.0;  ym2 = 0.0;
+    zmin = MaxReal;   zmax = MinReal;    zm = 0.0;  zm2 = 0.0;
+
+    occ_min = MaxReal;  occ_max = MinReal;  occ_m = 0.0;  occ_m2 = 0.0;
+    tFmin   = MaxReal;  tFmax   = MinReal;  tFm   = 0.0;  tFm2   = 0.0;
+
+    u11_min = MaxReal;  u11_max = MinReal;  u11_m = 0.0;  u11_m2 = 0.0;
+    u22_min = MaxReal;  u22_max = MinReal;  u22_m = 0.0;  u22_m2 = 0.0;
+    u33_min = MaxReal;  u33_max = MinReal;  u33_m = 0.0;  u33_m2 = 0.0;
+    u12_min = MaxReal;  u12_max = MinReal;  u12_m = 0.0;  u12_m2 = 0.0;
+    u13_min = MaxReal;  u13_max = MinReal;  u13_m = 0.0;  u13_m2 = 0.0;
+    u23_min = MaxReal;  u23_max = MinReal;  u23_m = 0.0;  u23_m2 = 0.0;
+
+    WhatIsSet = ASET_All;
+
+    finished = false;
+
+  }
+
+  void  AtomStat::Finish()  {
+  realtype v;
+
+    if (!finished)  {
+
+      finished = true;
+
+      if (nAtoms>0)  {
+
+        v      = nAtoms;
+
+        xm    /= v;    xm2    /= v;
+        ym    /= v;    ym2    /= v;
+        zm    /= v;    zm2    /= v;
+
+        occ_m /= v;    occ_m2 /= v;
+        tFm   /= v;    tFm2   /= v;
+
+        u11_m /= v;    u11_m2 /= v;
+        u22_m /= v;    u22_m2 /= v;
+        u33_m /= v;    u33_m2 /= v;
+        u12_m /= v;    u12_m2 /= v;
+        u13_m /= v;    u13_m2 /= v;
+        u23_m /= v;    u23_m2 /= v;
+      }
+    }
+
+  }
+
+  realtype  AtomStat::GetMaxSize()  {
+  realtype  r;
+    r = RMax(xmax-xmin,ymax-ymin);
+    r = RMax(r,zmax-zmin);
+    return RMax(r,0.0);
+  }
+
+
+  // ----------------------------------------------------------------
+
+
+  Residue::Residue() : UDData()  {
+    InitResidue();
+  }
+
+  Residue::Residue ( PChain Chain_Owner ) : UDData()  {
+    InitResidue();
+    if (Chain_Owner)
+      Chain_Owner->AddResidue ( this );
+  }
+
+  Residue::Residue ( PChain       Chain_Owner,
+                       const ResName resName,
+                       int           sqNum,
+                       const InsCode ins ) : UDData()  {
+    InitResidue();
+    seqNum = sqNum;
+    strcpy_css ( name,pstr(resName) );
+    strcpy_css ( insCode,pstr(ins) );
+    if (Chain_Owner)
+      Chain_Owner->AddResidue ( this );
+  }
+
+  Residue::Residue ( io::RPStream Object ) : UDData(Object)  {
+    InitResidue();
+  }
+
+  Residue::~Residue()  {
+    FreeMemory();
+    if (chain)  chain->_ExcludeResidue ( name,seqNum,insCode );
+  }
+
+
+  void  Residue::InitResidue()  {
+    strcpy ( name         ,"---"  );  // residue name
+    strcpy ( label_comp_id,"---"  );  // assigned residue name
+    label_asym_id[0] = char(0);       // assigned chain Id
+    seqNum           = -MaxInt;       // residue sequence number
+    label_seq_id     = -MaxInt;       // assigned residue sequence number
+    label_entity_id  = 1;             // assigned entity id
+    strcpy ( insCode,"" );            // residue insertion code
+    chain   = NULL;                   // reference to chain
+    index   = -1;                     // undefined index in chain
+    nAtoms  = 0;                      // number of atoms in the residue
+    AtmLen  = 0;                      // length of atom array
+    atom    = NULL;                   // array of atoms
+    Exclude = true;
+    SSE     = SSE_None;
+  }
+
+  void  Residue::SetChain ( PChain Chain_Owner )  {
+    chain = Chain_Owner;
+  }
+
+
+  int  Residue::GetResidueNo()  {
+    if (chain)  return  chain->GetResidueNo ( seqNum,insCode );
+          else  return  -1;
+  }
+
+  void Residue::SetChainID ( const ChainID chID )  {
+    if (chain)
+      chain->SetChainID ( chID );
+  }
+
+
+  int  Residue::GetCenter ( realtype & x, realtype & y,
+                             realtype & z )  {
+  int i,k;
+    x = 0.0;
+    y = 0.0;
+    z = 0.0;
+    k = 0;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (!atom[i]->Ter)  {
+          x += atom[i]->x;
+          y += atom[i]->y;
+          z += atom[i]->z;
+          k++;
+        }
+      }
+    if (k>0)  {
+      x /= k;
+      y /= k;
+      z /= k;
+      return 0;
+    }
+    return 1;
+  }
+
+  void * Residue::GetCoordHierarchy()  {
+    if (chain)  return chain->GetCoordHierarchy();
+    return NULL;
+  }
+
+  void  Residue::GetAltLocations ( int     & nAltLocs,
+                                    PAltLoc & aLoc,
+                                    rvector & occupancy,
+                                    int     & alflag )  {
+  int      i,j,k, nal,nal1;
+  realtype occ1;
+  bool  B;
+  PAltLoc  aL;
+  rvector  occ;
+  bvector  alv;
+
+    aLoc      = NULL;
+    occupancy = NULL;
+    nAltLocs  = 0;
+    alflag    = ALF_NoAltCodes;
+
+    if (nAtoms>0)  {
+
+      // temporary array for altcodes
+      aL = new AltLoc[nAtoms];
+      // temporary array for occupancies
+      GetVectorMemory ( occ,nAtoms,0 );
+      // temporary array for checking altcodes
+      GetVectorMemory ( alv,nAtoms,0 );
+      for (i=0;i<nAtoms;i++)
+        alv[i] = false;
+
+      k   = 0;  // counts unique alternation codes
+      nal = 0;
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)  {
+            // Find if the alternation code of ith atom is
+            // a new one.
+            B = false;
+            for (j=0;(j<k) && (!B);j++)
+              B = !strcmp(atom[i]->altLoc,aL[j]);
+            if (!B)  {
+              // that's a new altcode, get its occupancy
+              if (atom[i]->WhatIsSet & ASET_Occupancy)
+                   occ[k] = atom[i]->occupancy;
+              else occ[k] = -1.0;
+              // store new altcode in temporary array
+              strcpy ( aL[k],atom[i]->altLoc );
+              // check consistency of the altcode data if:
+              //   a) the data was not found wrong so far
+              //   b) this atom name has not been checked before
+              //   c) altcode is not the "empty"-altcode
+              if ((!(alflag & ALF_Mess)) && (!alv[i]) &&
+                  (atom[i]->altLoc[0]))  {
+                B    = false; // will be set true if "empty"-altcode
+                              // is found for current atom name
+                nal1 = 0;     // counts the number of different altcodes
+                              // for current atom name
+                occ1 = 0.0;   // will count the sum of occupancies for
+                              // current atom name
+                for (j=0;j<nAtoms;j++)
+                  if (atom[j])  {
+                    if ((!atom[j]->Ter) &&
+                        (!strcmp(atom[j]->name,atom[i]->name)))  {
+                      if (atom[j]->WhatIsSet & ASET_Occupancy)
+                        occ1 += atom[j]->occupancy;
+                      if (!atom[j]->altLoc[0])  B = true;
+                      alv[j] = true;  // mark it as "checked"
+                      nal1++;
+                    }
+                  }
+                if (!(alflag & (ALF_EmptyAltLoc | ALF_NoEmptyAltLoc)))  {
+                  if (B)  alflag |= ALF_EmptyAltLoc;
+                    else  alflag |= ALF_NoEmptyAltLoc;
+                } else if (((alflag & ALF_EmptyAltLoc) && (!B)) ||
+                           ((alflag & ALF_NoEmptyAltLoc) && (B)))
+                  alflag |= ALF_Mess;
+                if ((occ[k]>=0) && (fabs(1.0-occ1)>0.01))
+                  alflag |= ALF_Occupancy;
+                if (nal==0)    // first time just remember the number
+                  nal = nal1;  // of different altcodes
+                else if (nal!=nal1)   // check if number of different altcodes
+                  alflag |= ALF_Mess; // is not the same through the residue
+              }
+              k++;
+            }
+          }
+        }
+      if (k>0)  {
+        aLoc = new AltLoc[k];
+        GetVectorMemory ( occupancy,k,0 );
+        for (i=0;i<k;i++) {
+          strcpy ( aLoc[i],aL[i] );
+          occupancy[i] = occ[i];
+        }
+        nAltLocs = k;
+      }
+
+      delete[] aL;
+      FreeVectorMemory ( occ,0 );
+      FreeVectorMemory ( alv,0 );
+
+    }
+
+  }
+
+  int Residue::GetNofAltLocations() {
+  int     i,j,k;
+  bool B;
+    k = 0;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (!atom[i]->Ter)  {
+          B = false;
+          for (j=0;(j<i) && (!B);j++)
+            if (atom[j])  {
+              if (!atom[j]->Ter)
+                B = !strcmp(atom[i]->altLoc,atom[j]->altLoc);
+            }
+          if (!B)  k++;
+        }
+      }
+    return k;
+  }
+
+  void  Residue::SetResID ( const ResName resName, int sqNum,
+                             const InsCode ins )  {
+    strcpy_css ( name,pstr(resName) );
+    seqNum = sqNum;
+    strcpy_css ( insCode,pstr(ins) );
+    strcpy (label_comp_id,name );
+  }
+
+  void  Residue::FreeMemory()  {
+  //   NOTE: individual atoms are disposed here as well!
+    DeleteAllAtoms();
+    if (atom)  delete[] atom;
+    atom   = NULL;
+    nAtoms = 0;
+    AtmLen = 0;
+  }
+
+  void Residue::ExpandAtomArray ( int nAdd )  {
+  int     i;
+  PPAtom atom1;
+    AtmLen += abs(nAdd);
+    atom1   = new PAtom[AtmLen];
+    for (i=0;i<nAtoms;i++)
+      atom1[i] = atom[i];
+    for (i=nAtoms;i<AtmLen;i++)
+      atom1[i] = NULL;
+    if (atom)  delete[] atom;
+    atom = atom1;
+  }
+
+  int  Residue::_AddAtom ( PAtom atm )  {
+  // Adds atom to the residue
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i]==atm)  return -i;  // this atom is already there
+    if (nAtoms>=AtmLen)
+      ExpandAtomArray ( nAtoms+10-AtmLen );
+    atom[nAtoms] = atm;
+    atom[nAtoms]->residue = this;
+    nAtoms++;
+    return 0;
+  }
+
+  int  Residue::AddAtom ( PAtom atm )  {
+  //   AddAtom(..) adds atom to the residue. If residue is associated
+  // with a coordinate hierarchy, and atom 'atm' is not, the latter
+  // is checked in automatically. If atom 'atm' belongs to any
+  // coordinate hierarchy (even though that of the residue), it is
+  // *copied* rather than simply taken over, and is checked in.
+  //   If residue is not associated with a coordinate hierarchy, all
+  // added atoms will be checked in automatically once the residue
+  // is checked in.
+  PRoot manager;
+  PResidue  res;
+  int        i;
+
+    for (i=0;i<nAtoms;i++)
+      if (atom[i]==atm)  return -i;  // this atom is already there
+
+    if (nAtoms>=AtmLen)
+      ExpandAtomArray ( nAtoms+10-AtmLen );
+
+    if (atm->GetCoordHierarchy()) {
+      atom[nAtoms] = newAtom();
+      atom[nAtoms]->Copy ( atm );
+    } else  {
+      res = atm->GetResidue();
+      if (res)
+        for (i=0;i<res->nAtoms;i++)
+          if (res->atom[i]==atm)  {
+            res->atom[i] = NULL;
+            break;
+          }
+      atom[nAtoms] = atm;
+    }
+
+    atom[nAtoms]->residue = this;
+    manager = PRoot(GetCoordHierarchy());
+    if (manager)
+      manager->CheckInAtom ( 0,atom[nAtoms] );
+
+    nAtoms++;
+
+    return nAtoms;
+
+  }
+
+  int  Residue::InsertAtom ( PAtom atm, int position )  {
+  //   InsertAtom(..) inserts atom into the specified position of
+  // the residue. If residue is associated with a coordinate hierarchy,
+  // and atom 'atm' is not, the latter is checked in automatically.
+  // If atom 'atm' belongs to any coordinate hierarchy (even though
+  // that of the residue), it is *copied* rather than simply taken
+  // over, and is checked in.
+  //   If residue is not associated with a coordinate hierarchy, all
+  // added atoms will be checked in automatically once the residue
+  // is checked in.
+  PRoot manager;
+  PResidue  res;
+  int        i,pos;
+
+    for (i=0;i<nAtoms;i++)
+      if (atom[i]==atm)  return -i;  // this atom is already there
+
+    if (nAtoms>=AtmLen)
+      ExpandAtomArray ( nAtoms+10-AtmLen );
+
+    pos = IMin(position,nAtoms);
+    for (i=nAtoms;i>pos;i--)
+      atom[i] = atom[i-1];
+
+    if (atm->GetCoordHierarchy()) {
+      atom[pos] = newAtom();
+      atom[pos]->Copy ( atm );
+    } else  {
+      res = atm->GetResidue();
+      if (res)
+        for (i=0;i<res->nAtoms;i++)
+          if (res->atom[i]==atm)  {
+            res->atom[i] = NULL;
+            break;
+          }
+      atom[pos] = atm;
+    }
+
+    atom[pos]->residue = this;
+    manager = PRoot(GetCoordHierarchy());
+    if (manager)
+      manager->CheckInAtom ( 0,atom[pos] );
+
+    nAtoms++;
+
+    return nAtoms;
+
+  }
+
+  int  Residue::InsertAtom ( PAtom atm, const AtomName aname )  {
+  //   This version inserts before the atom with given name. If such
+  // name is not found, the atom is appended to the end.
+  int i;
+    i = 0;
+    while (i<nAtoms)
+      if (!atom[i])  i++;
+      else if (!strcmp(aname,atom[i]->name))  break;
+      else i++;
+    return InsertAtom ( atm,i );
+  }
+
+
+  void  Residue::CheckInAtoms()  {
+  PRoot manager;
+  int        i;
+    manager = PRoot(GetCoordHierarchy());
+    if (manager)
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (atom[i]->index<0)
+            manager->CheckInAtom ( 0,atom[i] );
+        }
+  }
+
+
+  int  Residue::_ExcludeAtom ( int kndex )  {
+  //  deletes atom from the residue
+  int  i,k;
+
+    if (!Exclude)  return 0;
+
+    k = -1;
+    for (i=0;(i<nAtoms) && (k<0);i++)
+      if (atom[i])  {
+        if (atom[i]->index==kndex)  k = i;
+      }
+
+    if (k>=0)  {
+      for (i=k+1;i<nAtoms;i++)
+        atom[i-1] = atom[i];
+      nAtoms--;
+    }
+
+    if (nAtoms<=0)  return 1;
+              else  return 0;
+
+  }
+
+
+  void  Residue::PDBASCIIAtomDump ( io::RFile f )  {
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])
+        atom[i]->PDBASCIIDump ( f );
+  }
+
+  void  Residue::MakeAtomCIF ( mmcif::PData CIF )  {
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])
+        atom[i]->MakeCIF ( CIF );
+  }
+
+
+  void  Residue::Copy ( PResidue res )  {
+  //
+  //  Modify Residue::Copy and both Residues::_copy methods
+  //  simultaneously!
+  //
+  //  This function will nake a copy of residue res in 'this' one.
+  //  All atoms are copied, none is moved regardless to the association
+  //  with coordinate hierarchy. If 'this' residue is associated with
+  //  a coordinate hierarchy, all atoms are checked in.
+  PRoot manager;
+  int        i;
+
+    FreeMemory();
+
+    seqNum          = res->seqNum;
+    label_seq_id    = res->label_seq_id;
+    label_entity_id = res->label_entity_id;
+    index           = res->index;
+    AtmLen          = res->nAtoms;
+    SSE             = res->SSE;
+    strcpy ( name         ,res->name          );
+    strcpy ( label_comp_id,res->label_comp_id );
+    strcpy ( label_asym_id,res->label_asym_id );
+    strcpy ( insCode      ,res->insCode       );
+
+    if (AtmLen>0)  {
+      atom   = new PAtom[AtmLen];
+      nAtoms = 0;
+      for (i=0;i<res->nAtoms;i++)
+        if (res->atom[i])  {
+          atom[nAtoms] = newAtom();
+          atom[nAtoms]->Copy ( res->atom[i] );
+          atom[nAtoms]->SetResidue ( this );
+          nAtoms++;
+        }
+      for (i=nAtoms;i<AtmLen;i++)
+        atom[i] = NULL;
+      manager = PRoot(GetCoordHierarchy());
+      if (manager)
+        manager->CheckInAtoms ( 0,atom,nAtoms );
+    }
+
+  }
+
+
+  void  Residue::_copy ( PResidue res )  {
+  //  Modify both Residue::_copy and Residue::Copy methods
+  //  simultaneously!
+  //
+  //  will work properly only if atomic arrays
+  //  this->chain->model->GetAtom() and
+  //  res->chain->model->GetAtom() are identical
+  //
+  int     i;
+  PPAtom A;
+
+    FreeMemory();
+
+    seqNum          = res->seqNum;
+    label_seq_id    = res->label_seq_id;
+    label_entity_id = res->label_entity_id;
+    index           = res->index;
+    nAtoms          = res->nAtoms;
+    SSE             = res->SSE;
+    strcpy ( name         ,res->name          );
+    strcpy ( label_comp_id,res->label_comp_id );
+    strcpy ( label_asym_id,res->label_asym_id );
+    strcpy ( insCode      ,res->insCode       );
+
+    AtmLen = nAtoms;
+    A      = NULL;
+    if (chain)  {
+      if (chain->model)
+        A = chain->model->GetAllAtoms();
+    }
+    if ((nAtoms>0) && (A))  {
+      atom = new PAtom[nAtoms];
+      for (i=0;i<nAtoms;i++)  {
+        atom[i] = A[res->atom[i]->index-1];
+        atom[i]->SetResidue ( this );
+      }
+    } else  {
+      nAtoms = 0;
+      AtmLen = 0;
+    }
+
+  }
+
+  void  Residue::_copy ( PResidue res, PPAtom atm,
+                          int & atom_index )  {
+  //  modify both Residue::_copy and Residue::Copy methods
+  // simultaneously!
+  //
+  //  This function physically copies the atoms, creating new atom
+  // instances and putting them into array 'atm' sequentially from
+  // 'atom_index' position. 'atom_index' is modified (advanced).
+  //
+  int i;
+
+    FreeMemory();
+
+    seqNum          = res->seqNum;
+    label_seq_id    = res->label_seq_id;
+    label_entity_id = res->label_entity_id;
+    index           = res->index;
+    nAtoms          = res->nAtoms;
+    SSE             = res->SSE;
+    strcpy ( name         ,res->name          );
+    strcpy ( label_comp_id,res->label_comp_id );
+    strcpy ( label_asym_id,res->label_asym_id );
+    strcpy ( insCode      ,res->insCode       );
+
+    AtmLen = nAtoms;
+    if (AtmLen>0)  {
+      atom = new PAtom[AtmLen];
+      for (i=0;i<nAtoms;i++)
+        if (res->atom[i])  {
+          if (!atm[atom_index])  atm[atom_index] = newAtom();
+          atm[atom_index]->Copy ( res->atom[i] );
+          atm[atom_index]->residue = this;
+          atm[atom_index]->index = atom_index+1;
+          atom[i] = atm[atom_index];
+          atom_index++;
+        } else
+          atom[i] = NULL;
+    }
+
+  }
+
+
+  void  Residue::GetAtomStatistics ( RAtomStat AS )  {
+    AS.Init();
+    CalAtomStatistics ( AS );
+    AS.Finish();
+  }
+
+  void  Residue::CalAtomStatistics ( RAtomStat AS )  {
+  //   AS must be initialized. The function only accumulates
+  // the statistics.
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])
+        atom[i]->CalAtomStatistics ( AS );
+  }
+
+
+  PChain  Residue::GetChain()  {
+    return chain;
+  }
+
+  PModel  Residue::GetModel()  {
+    if (chain) return (PModel)chain->model;
+          else return NULL;
+  }
+
+
+  int Residue::GetModelNum()  {
+    if (chain)  {
+      if (chain->model)
+        return chain->model->GetSerNum();
+    }
+    return 0;
+  }
+
+  pstr Residue::GetChainID()  {
+    if (chain)  return chain->chainID;
+    return  pstr("");
+  }
+
+  pstr Residue::GetLabelAsymID()  {
+    return label_asym_id;
+  }
+
+  pstr  Residue::GetResName()  {
+    return name;
+  }
+
+  pstr  Residue::GetLabelCompID()  {
+    return label_comp_id;
+  }
+
+  int   Residue::GetAASimilarity ( const ResName resName )  {
+    return  mmdb::GetAASimilarity ( pstr(name),pstr(resName) );
+  }
+
+  int   Residue::GetAASimilarity ( PResidue res )  {
+    return  mmdb::GetAASimilarity ( name,res->name );
+  }
+
+  realtype Residue::GetAAHydropathy()  {
+    return  mmdb::GetAAHydropathy ( name );
+  }
+
+  void  Residue::SetResName ( const ResName resName )  {
+    strcpy ( name,resName );
+  }
+
+  int   Residue::GetSeqNum()  {
+    return seqNum;
+  }
+
+  int   Residue::GetLabelSeqID()  {
+    return label_seq_id;
+  }
+
+  int   Residue::GetLabelEntityID()  {
+    return label_entity_id;
+  }
+
+  pstr  Residue::GetInsCode()  {
+    return insCode;
+  }
+
+  bool Residue::isAminoacid ()  {
+    return mmdb::isAminoacid ( name );
+  }
+
+  bool Residue::isNucleotide()  {
+    return mmdb::isNucleotide ( name );
+  }
+
+  int Residue::isDNARNA()  {
+    return mmdb::isDNARNA ( name );
+  }
+
+  bool Residue::isSugar()  {
+    return mmdb::isSugar ( name );
+  }
+
+  bool Residue::isSolvent()  {
+    return mmdb::isSolvent ( name );
+  }
+
+  bool Residue::isModRes()  {
+  PChain  chn;
+  PModRes modRes;
+  int     nModRes,i;
+    chn = GetChain();
+    if (chn)  {
+      nModRes = chn->GetNofModResidues();
+      for (i=0;i<nModRes;i++)  {
+        modRes = chn->GetModResidue ( i );
+        if (modRes)  {
+          if ((!strcmp(modRes->resName,name)) &&
+              (modRes->seqNum==seqNum)     &&
+              (!strcmp(modRes->insCode,insCode)))
+            return true;
+        }
+      }
+
+    }
+    return false;
+  }
+
+  bool Residue::isInSelection ( int selHnd )  {
+  PRoot  manager = (PRoot)GetCoordHierarchy();
+  PMask  mask;
+    if (manager)  {
+      mask = manager->GetSelMask ( selHnd );
+      if (mask)  return CheckMask ( mask );
+    }
+    return false;
+  }
+
+
+  bool Residue::isNTerminus()  {
+  PPResidue Res;
+  int       i,j,nRes;
+    if (chain)  {
+      chain->GetResidueTable ( Res,nRes );
+      i = 0;
+      j = -1;
+      while ((i<nRes) && (j<0))  {
+        if (Res[i])  j = i;
+        i++;
+      }
+      if (j>=0)
+        return (Res[j]->index==index);
+    }
+    return false;
+  }
+
+  bool Residue::isCTerminus()  {
+  PPResidue Res;
+  int       i,j,nRes;
+    if (chain)  {
+      chain->GetResidueTable ( Res,nRes );
+      i = nRes-1;
+      j = -1;
+      while ((i>=0) && (j<0))  {
+        if (Res[i])  j = i;
+        i--;
+      }
+      if (j>=0)
+        return (Res[j]->index==index);
+    }
+    return false;
+  }
+
+
+  pstr  Residue::GetResidueID ( pstr ResidueID )  {
+    ResidueID[0] = char(0);
+    if (chain)  {
+      if (chain->model)
+            sprintf ( ResidueID,"/%i/",chain->model->GetSerNum() );
+      else  strcpy  ( ResidueID,"/-/" );
+      strcat ( ResidueID,chain->chainID );
+    } else
+      strcpy ( ResidueID,"/-/-" );
+    ParamStr ( ResidueID,pstr("/"),seqNum );
+    strcat ( ResidueID,"(" );
+    strcat ( ResidueID,name );
+    strcat ( ResidueID,")" );
+    if (insCode[0])  {
+      strcat ( ResidueID,"." );
+      strcat ( ResidueID,insCode );
+    }
+    return ResidueID;
+  }
+
+
+  int Residue::CheckID ( int * snum,
+                          const InsCode inscode,
+                          const ResName resname )  {
+    if (snum)  {
+      if (*snum!=seqNum)  return 0;
+    }
+    if (inscode)  {
+      if ((inscode[0]!='*') && (strcmp(inscode,insCode)))  return 0;
+    }
+    if (!resname)        return 1;
+    if ((resname[0]!='*') && (strcmp(resname,name))) return 0;
+    return 1;
+  }
+
+  int Residue::CheckIDS ( cpstr CID )  {
+  ChainID  chn;
+  InsCode  inscode;
+  ResName  resname;
+  AtomName atm;
+  Element  elm;
+  AltLoc   aloc;
+  pstr     p1,p2;
+  int      mdl,sn,rc;
+
+    rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
+                         atm,elm,aloc,NULL );
+   //  rc = ParseResID ( CID,sn,inscode,resname );
+
+    if (rc>=0)  {
+      p1 = NULL;
+      p2 = NULL;
+      if (inscode[0]!='*')  p1 = inscode;
+      if (resname[0]!='*')  p2 = resname;
+      if (!rc)  return  CheckID ( &sn ,p1,p2 );
+          else  return  CheckID ( NULL,p1,p2 );
+    }
+    return 0;
+
+  }
+
+
+  //  --------------------  Extracting atoms  -------------------------
+
+  int  Residue::GetNumberOfAtoms()  {
+    return nAtoms;
+  }
+
+  int  Residue::GetNumberOfAtoms ( bool countTers )  {
+  int i,na;
+    na = 0;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (countTers || (!atom[i]->Ter))  na++;
+      }
+    return na;
+  }
+
+  PAtom Residue::GetAtom ( const AtomName aname,
+                             const Element  elname,
+                             const AltLoc   aloc )  {
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (atom[i]->CheckID(aname,elname,aloc))
+          return atom[i];
+      }
+    return NULL;
+  }
+
+  PAtom Residue::GetAtom ( int atomNo )  {
+    if ((0<=atomNo) && (atomNo<nAtoms))
+      return atom[atomNo];
+    return NULL;
+  }
+
+  void Residue::GetAtomTable ( PPAtom & atomTable, int & NumberOfAtoms )  {
+    atomTable     = atom;
+    NumberOfAtoms = nAtoms;
+  }
+
+  void Residue::GetAtomTable1 ( PPAtom & atomTable, int & NumberOfAtoms )  {
+  int i,j;
+    if (atomTable)  delete[] atomTable;
+    if (nAtoms>0)  {
+      atomTable = new PAtom[nAtoms];
+      j = 0;
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)
+            atomTable[j++] = atom[i];
+        }
+      NumberOfAtoms = j;
+    } else  {
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void Residue::TrimAtomTable()  {
+  int i,j;
+    j = 0;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (j<i)  {
+          atom[j] = atom[i];
+          atom[i] = NULL;
+        }
+        j++;
+      }
+    nAtoms = j;
+  }
+
+
+  //  ---------------------  Deleting atoms  --------------------------
+
+  int Residue::DeleteAtom ( const AtomName aname,
+                             const Element  elname,
+                             const AltLoc   aloc )  {
+  // apply Root::FinishStructEdit() after all editings are done!
+  // returns number of deleted atoms
+  int     i,k,nA,kndex;
+  PPAtom A;
+
+    A  = NULL;
+    nA = 0;
+    if (chain)  {
+      if (chain->model)  {
+        A  = chain->model->GetAllAtoms();
+        nA = chain->model->GetNumberOfAllAtoms();
+      }
+    }
+
+    k = 0;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (atom[i]->CheckID(aname,elname,aloc))  {
+          k++;
+          kndex = atom[i]->index;
+          if ((0<kndex) && (kndex<=nA))   A[kndex-1] = NULL;
+          Exclude = false;
+          delete atom[i];
+          atom[i] = NULL;
+          Exclude = true;
+        }
+      }
+
+    return k;
+
+  }
+
+  int Residue::DeleteAtom ( int atomNo )  {
+  // apply Root::FinishStructEdit() after all editings are done!
+  // returns number of deleted atoms
+  int     kndex,nA;
+  PPAtom A;
+
+    if ((0<=atomNo) && (atomNo<nAtoms))  {
+      if (atom[atomNo])  {
+        A  = NULL;
+        nA = 0;
+        if (chain)  {
+          if (chain->model)  {
+            A  = chain->model->GetAllAtoms();
+            nA = chain->model->GetNumberOfAllAtoms();
+          }
+        }
+        kndex = atom[atomNo]->index;
+        if ((0<kndex) && (kndex<=nA))   A[kndex-1] = NULL;
+        Exclude = false;
+        delete atom[atomNo];
+        atom[atomNo] = NULL;
+        Exclude = true;
+        return 1;
+      }
+    }
+
+    return 0;
+
+  }
+
+
+  int  Residue::DeleteAllAtoms()  {
+  int     i,k,nA,kndex;
+  PPAtom A;
+
+    Exclude = false;
+
+    A  = NULL;
+    nA = 0;
+    if (chain)  {
+      if (chain->model)  {
+        A  = chain->model->GetAllAtoms();
+        nA = chain->model->GetNumberOfAllAtoms();
+      }
+    }
+
+    k = 0;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        k++;
+        kndex = atom[i]->index;
+        if ((0<kndex) && (kndex<=nA))  A[kndex-1] = NULL;
+        delete atom[i];
+        atom[i] = NULL;
+      }
+    nAtoms  = 0;
+
+    Exclude = true;
+
+    return k;
+
+  }
+
+
+  int Residue::DeleteAltLocs()  {
+  //   This function leaves only alternative location with maximal
+  // occupancy, if those are equal or unspecified, the one with
+  // "least" alternative location indicator.
+  //   The function returns the number of deleted atoms. The atom
+  // table remains untrimmed, so that nAtoms are wrong until that
+  // is done. Tables are trimmed by FinishStructEdit() or
+  // explicitely.
+  PPAtom  A;
+  AtomName aname;
+  AltLoc   aLoc,aL;
+  realtype occupancy,occ;
+  int      nA,i,i1,i2,j,k,n,kndex;
+
+    A  = NULL;
+    nA = 0;
+    if (chain)  {
+      if (chain->model)  {
+        A  = chain->model->GetAllAtoms();
+        nA = chain->model->GetNumberOfAllAtoms();
+      }
+    }
+    Exclude = false;
+
+    n = 0;
+    for (i=0;i<nAtoms;i++)
+
+      if (atom[i])  {
+        if (!atom[i]->Ter)  {
+          occupancy = atom[i]->GetOccupancy();
+          strcpy ( aname,atom[i]->name );
+          strcpy ( aLoc ,atom[i]->altLoc );
+          i1 = -1;
+          i2 = i;
+          k  = 0;
+          for (j=i+1;j<nAtoms;j++)
+            if (atom[j])  {
+              if ((!atom[j]->Ter) && (!strcmp(atom[j]->name,aname)))  {
+                k++;
+                occ = atom[j]->GetOccupancy();
+                if (occ>occupancy)  {
+                  occupancy = occ;
+                  i1 = j;
+                }
+                if (aLoc[0])  {
+                  strcpy ( aL,atom[j]->altLoc );
+                  if (!aL[0])  {
+                    aLoc[0] = char(0);
+                    i2 = j;
+                  } else if (strcmp(aL,aLoc)<0)  {
+                    strcpy ( aLoc,aL );
+                    i2 = j;
+                  }
+                }
+              }
+            }
+          if (k>0)  {
+            if (i1<0)  {
+              if (atom[i]->WhatIsSet & ASET_Occupancy)  i1 = i;
+                                                  else  i1 = i2;
+            }
+            for (j=i;j<nAtoms;j++)
+              if ((j!=i1) && atom[j])  {
+                if ((!atom[j]->Ter) && (!strcmp(atom[j]->name,aname)))  {
+                  n++;
+                  kndex = atom[j]->index;
+                  if ((0<kndex) && (kndex<=nA))  A[kndex-1] = NULL;
+                  delete atom[j];
+                  atom[j] = NULL;
+                }
+              }
+          }
+        }
+      }
+
+    Exclude = true;
+
+    return n;
+
+  }
+
+  void  Residue::ApplyTransform ( mat44 & TMatrix )  {
+  // transforms all coordinates by multiplying with matrix TMatrix
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (!atom[i]->Ter)
+          atom[i]->Transform ( TMatrix );
+      }
+  }
+
+
+
+  //  -----------------------------------------------------------------
+
+
+  void  Residue::MaskAtoms ( PMask Mask )  {
+  int i;
+    for (i=0;i<nAtoms;i++)
+       if (atom[i])  atom[i]->SetMask ( Mask );
+  }
+
+  void  Residue::UnmaskAtoms ( PMask Mask )  {
+  int i;
+    for (i=0;i<nAtoms;i++)
+       if (atom[i])  atom[i]->RemoveMask ( Mask );
+  }
+
+
+
+  // -------  user-defined data handlers
+
+  int  Residue::PutUDData ( int UDDhandle, int iudd )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::putUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Residue::PutUDData ( int UDDhandle, realtype rudd )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::putUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Residue::PutUDData ( int UDDhandle, cpstr sudd )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::putUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Residue::GetUDData ( int UDDhandle, int & iudd )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::getUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Residue::GetUDData ( int UDDhandle, realtype & rudd )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::getUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Residue::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::getUDData ( UDDhandle,sudd,maxLen );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Residue::GetUDData ( int UDDhandle, pstr & sudd )  {
+    if (UDDhandle & UDRF_RESIDUE)
+          return  UDData::getUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+
+  #define  NOmaxdist2   12.25
+
+  bool Residue::isMainchainHBond ( PResidue res ) {
+  //  Test if there is main chain Hbond between PCRes1 (donor) and
+  //  PCRes2 (acceptor).
+  //  As defined Kabsch & Sanders
+  //  This probably needs the option of supporting alternative criteria
+  PAtom   NAtom,OAtom,Atom;
+  realtype abx,aby,abz;
+  realtype acx,acy,acz;
+  realtype bcx,bcy,bcz;
+  realtype absq,acsq,bcsq;
+
+    NAtom = GetAtom      ( "N" );
+    OAtom = res->GetAtom ( "O" );
+    Atom = res->GetAtom ( "C" );
+
+    if (NAtom && OAtom && Atom)  {
+
+      abx = OAtom->x - NAtom->x;
+      aby = OAtom->y - NAtom->y;
+      abz = OAtom->z - NAtom->z;
+      absq = abx*abx + aby*aby + abz*abz;
+
+
+      if (absq<=NOmaxdist2)  {
+
+        acx = NAtom->x - Atom->x;
+        acy = NAtom->y - Atom->y;
+        acz = NAtom->z - Atom->z;
+
+        bcx = Atom->x - OAtom->x;
+        bcy = Atom->y - OAtom->y;
+        bcz = Atom->z - OAtom->z;
+
+        acsq = acx*acx + acy*acy + acz*acz;
+        bcsq = bcx*bcx + bcy*bcy + bcz*bcz;
+
+        return (acos((bcsq+absq-acsq)/(2.0*sqrt(bcsq*absq)))>=Pi/2.0);
+
+      }
+
+    }
+
+    return  false;
+
+  }
+
+
+  void  Residue::write ( io::RFile f )  {
+  int  i;
+  byte Version=2;
+
+    UDData::write ( f );
+
+    f.WriteByte    ( &Version         );
+    f.WriteInt     ( &seqNum          );
+    f.WriteInt     ( &label_seq_id    );
+    f.WriteInt     ( &label_entity_id );
+    f.WriteInt     ( &index           );
+    f.WriteInt     ( &nAtoms          );
+    f.WriteByte    ( &SSE             );
+    f.WriteTerLine ( name         ,false );
+    f.WriteTerLine ( label_comp_id,false );
+    f.WriteTerLine ( label_asym_id,false );
+    f.WriteTerLine ( insCode      ,false );
+    for (i=0;i<nAtoms;i++)
+      f.WriteInt ( &(atom[i]->index) );
+
+  }
+
+  void  Residue::read ( io::RFile f ) {
+  //   IMPORTANT: array Atom in Root class should be
+  // read prior calling this function!
+  PPAtom A;
+  int     i,k;
+  byte    Version;
+
+    FreeMemory ();
+
+    UDData::read ( f );
+
+    f.ReadByte    ( &Version );
+    f.ReadInt     ( &seqNum  );
+    if (Version>1)  {
+      f.ReadInt ( &label_seq_id    );
+      f.ReadInt ( &label_entity_id );
+    }
+    f.ReadInt     ( &index   );
+    f.ReadInt     ( &nAtoms  );
+    f.ReadByte    ( &SSE     );
+    f.ReadTerLine ( name,false );
+    if (Version>1)  {
+      f.ReadTerLine ( label_comp_id,false );
+      f.ReadTerLine ( label_asym_id,false );
+    }
+    f.ReadTerLine ( insCode,false );
+    AtmLen = nAtoms;
+    A      = NULL;
+    if (chain) {
+      if (chain->model)
+        A = chain->model->GetAllAtoms();
+    }
+    if ((nAtoms>0) && (A))  {
+      atom = new PAtom[nAtoms];
+      for (i=0;i<nAtoms;i++)  {
+        f.ReadInt ( &k );
+        atom[i] = A[k-1];
+        atom[i]->SetResidue ( this );
+        atom[i]->_setBonds  ( A );
+      }
+    } else  {
+      for (i=0;i<nAtoms;i++)
+        f.ReadInt ( &k );
+      nAtoms = 0;
+      AtmLen = 0;
+    }
+  }
+
+
+  MakeFactoryFunctions(Residue)
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_atom.h b/mmdb2/mmdb_atom.h
new file mode 100644
index 0000000..63d5cb3
--- /dev/null
+++ b/mmdb2/mmdb_atom.h
@@ -0,0 +1,732 @@
+//  $Id: mmdb_atom.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Atom <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Atom     ( atom class    )
+//       ~~~~~~~~~  mmdb::Residue  ( residue class )
+//  **** Functions: mmdb::BondAngle
+//       ~~~~~~~~~~
+//
+//  Copyright (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Atom__
+#define __MMDB_Atom__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_uddata.h"
+#include "mmdb_utils.h"
+#include "mmdb_defs.h"
+
+
+namespace mmdb  {
+
+  //  ======================  Atom  ==========================
+
+  // constants for the WhatIsSet field
+  enum ASET_FLAG  {
+    ASET_Coordinates  = 0x00000001,
+    ASET_Occupancy    = 0x00000002,
+    ASET_tempFactor   = 0x00000004,
+    ASET_CoordSigma   = 0x00000010,
+    ASET_OccSigma     = 0x00000020,
+    ASET_tFacSigma    = 0x00000040,
+    ASET_Anis_tFac    = 0x00000100,
+    ASET_Anis_tFSigma = 0x00001000,
+    ASET_Charge       = 0x00000080,
+    ASET_All          = 0x000FFFFF
+  };
+
+  const int ATOM_NoSeqNum = MinInt4;
+
+  extern bool  ignoreSegID;
+  extern bool  ignoreElement;
+  extern bool  ignoreCharge;
+  extern bool  ignoreNonCoorPDBErrors;
+  extern bool  ignoreUnmatch;
+
+
+  DefineStructure(AtomStat);
+
+  struct AtomStat  {
+
+    public :
+      int       nAtoms;          // number of atoms in statistics
+
+      realtype  xmin,ymin,zmin;  // minimums of coordinates
+      realtype  xmax,ymax,zmax;  // maximums of coordinates
+      realtype  xm  ,ym  ,zm;    // mediums  of coordinates
+      realtype  xm2 ,ym2 ,zm2;   // square mediums of coordinates
+
+      realtype  occ_min,occ_max; // minimum/maximum occupancy
+      realtype  occ_m  ,occ_m2;  // medium and square medium occupancy
+
+      realtype  tFmin,tFmax;     // minimum/maximum temperature factor
+      realtype  tFm  ,tFm2;      // medium and sq. med. temp. factor
+
+      realtype  u11_min,u11_max; // minimums and
+      realtype  u22_min,u22_max; //   maximums of
+      realtype  u33_min,u33_max; //     anisotropic
+      realtype  u12_min,u12_max; //       temperature
+      realtype  u13_min,u13_max; //         factors
+      realtype  u23_min,u23_max;
+
+      realtype  u11_m,u11_m2;    // mediums and
+      realtype  u22_m,u22_m2;    //   square mediums of
+      realtype  u33_m,u33_m2;    //     anisotropic
+      realtype  u12_m,u12_m2;    //       temperature
+      realtype  u13_m,u13_m2;    //         factors
+      realtype  u23_m,u23_m2;
+
+      word      WhatIsSet;       //   mask field
+
+      void  Init  ();
+      void  Finish();
+
+      realtype GetMaxSize();
+
+    private :
+      bool finished;
+
+  };
+
+
+  DefineStructure(AtomBondI);
+
+  struct AtomBondI  {
+    int  index;  //!< bonded atom index
+    byte order;  //!< bond order
+  };
+
+
+  DefineStructure(AtomBond);
+
+  struct AtomBond  {
+    PAtom atom;  //!< bonded atom pointer
+    byte  order;  //!< bond order
+  };
+
+
+  DefineFactoryFunctions(Atom);
+
+  class Atom : public UDData  {
+
+    friend class Residue;
+    friend class Model;
+    friend class Root;
+    friend class CoorManager;
+    friend class SelManager;
+
+    public :
+      int        serNum;         //!< serial number
+      AtomName   name;           //!< atom name (ALIGNED)
+      AtomName   label_atom_id;  //!< assigned atom name (not aligned)
+      AltLoc     altLoc; //!< alternative location indicator ("" for none)
+      SegID      segID;          //!< segment identifier
+      Element    element;        //!< element symbol (ALIGNED TO RIGHT)
+      EnergyType energyType;     //!< energy type (without spaces)
+      PResidue   residue;        //!< reference to residue
+      realtype   x,y,z;          //!< orthogonal coordinates in angstroms
+      realtype   occupancy;      //!< occupancy
+      realtype   tempFactor;     //!< temperature factor
+      realtype   charge;         //!< charge on the atom
+      realtype   sigX,sigY,sigZ; //!< standard deviations of the coords
+      realtype   sigOcc;         //!< standard deviation of occupancy
+      realtype   sigTemp;        //!< standard deviation of temp. factor
+      realtype   u11,u22,u33;    //!< anisotropic temperature
+      realtype   u12,u13,u23;    ///    factors
+      realtype   su11,su22,su33; //!< standard deviations of
+      realtype   su12,su13,su23; ///    anisotropic temperature factors
+      bool       Het;            //!< indicator of het atom
+      bool       Ter;            //!< chain terminator
+
+      word       WhatIsSet;      //!<   mask      field
+                         ///  0x0001   atomic coordinates
+                         ///  0x0002   occupancy
+                         ///  0x0004   temperature factor
+                         ///  0x0010   coordinate standard deviations
+                         ///  0x0020   deviation of occupancy
+                         ///  0x0040   deviation of temperature factor
+                         ///  0x0100   anisotropic temperature factors
+                         ///  0x1000   anis. temp. fact-s st-d deviations
+
+      Atom ();
+      Atom ( PResidue     res    );
+      Atom ( io::RPStream Object );
+      ~Atom();
+
+      void  SetResidue   ( PResidue     res );
+      void  PDBASCIIDump ( io::RFile    f   );
+      void  MakeCIF      ( mmcif::PData CIF );
+
+      //    AddBond(...) adds a bond to the atom, that is a pointer
+      //  to the bonded atom and the bond order. nAdd_bonds allows
+      //  one to minimize the memory reallocations, if number of
+      //  bonds is known apriori: Atom adds space for nAdd_bonds
+      //  if currently allocated space is exchausted.
+      //    Return:  <=0  - error: bond_atom is already "bonded"
+      //              >0  - Ok, returns current number of bonds
+      int   AddBond  ( PAtom bond_atom, int bond_order,
+                                        int nAdd_bonds=1 );
+      int   GetNBonds();
+
+      //    This GetBonds(..) returns pointer to the Atom's
+      //  internal Bond structure, IT MUST NOT BE DISPOSED.
+      void  GetBonds ( RPAtomBond atomBond, int & nAtomBonds );
+      void  FreeBonds();
+
+      //    This GetBonds(..) disposes AtomBondI, if it was not set
+      //  to NULL, allocates AtomBondI[nAtomBonds] and returns its
+      //  pointer. AtomBondI MUST BE DISPOSED BY APPLICATION.
+      void  GetBonds ( RPAtomBondI atomBondI, int & nAtomBonds );
+
+      //    This GetBonds(..) does not dispose or allocate AtomBondI.
+      //  It is assumed that length of AtomBondI is sufficient to
+      //  accomodate all bonded atoms.
+      void  GetBonds ( PAtomBondI atomBondI, int & nAtomBonds,
+                       int maxlength );
+
+
+      //   ConvertPDBxxxxxx() gets data from the PDB ASCII xxxxxx
+      // record (xxxxxx stands for ATOM, SIGATM, ANISOU, SIGUIJ,
+      // TER or HETATM).
+      //   These functions DO NOT check the xxxxxx keyword and
+      // do not decode the chain and residue parameters! These
+      // must be treated by the calling process, see
+      // CMMDBFile::ReadPDBAtom().
+      //   The atom reference is updated in the corresponding
+      // residue.
+      ERROR_CODE ConvertPDBATOM   ( int ix, cpstr S );
+      ERROR_CODE ConvertPDBSIGATM ( int ix, cpstr S );
+      ERROR_CODE ConvertPDBANISOU ( int ix, cpstr S );
+      ERROR_CODE ConvertPDBSIGUIJ ( int ix, cpstr S );
+      ERROR_CODE ConvertPDBTER    ( int ix, cpstr S );
+      ERROR_CODE ConvertPDBHETATM ( int ix, cpstr S );
+
+      ERROR_CODE GetCIF           ( int ix, mmcif::PLoop Loop,
+                                     mmcif::PLoop LoopAnis );
+
+      bool RestoreElementName();
+      bool MakePDBAtomName();
+
+      void  SetAtomName    ( int            ix,      // index
+                             int            sN,      // serial number
+                             const AtomName aName,   // atom name
+                             const AltLoc   aLoc, // alternative location
+                             const SegID    sID,     // segment ID
+                             const Element  eName ); // element name
+
+      //  This only renames the atom
+      void  SetAtomName    ( const AtomName atomName );
+      void  SetElementName ( const Element  elName   );
+      void  SetCharge      ( cpstr          chrg     );
+      void  SetCharge      ( realtype       chrg     );
+
+      void  SetAtomIndex   ( int ix ); // don't use in your applications!
+
+      void  MakeTer();  // converts atom into 'ter'
+
+      void  SetCoordinates ( realtype xx,  realtype yy, realtype zz,
+                             realtype occ, realtype tFac );
+
+      int   GetModelNum       ();
+      pstr  GetChainID        ();
+      pstr  GetLabelAsymID    ();
+      pstr  GetResName        ();
+      pstr  GetLabelCompID    ();
+      int   GetAASimilarity   ( const ResName resName );
+      int   GetAASimilarity   ( PAtom  A );
+      realtype GetAAHydropathy();
+      realtype GetOccupancy   ();
+      int   GetSeqNum         ();
+      int   GetLabelSeqID     ();
+      int   GetLabelEntityID  ();
+      pstr  GetInsCode        ();
+      int   GetSSEType        ();  // works only after SSE calculations
+      pstr  GetAtomName       () { return name;    }
+      pstr  GetElementName    () { return element; }
+      pstr  GetAtomCharge     ( pstr chrg );
+
+      //   GetChainCalphas(...) is a specialized function for quick
+      // access to C-alphas of chain which includes given atom.
+      // This function works faster than an equivalent implementation
+      // through MMDB's selection procedures.
+      //    Parameters:
+      //       Calphas   - array to accept pointers on C-alpha atoms
+      //                  If Calphas!=NULL, then the function will
+      //                  delete and re-allocate it. When the array
+      //                  is no longer needed, the application MUST
+      //                  delete it:  delete[] Calphas; Deleting
+      //                  Calphas does not delete atoms from MMDB.
+      //       nCalphas   - integer to accept number of C-alpha atoms
+      //                  and the length of Calphas array.
+      //       altLoc     - alternative location indicator. By default
+      //                  (""), maximum-occupancy locations are taken.
+      void  GetChainCalphas ( PPAtom & Calphas, int & nCalphas,
+                              cpstr altLoc = "" );
+
+      bool isTer         () { return Ter; }
+      bool isMetal       ();
+      bool isSolvent     ();  // works only for atom in a residue!
+      bool isInSelection ( int selHnd );
+      bool isNTerminus   ();
+      bool isCTerminus   ();
+
+      void  CalAtomStatistics ( RAtomStat AS );
+
+      realtype GetDist2 ( PAtom a );
+      realtype GetDist2 ( PAtom a, mat44 & tm );  // tm applies to A
+      realtype GetDist2 ( PAtom a, mat33 & r, vect3 & t );// tm applies to A
+      realtype GetDist2 ( realtype ax, realtype ay, realtype az );
+
+      // GetCosine(a1,a2) calculates cosine of angle a1-this-a2,
+      // i.e. that between vectors [a1,this] and [this,a2].
+      realtype GetCosine ( PAtom a1, PAtom a2 );
+
+      PResidue GetResidue  ();
+      PChain   GetChain    ();
+      PModel   GetModel    ();
+      int       GetResidueNo();
+      void *    GetCoordHierarchy();  // PRoot
+
+      //  GetAtomID(..) generates atom ID in the form
+      //     /m/c/r(rn).i/n[e]:a
+      //  where  m  - model number
+      //         c  - chain ID
+      //         r  - residue sequence number
+      //         rn - residue name
+      //         i  - insertion code
+      //         n  - atom name
+      //         e  - chemical element specification
+      //         a  - alternate location indicator
+      //  If any of the fields is undefined, it is replaced by
+      //  hyphen  '-'.
+      //    No checks on the sufficiency of string buffer AtomID
+      //  is made.
+      //    GetAtomID returns AtomID.
+      pstr  GetAtomID ( pstr AtomID );
+
+      pstr  GetAtomIDfmt ( pstr AtomID );
+
+      // -------  checking atom ID
+      // CheckID(..) returns 1 if atom is identified, and 0 otherwise.
+      //   Parameters:
+      //     aname   - atom name. It may or may not be aligned (as in
+      //               a PDB file), only first word of the name will
+      //               be taken ("CA", " CA" and " CA B" are all
+      //               considered as "CA"). aname may be set to NULL
+      //               or '*', then this parameter is ignored.
+      //     elname  - element code. It will work only if element code
+      //               is supplied (which might not be the case if
+      //               the atom was created in a tricky way). elname
+      //               should be used to distinguih between, e.g.
+      //               "Ca" and "C_alpha"). elname may be set to NULL,
+      //               or '*', then this parameter is ignored.
+      //     aloc    - the alternate location code. aloc may be set to
+      //               NULL or '*', then this parameter is ignored.
+      //  IMPORTANT: comparison is case-sensitive.
+      //  The atom is considered as identified, if all non-NULL
+      //  parameters do match. If all parameters are set NULL, any atom
+      //  is identified.
+      //  DEFAULT values correspond to 'any element' and
+      //                 'no alternate location code'
+      //  NOTE that " " is not an empty item.
+      int   CheckID ( const AtomName aname, const Element elname=NULL,
+                      const AltLoc aloc=pstr("") );
+
+      // CheckIDS(..) works exactly like CheckID(..), but it takes
+      // the only parameter, the atom ID, which is of the form:
+      //    {name} {[element]} {:altcode}
+      // Here {} means that the item may be omitted. Any item may be
+      // represented by a wildcard '*', which means 'any value'. Just
+      // absence of an item means 'empty', which makes sense only for
+      // alternate location code. Missing name or element therefore
+      // mean 'any name' or 'any element', correspondingly (same as a
+      // wildcard). There should be no spaces in ID except for leading
+      // spaces; any following space will terminate parsing.
+      // The followings are perfectly valid IDs:
+      //   CA[C]:A     (carbon C_alpha in location A)
+      //   CA[*]:A     (either C_alpha or Ca in location A)
+      //   CA:A        (same as above)
+      //   CA          (either C_alpha or Ca with no location indicator)
+      //   CA[]        (same as above)
+      //   CA[C]:      (C_alpha with no location indicator)
+      //   [C]         (any carbon with no location indicator)
+      //   [C]:*       (any carbon with any location indicator)
+      //   *[C]:*      (same as above)
+      //   :A          (any atom in location A)
+      //   *[*]:A      (same as above)
+      //   *[*]:*      (any atom)
+      //   *           (any atom with no alternate location indicator)
+      int   CheckIDS ( cpstr ID );
+
+
+      // -------  transform coordinates: x := m*x + v
+      void  Transform     ( mat33 & tm, vect3 & v );
+      void  Transform     ( mat44 & tm );
+      void  TransformCopy ( mat44 & tm,
+                            realtype & xx, realtype & yy, realtype & zz );
+      void  TransformSet  ( mat44 & tm,
+                            realtype xx, realtype yy, realtype zz );
+
+
+      // -------  user-defined data handlers
+      int   PutUDData ( int UDDhandle, int      iudd );
+      int   PutUDData ( int UDDhandle, realtype rudd );
+      int   PutUDData ( int UDDhandle, cpstr    sudd );
+
+      int   GetUDData ( int UDDhandle, int      & iudd );
+      int   GetUDData ( int UDDhandle, realtype & rudd );
+      int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+      int   GetUDData ( int UDDhandle, pstr     & sudd );
+
+
+      int   GetIndex()  { return index; }
+
+      virtual void Copy ( PAtom atom );  // without references in
+                                          // residues
+
+      void  SetShortBinary();  // leaves only coordinates in binary files
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      int       index;   // index in the file
+      int       nBonds;  // number of bonds in the lowest byte (!)
+      PAtomBond Bond;    // atom bonds
+
+      void  InitAtom       ();
+      void  FreeMemory     ();
+      void  StandardPDBOut ( cpstr Record, pstr S );
+      void  GetData        ( cpstr S );
+      ERROR_CODE CheckData ( cpstr S );
+      void  GetStat        ( realtype   v,
+                             realtype & v_min, realtype & v_max,
+                             realtype & v_m,   realtype & v_m2 );
+      void  _setBonds      ( PPAtom A ); // used only in Residue
+
+  };
+
+
+  //  ======================  Residue  ==========================
+
+  enum ALTLOC_FLAG  {
+    ALF_NoAltCodes    = 0x00000000,
+    ALF_EmptyAltLoc   = 0x00000001,
+    ALF_NoEmptyAltLoc = 0x00000002,
+    ALF_Mess          = 0x00000004,
+    ALF_Occupancy     = 0x00000008
+  };
+
+  enum SSE_FLAG  {
+    SSE_None   = 0,
+    SSE_Strand = 1,
+    SSE_Bulge  = 2,
+    SSE_3Turn  = 3,
+    SSE_4Turn  = 4,
+    SSE_5Turn  = 5,
+    SSE_Helix  = 6
+  };
+
+  DefineFactoryFunctions(Residue);
+
+  class Residue : public UDData  {
+
+    friend class Atom;
+    friend class Chain;
+    friend class Root;
+
+    public :
+
+      ResName  name;            //!< residue name - all spaces cut
+      ResName  label_comp_id;   //!< assigned residue name
+      ChainID  label_asym_id;   //!< assigned chain Id
+      InsCode  insCode;         //!< residue insertion code
+      PChain   chain;           //!< reference to chain
+      PPAtom   atom;            //!< array of atoms
+      int      seqNum;          //!< residue sequence number
+      int      label_seq_id;    //!< assigned residue sequence number
+      int      label_entity_id; //!< assigned entity id
+      int      index;           //!< index in the chain
+      int      nAtoms;          //!< number of atoms in the residue
+      byte     SSE;             //!< SSE type
+
+      Residue ();
+      Residue ( PChain Chain_Owner );
+      Residue ( PChain Chain_Owner, const ResName resName,
+                int    sqNum,       const InsCode ins );
+      Residue ( io::RPStream Object    );
+      ~Residue();
+
+      void  SetChain ( PChain Chain_Owner );
+      void  SetResID ( const ResName resName, int sqNum,
+                       const InsCode ins );
+      void  SetChainID ( const ChainID chID );
+
+      void  PDBASCIIAtomDump ( io::RFile f      );
+      void  MakeAtomCIF      ( mmcif::PData CIF );
+
+      PChain GetChain();
+      PModel GetModel();
+
+      int   GetModelNum   ();
+      pstr  GetChainID    ();
+      pstr  GetLabelAsymID();
+      pstr  GetResName    ();
+      pstr  GetLabelCompID();
+      int   GetAASimilarity ( const ResName resName );
+      int   GetAASimilarity ( PResidue res );
+      realtype GetAAHydropathy();
+      void  SetResName      ( const ResName resName );
+      int   GetSeqNum       ();
+      int   GetLabelSeqID   ();
+      int   GetLabelEntityID();
+      pstr  GetInsCode      ();
+      int   GetResidueNo    ();
+      int   GetCenter       ( realtype & x, realtype & y, realtype & z );
+      void * GetCoordHierarchy();  // PCMMDBFile
+
+      void  GetAtomStatistics ( RAtomStat AS );
+      void  CalAtomStatistics ( RAtomStat AS );
+
+      pstr  GetResidueID ( pstr ResidueID );
+
+      //   GetAltLocations(..) returns the number of different
+      // alternative locations in nAltLocs, the locations themselves
+      // - in aLoc and the corresponding occupancies - in occupancy.
+      //   aLoc and occupancy are allocated dynamically; it is
+      // responsibility of the application to deallocate aLoc prior
+      // calling GetAltLocations(..) if they were previously allocated.
+      // Either, the application is responsible for deallocating aLoc and
+      // occupancy after use.
+      //   occupancy[i] may return -1.0 if occupancies were not read
+      // from coordinate file.
+      //   alflag returns ALF_NoAltCodes if no alt codes was found,
+      // otherwise the output is decoded according to bits:
+      //   ALF_EmptyAltLoc   alternative locations include the
+      //                     "no alt loc indicator" ("" for
+      //                     Atom::altLoc).
+      //                     This means that each atom that has alt locs
+      //                     different of "", also includes one marked as
+      //                     "".
+      //  ALF_NoEmptyAltLoc  alternative locations do not include the
+      //                     "no alt loc indicator" ("" for
+      //                     Atom::altLoc).
+      //                     This means that each atom has either ""
+      //                     alt loc or at least two alt locs different
+      //                     of "".
+      //  ALF_Mess           incorrect residue: it mixes both
+      //                     ""-including and not-""-including schemes
+      //  ALF_Occupancy      warning that sum of occupancies for alt
+      //                     located atoms differ from 1.0 by more
+      //                     than 0.01.
+      void  GetAltLocations   ( int & nAltLocs, PAltLoc & aLoc,
+                                rvector & occupancy, int & alflag );
+      int   GetNofAltLocations();
+
+      bool isAminoacid   ();
+      bool isNucleotide  ();
+      int  isDNARNA      (); // 0(neither),1(DNA),2(RNA)
+      bool isSugar       ();
+      bool isSolvent     ();
+      bool isModRes      ();
+      bool isInSelection ( int selHnd );
+      bool isNTerminus   ();
+      bool isCTerminus   ();
+
+      // -------  checking residue ID
+      // CheckID(..) returns 1 if residue is identified, and 0 otherwise.
+      //   Parameters:
+      //     sname   - pointer to sequence number; if NULL then ignored.
+      //     inscode - insertion code; if NULL or '*' then ignored.
+      //     resname - residue name; if NULL or '*' then ignored.
+      //  IMPORTANT: comparison is case-sensitive.
+      //  The residue is considered as identified, if all non-NULL
+      //  parameters do match. If all parameters are set NULL, any
+      //  residue is identified.
+      //  DEFAULT values correspond to 'any residue name' and
+      //                 'no insertion code'
+      //  NOTE that " " is not an empty item.
+      int   CheckID ( int * snum, const InsCode inscode=pstr(""),
+                      const ResName resname=NULL );
+
+      // CheckIDS(..) works exactly like CheckID(..), but it takes
+      // the only parameter, the residue ID, which is of the form:
+      //    {seqnum} {(name)} {.inscode}
+      // Here {} means that the item may be omitted. Any item may be
+      // represented by a wildcard '*', which means 'any value'. Just
+      // absence of a value means 'empty', which is meaningful only for
+      // the insertion code. Missing sequence number or residue name
+      // therefore mean 'any sequence number' or 'any residue name',
+      // correspondingly (same as a wildcard).  There should be no
+      // spaces in ID except for leading spaces; any following space will
+      // terminate parsing. The followings are perfectly valid IDs:
+      //        27(ALA).A   (residue 27A ALA)
+      //        27().A      (residue 27A)
+      //        27(*).A     (same as above)
+      //        27.A        (same as above)
+      //        27          (residue 27)
+      //        27().       (same as above)
+      //        (ALA)       (any ALA without insertion code)
+      //        (ALA).      (same as above)
+      //        (ALA).*     (any ALA)
+      //        *(ALA).*    (any ALA)
+      //        .A          (any residue with insertion code A)
+      //        *(*).A      (same as above)
+      //        *(*).*      (any residue)
+      //        *           (any residue with no insertion code)
+      int  CheckIDS ( cpstr ID );
+
+
+      //  --------------------  Extracting atoms  ----------------------
+
+      int  GetNumberOfAtoms ();
+      int  GetNumberOfAtoms ( bool countTers );
+
+      PAtom GetAtom ( const AtomName aname, const Element elname=NULL,
+                      const AltLoc aloc=cpstr("") );
+      PAtom GetAtom ( int atomNo );
+
+      void GetAtomTable  ( PPAtom & atomTable, int & NumberOfAtoms );
+
+      //   GetAtomTable1(..) returns atom table without TER atoms and
+      // without NULL atom pointers. NumberOfAtoms returns the actual
+      // number of atom pointers in atomTable.
+      //   atomTable is allocated withing the function. If it was
+      // not set to NULL before calling the function, the latter will
+      // attempt to deallocate it first.
+      //   The application is responsible for deleting atomTable,
+      // however it must not touch atom pointers, i.e. use simply
+      // "delete[] atomTable;". Never pass atomTable from GetAtomTable()
+      // into this function, unless you set it to NULL before doing that.
+      void GetAtomTable1 ( PPAtom & atomTable, int & NumberOfAtoms );
+
+
+      //  ---------------------  Deleting atoms  -----------------------
+
+      int  DeleteAtom ( const AtomName aname, const Element elname=NULL,
+                        const AltLoc aloc=cpstr("") );
+      int  DeleteAtom ( int atomNo );
+      int  DeleteAllAtoms();
+
+      //   DeleteAltLocs() leaves only alternative location with maximal
+      // occupancy, if those are equal or unspecified, the one with
+      // "least" alternative location indicator.
+      //   The function returns the number of deleted atoms. The atom
+      // table remains untrimmed, so that nAtoms are wrong until that
+      // is done. Tables are trimmed by FinishStructEdit() or
+      // explicitely.
+      int  DeleteAltLocs ();
+
+      void TrimAtomTable ();
+
+      //  ----------------------  Adding atoms  ------------------------
+
+      //   AddAtom(..) adds atom to the residue. If residue is associated
+      // with a coordinate hierarchy, and atom 'atm' is not, the latter
+      // is checked in automatically. If atom 'atm' belongs to any
+      // coordinate hierarchy (even though that of the residue), it is
+      // *copied* rather than simply taken over, and is checked in.
+      //   If residue is not associated with a coordinate hierarchy, all
+      // added atoms will be checked in automatically once the residue
+      // is checked in.
+      int  AddAtom ( PAtom atm );
+
+      //   InsertAtom(..) inserts atom into the specified position of
+      // the residue. If residue is associated with a coordinate
+      // hierarchy, and atom 'atm' is not, the latter is checked in
+      // automatically. If atom 'atm' belongs to any coordinate
+      // hierarchy (even though that of the residue), it is *copied*
+      // rather than simply taken over, and is checked in.
+      //   If residue is not associated with a coordinate hierarchy, all
+      // added atoms will be checked in automatically once the residue
+      // is checked in.
+      int  InsertAtom ( PAtom atm, int position );
+
+      //   This version inserts before the atom with given name. If such
+      // name is not found, the atom is appended to the end.
+      int  InsertAtom ( PAtom atm, const AtomName aname );
+
+      //  --------------------------------------------------------------
+
+      void  ApplyTransform ( mat44 & TMatrix );  // transforms all
+                                                 // coordinates by
+                                                 // multiplying with
+                                                 // matrix TMatrix
+
+      void  MaskAtoms   ( PMask Mask );
+      void  UnmaskAtoms ( PMask Mask );
+
+
+      // -------  user-defined data handlers
+      int   PutUDData ( int UDDhandle, int      iudd );
+      int   PutUDData ( int UDDhandle, realtype rudd );
+      int   PutUDData ( int UDDhandle, cpstr    sudd );
+
+      int   GetUDData ( int UDDhandle, int      & iudd );
+      int   GetUDData ( int UDDhandle, realtype & rudd );
+      int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+      int   GetUDData ( int UDDhandle, pstr     & sudd );
+
+
+      bool isMainchainHBond ( PResidue res );
+
+      void  Copy  ( PResidue res );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      int   AtmLen;   // length of atom array
+      bool  Exclude;  // used internally
+
+      void  InitResidue  ();
+      void  FreeMemory   ();
+      int   _AddAtom     ( PAtom atm );
+      int   _ExcludeAtom ( int  kndex );  // 1: residue gets empty,
+                                          // 0 otherwise
+      void  _copy ( PResidue res );
+      void  _copy ( PResidue res, PPAtom atm, int & atom_index );
+      void  ExpandAtomArray ( int nAdd );
+      void  CheckInAtoms ();
+
+  };
+
+
+  extern realtype  BondAngle ( PAtom A, PAtom B, PAtom C );
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_bondmngr.cpp b/mmdb2/mmdb_bondmngr.cpp
new file mode 100644
index 0000000..6c7b99f
--- /dev/null
+++ b/mmdb2/mmdb_bondmngr.cpp
@@ -0,0 +1,121 @@
+//  $Id: mmdb_bondmngr.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    15.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_bondmngr <implementation>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::BondManager ( MMDB bonds maker )
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#include <string.h>
+
+#include "mmdb_bondmngr.h"
+#include "mmdb_math_graph.h"
+
+namespace mmdb  {
+
+  //  =====================   BondManager   =====================
+
+  BondManager::BondManager() : SelManager()  {
+  }
+
+  BondManager::BondManager ( io::RPStream Object )
+             : SelManager(Object)  {
+  }
+
+  BondManager::~BondManager()  {}
+
+  void  BondManager::MakeBonds ( bool calc_only )  {
+  UNUSED_ARGUMENT(calc_only);
+  PModel         mdl;
+  PChain         chain;
+  PResidue       res;
+  math::Graph    graph;
+  math::PPVertex V;
+  math::PPEdge   E;
+  int            i, im,ic,ir, nV,nE, k1,k2;
+
+    RemoveBonds();
+
+    for (im=0;im<nModels;im++)  {
+      mdl = model[im];
+      if (mdl)
+        for (ic=0;ic<mdl->nChains;ic++)  {
+          chain = mdl->chain[ic];
+          if (chain)
+            for (ir=0;ir<chain->nResidues;ir++)  {
+              res = chain->residue[ir];
+              if (res)  {
+                graph.MakeGraph   ( res,NULL );
+                graph.GetVertices ( V,nV );
+                graph.GetEdges    ( E,nE );
+                for (i=0;i<nE;i++)  {
+                  k1 = V[E[i]->GetVertex1()-1]->GetUserID();
+                  k2 = V[E[i]->GetVertex2()-1]->GetUserID();
+                  res->atom[k1]->AddBond ( res->atom[k2],E[i]->GetType() );
+                  res->atom[k2]->AddBond ( res->atom[k1],E[i]->GetType() );
+                }
+              }
+            }
+        }
+    }
+
+  }
+
+  void  BondManager::RemoveBonds()  {
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])
+        atom[i]->FreeBonds();
+  }
+
+  //  -------------------  Stream functions  ----------------------
+
+  void  BondManager::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    SelManager::write ( f );
+  }
+
+  void  BondManager::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    SelManager::read ( f );
+  }
+
+
+  MakeStreamFunctions(BondManager)
+
+}  // namespace mmdb
diff --git a/mmdb/mmdb_bondmngr.h b/mmdb2/mmdb_bondmngr.h
old mode 100755
new mode 100644
similarity index 66%
rename from mmdb/mmdb_bondmngr.h
rename to mmdb2/mmdb_bondmngr.h
index 0df4c96..9186232
--- a/mmdb/mmdb_bondmngr.h
+++ b/mmdb2/mmdb_bondmngr.h
@@ -1,18 +1,18 @@
-//  $Id: mmdb_bondmngr.h,v 1.20 2012/01/26 17:52:20 ekr Exp $
+//  $Id: mmdb_bondmngr.h $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
 //   functionality in protein crystallography applications.
 //
-//   Copyright (C) Eugene Krissinel 2000-2008.
+//   Copyright (C) Eugene Krissinel 2000-2013.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -22,7 +22,7 @@
 //
 //  =================================================================
 //
-//    17.11.00   <--  Date of Last Modification.
+//    15.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
@@ -30,10 +30,10 @@
 //       ~~~~~~~~~
 //       Project :  MacroMolecular Data Base (MMDB)
 //       ~~~~~~~~~
-//  **** Classes :  CMMDBBondManager ( MMDB bonds maker )
+//  **** Classes :  mmdb::BondManager ( MMDB bonds maker )
 //       ~~~~~~~~~
 //
-//  (C) E. Krissinel 2000-2008
+//  (C) E. Krissinel 2000-2013
 //
 //  =================================================================
 //
@@ -41,33 +41,33 @@
 #ifndef __MMDB_BondMngr__
 #define __MMDB_BondMngr__
 
-#ifndef  __MMDB_SelMngr__
 #include "mmdb_selmngr.h"
-#endif
 
+namespace mmdb  {
 
-// =======================  CMMDBBondManager  =======================
+  // =======================  BondManager  =======================
 
+  DefineClass(BondManager);
+  DefineStreamFunctions(BondManager);
 
-DefineClass(CMMDBBondManager);
-DefineStreamFunctions(CMMDBBondManager);
+  class BondManager : public SelManager  {
 
-class CMMDBBondManager : public CMMDBSelManager  {
+    public :
 
-  public :
+      BondManager ();
+      BondManager ( io::RPStream Object );
+      ~BondManager();
 
-    CMMDBBondManager ();
-    CMMDBBondManager ( RPCStream Object );
-    ~CMMDBBondManager();
+      void  MakeBonds  ( bool calc_only );
+      void  RemoveBonds();
 
-    void  MakeBonds  ( Boolean calc_only );
-    void  RemoveBonds();
+    protected :
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
 
-  protected :
-    void  write ( RCFile f );
-    void  read  ( RCFile f );
+  };
 
-};
+}  // namespace mmdb
 
 #endif
 
diff --git a/mmdb2/mmdb_chain.cpp b/mmdb2/mmdb_chain.cpp
new file mode 100644
index 0000000..1c3ab8e
--- /dev/null
+++ b/mmdb2/mmdb_chain.cpp
@@ -0,0 +1,2575 @@
+//  $Id: mmdb_chain.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    16.05.14   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Chain <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::ProModel     ( a virtue of Model           )
+//       ~~~~~~~~~  mmdb::DBReference  ( DBREF  records               )
+//             mmdb::ChainContainer ( container of in-chain classes   )
+//             mmdb::ContainerChain ( chain containered class template)
+//             mmdb::SeqAdv         ( SEQADV records                  )
+//             mmdb::SeqRes         ( SEQRES records                  )
+//             mmdb::ModRes         ( MODRES records                  )
+//             mmdb::HetRec         ( HET    records                  )
+//             mmdb::Chain          ( chain class                     )
+//
+//  Copyright (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_chain.h"
+#include "mmdb_model.h"
+#include "mmdb_root.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb  {
+
+  //  ==================  ProModel  ======================
+
+  MakeStreamFunctions(ProModel)
+
+  //  ==============  ChainContainer  ====================
+
+  PContainerClass ChainContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template    : return
+                                   ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_DBReference : return new DBReference ( chain );
+      case ClassID_SeqAdv      : return new SeqAdv      ( chain );
+      case ClassID_ModRes      : return new ModRes      ( chain );
+      case ClassID_Het         : return new HetRec      ( chain );
+    }
+  }
+
+  void ChainContainer::SetChain ( PChain Chain_Owner )  {
+  int i;
+    chain = Chain_Owner;
+    for (i=0;i<length;i++)
+      if (Container[i])
+        (void)PContainerChain(Container[i])->SetChain ( chain );
+  }
+
+  cpstr ChainContainer::Get1stChainID()  {
+  int i;
+    i = 0;
+    if (Container)  {
+      while ((i<length-1) && (!Container[i])) i++;
+      if (Container[i])
+            return PContainerChain(Container[i])->chainID;
+      else  return NULL;
+    } else
+      return NULL;
+  }
+
+  void ChainContainer::MoveByChainID ( const ChainID chainID,
+                                       PChainContainer ChainContainer ) {
+  int i;
+    for (i=0;i<length;i++)
+      if (Container[i])  {
+        if (!strcmp(PContainerChain(Container[i])->chainID,chainID))  {
+          ChainContainer->AddData ( Container[i] );
+          Container[i] = NULL;
+        }
+      }
+  }
+
+
+  MakeStreamFunctions(ChainContainer)
+
+
+  //  ================  ContainerChain  ===================
+
+  ContainerChain::ContainerChain() : ContainerClass()  {
+    chain      = NULL;
+    chainID[0] = char(0);
+  }
+
+  ContainerChain::ContainerChain ( PChain Chain_Owner)
+                : ContainerClass()  {
+    chain = Chain_Owner;
+    if (chain)  strcpy ( chainID,chain->GetChainID() );
+          else  chainID[0] = char(0);
+  }
+
+  void ContainerChain::SetChain ( PChain Chain_Owner )  {
+    chain = Chain_Owner;
+    if (chain)  strcpy ( chainID,chain->GetChainID() );
+          else  strcpy ( chainID,"" );
+  }
+
+  MakeStreamFunctions(ContainerChain)
+
+
+  //  ================  DBReference  ===================
+
+  DBReference::DBReference() : ContainerChain()  {
+    InitDBReference();
+  }
+
+  DBReference::DBReference( PChain Chain_Owner )
+             : ContainerChain(Chain_Owner)  {
+    InitDBReference();
+  }
+
+  DBReference::DBReference ( PChain Chain_Owner, cpstr S )
+             : ContainerChain(Chain_Owner)  {
+    InitDBReference();
+    ConvertPDBASCII ( S );
+  }
+
+  DBReference::DBReference ( io::RPStream Object )
+             : ContainerChain(Object)  {
+    InitDBReference();
+  }
+
+  DBReference::~DBReference() {}
+
+  void  DBReference::InitDBReference()  {
+    seqBeg = 0;
+    strcpy ( insBeg     ,"-"            );
+    seqEnd = 0;
+    strcpy ( insEnd     ,"-"            );
+    strcpy ( database   ,"------"       );
+    strcpy ( dbAccession,"--------"     );
+    strcpy ( dbIdCode   ,"------------" );
+    dbseqBeg = 0;
+    strcpy ( dbinsBeg,"-" );
+    dbseqEnd = 0;
+    strcpy ( dbinsEnd,"-" );
+  }
+
+  void  DBReference::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB DBREF line number N
+  //  from the class' data
+    strcpy ( S,"DBREF" );
+    PadSpaces ( S,80 );
+    strcpy_n  ( &(S[7]),chain->GetEntryID(),4 );
+    if (chain->chainID[0])  S[12] = chain->chainID[0];
+    PutIntIns ( &(S[14]),seqBeg,4,insBeg     );
+    PutIntIns ( &(S[20]),seqEnd,4,insEnd     );
+    strcpy_n  ( &(S[26]),database   ,6       );
+    strcpy_n  ( &(S[33]),dbAccession,8       );
+    strcpy_n  ( &(S[42]),dbIdCode   ,12      );
+    PutIntIns ( &(S[55]),dbseqBeg,5,dbinsBeg );
+    PutIntIns ( &(S[62]),dbseqEnd,5,dbinsEnd );
+  }
+
+  void  DBReference::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop1,Loop2;
+  int          RC1,RC2;
+
+    RC1 = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ,Loop1 );
+    RC2 = CIF->AddLoop ( CIFCAT_STRUCT_REF    ,Loop2 );
+
+    if ((RC1!=mmcif::CIFRC_Ok) || (RC2!=mmcif::CIFRC_Ok))  {
+      // the category was (re)created, provide tags
+      Loop1->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE            );
+      Loop1->AddLoopTag ( CIFTAG_NDB_CHAIN_ID               );
+      Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_BEG              );
+      Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE );
+      Loop1->AddLoopTag ( CIFTAG_SEQ_ALIGN_END              );
+      Loop1->AddLoopTag ( CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE );
+      Loop1->AddLoopTag ( CIFTAG_NDB_DB_ACCESSION           );
+      Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_BEG               );
+      Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE  );
+      Loop1->AddLoopTag ( CIFTAG_DB_ALIGN_END               );
+      Loop1->AddLoopTag ( CIFTAG_NDB_DB_ALIGN_END_INS_CODE  );
+      Loop2->AddLoopTag ( CIFTAG_DB_NAME );
+      Loop2->AddLoopTag ( CIFTAG_DB_CODE );
+    }
+
+    Loop1->AddString  ( chain->GetEntryID(),true );
+    Loop1->AddString  ( chain->chainID     ,true );
+    Loop1->AddInteger ( seqBeg                   );
+    Loop1->AddString  ( insBeg             ,true );
+    Loop1->AddInteger ( seqEnd                   );
+    Loop1->AddString  ( insEnd             ,true );
+    Loop1->AddString  ( dbAccession        ,true );
+    Loop1->AddInteger ( dbseqBeg                 );
+    Loop1->AddString  ( dbinsBeg           ,true );
+    Loop1->AddInteger ( dbseqEnd                 );
+    Loop1->AddString  ( dbinsEnd           ,true );
+
+    Loop2->AddString  ( database,true );
+    Loop2->AddString  ( dbIdCode,true );
+
+  }
+
+  ERROR_CODE DBReference::GetCIF ( mmcif::PData CIF, int & n )  {
+  //  GetCIF(..) must be always run without reference to Chain,
+  //  see CModel::GetCIF(..).
+  mmcif::PLoop   Loop1,Loop2;
+  mmcif::PStruct Struct2;
+  pstr           F;
+  int            RC,ref_id1,ref_id2;
+  CIF_MODE       CIFMode;
+  ERROR_CODE     rc;
+
+    Loop1 = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ );
+
+    if (!Loop1)  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    if (n>=Loop1->GetLoopLength())  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+
+    //  Determine the ChainID first and store it locally. It will
+    // be used by CModel for generating chains and placing the
+    // primary structure data BEFORE reading the coordinate section.
+    CIFMode = CIF_NDB;
+    F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),n,RC );
+    if ((RC) || (!F))  {
+      CIFMode = CIF_PDBX;
+      F = Loop1->GetString ( CIFName(TAG_CHAIN_ID,CIFMode),n,RC );
+    }
+    if ((!RC) && F)  {
+      strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+      Loop1->DeleteField ( CIFName(TAG_CHAIN_ID,CIFMode),n );
+    } else
+      strcpy ( chainID,"" );
+
+
+    rc = CIFGetInteger(seqBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG,CIFMode),n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+    CIFGetString ( insBeg,Loop1,CIFName(TAG_SEQ_ALIGN_BEG_INS_CODE,CIFMode),
+                   n,sizeof(InsCode),pstr(" ") );
+
+    rc = CIFGetInteger(seqEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END,CIFMode),n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+    CIFGetString ( insEnd,Loop1,CIFName(TAG_SEQ_ALIGN_END_INS_CODE,CIFMode),
+                   n,sizeof(InsCode),pstr(" ") );
+    CIFGetString ( dbAccession,Loop1,CIFName(TAG_DB_ACCESSION,CIFMode),
+                   n,sizeof(DBAcCode),pstr("        ") );
+
+    rc = CIFGetInteger(dbseqBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG,CIFMode),n);
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+    CIFGetString ( dbinsBeg,Loop1,CIFName(TAG_DB_ALIGN_BEG_INS_CODE,CIFMode),
+                   n,sizeof(InsCode),pstr(" ") );
+
+    rc = CIFGetInteger(dbseqEnd,Loop1,CIFName(TAG_DB_ALIGN_END,CIFMode),n);
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+    CIFGetString ( dbinsEnd,Loop1,CIFName(TAG_DB_ALIGN_END_INS_CODE,CIFMode),
+                   n,sizeof(InsCode),pstr(" ") );
+
+    Loop2 = CIF->GetLoop ( CIFCAT_STRUCT_REF );
+    if (Loop2)  {
+      CIFGetString ( database,Loop2,CIFTAG_DB_NAME,n,
+                     sizeof(DBName)  ,pstr("      ")       );
+      CIFGetString ( dbIdCode,Loop2,CIFTAG_DB_CODE,n,
+                     sizeof(DBIdCode),pstr("            ") );
+    } else if (CIFMode==CIF_PDBX)  {
+      Struct2 = CIF->GetStructure ( CIFCAT_STRUCT_REF );
+      if (Struct2 &&
+          (!CIFGetInteger(ref_id1,Loop1,CIFTAG_REF_ID,n)) &&
+          (!CIFGetInteger(ref_id2,Struct2,CIFTAG_ID,false)))  {
+        if (ref_id1==ref_id2)  {
+          CIFGetString ( database,Struct2,CIFTAG_DB_NAME,
+                         sizeof(DBName)  ,pstr("      ")      ,false );
+          CIFGetString ( dbIdCode,Struct2,CIFTAG_DB_CODE,
+                         sizeof(DBIdCode),pstr("            "),false );
+        }
+      }
+    }
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+
+  ERROR_CODE DBReference::ConvertPDBASCII ( cpstr S )  {
+  IDCode idCode;
+    if (chain->chainID[0])  {
+      if (S[12]!=chain->chainID[0])
+        return Error_WrongChainID;
+    } else if (S[12]!=' ')  {
+      chain->chainID[0] = S[12];
+      chain->chainID[1] = char(0);
+    } else
+      chain->chainID[0] = char(0);
+    strcpy ( idCode,chain->GetEntryID() );
+    if (idCode[0])  {
+      if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
+        return Error_WrongEntryID;
+    } else  {
+      GetString ( idCode,&(S[7]),4 );
+      chain->SetEntryID ( idCode );
+    }
+    GetIntIns  ( seqBeg,insBeg,&(S[14]),4  );
+    GetIntIns  ( seqEnd,insEnd,&(S[20]),4  );
+    strcpy_ncs ( database     ,&(S[26]),6  );
+    strcpy_ncs ( dbAccession  ,&(S[33]),8  );
+    strcpy_ncs ( dbIdCode     ,&(S[42]),12 );
+    GetIntIns  ( dbseqBeg,dbinsBeg,&(S[55]),5 );
+    GetIntIns  ( dbseqEnd,dbinsEnd,&(S[62]),5 );
+    return Error_NoError;
+  }
+
+  void  DBReference::Copy ( PContainerClass DBRef )  {
+
+    ContainerChain::Copy ( DBRef );
+
+    seqBeg   = PDBReference(DBRef)->seqBeg;
+    seqEnd   = PDBReference(DBRef)->seqEnd;
+    dbseqBeg = PDBReference(DBRef)->dbseqBeg;
+    dbseqEnd = PDBReference(DBRef)->dbseqEnd;
+    strcpy ( insBeg     ,PDBReference(DBRef)->insBeg      );
+    strcpy ( insEnd     ,PDBReference(DBRef)->insEnd      );
+    strcpy ( database   ,PDBReference(DBRef)->database    );
+    strcpy ( dbAccession,PDBReference(DBRef)->dbAccession );
+    strcpy ( dbIdCode   ,PDBReference(DBRef)->dbIdCode    );
+    strcpy ( dbinsBeg   ,PDBReference(DBRef)->dbinsBeg    );
+    strcpy ( dbinsEnd   ,PDBReference(DBRef)->dbinsEnd    );
+
+  }
+
+  void  DBReference::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version  );
+    f.WriteInt  ( &seqBeg   );
+    f.WriteInt  ( &seqEnd   );
+    f.WriteInt  ( &dbseqBeg );
+    f.WriteInt  ( &dbseqEnd );
+    f.WriteTerLine ( insBeg     ,false );
+    f.WriteTerLine ( insEnd     ,false );
+    f.WriteTerLine ( database   ,false );
+    f.WriteTerLine ( dbAccession,false );
+    f.WriteTerLine ( dbIdCode   ,false );
+    f.WriteTerLine ( dbinsBeg   ,false );
+    f.WriteTerLine ( dbinsEnd   ,false );
+  }
+
+  void  DBReference::read  ( io::RFile f ) {
+  byte Version;
+    f.ReadByte ( &Version  );
+    f.ReadInt  ( &seqBeg   );
+    f.ReadInt  ( &seqEnd   );
+    f.ReadInt  ( &dbseqBeg );
+    f.ReadInt  ( &dbseqEnd );
+    f.ReadTerLine ( insBeg     ,false );
+    f.ReadTerLine ( insEnd     ,false );
+    f.ReadTerLine ( database   ,false );
+    f.ReadTerLine ( dbAccession,false );
+    f.ReadTerLine ( dbIdCode   ,false );
+    f.ReadTerLine ( dbinsBeg   ,false );
+    f.ReadTerLine ( dbinsEnd   ,false );
+  }
+
+  MakeStreamFunctions(DBReference)
+
+
+
+  //  ================  SeqAdv  ===================
+
+  SeqAdv::SeqAdv() : ContainerChain()  {
+    InitSeqAdv();
+  }
+
+  SeqAdv::SeqAdv ( PChain Chain_Owner )
+         : ContainerChain(Chain_Owner)  {
+    InitSeqAdv();
+  }
+
+  SeqAdv::SeqAdv ( PChain Chain_Owner, cpstr S )
+         : ContainerChain(Chain_Owner)  {
+    InitSeqAdv();
+    ConvertPDBASCII ( S );
+  }
+
+  SeqAdv::SeqAdv ( io::RPStream Object ) : ContainerChain(Object)  {
+    InitSeqAdv();
+  }
+
+  SeqAdv::~SeqAdv()  {
+    if (conflict)  delete[] conflict;
+  }
+
+  void  SeqAdv::InitSeqAdv()  {
+    strcpy ( resName    ,"---"       );
+    seqNum = 0;
+    strcpy ( insCode    ,"-"         );
+    strcpy ( database   ,"------"    );
+    strcpy ( dbAccession,"---------" );
+    strcpy ( dbRes      ,"---"       );
+    dbSeq = 0;
+    conflict = NULL;
+    CreateCopy ( conflict,pstr(" ") );
+  }
+
+  void  SeqAdv::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB SEQADV line number N
+  //  from the class' data
+    strcpy     ( S,"SEQADV" );
+    PadSpaces  ( S,80 );
+    strcpy_n   ( &(S[7]) ,chain->GetEntryID(),4 );
+    strcpy_n   ( &(S[12]),resName      ,3 );
+    if (chain->chainID[0])  S[16] = chain->chainID[0];
+    PutIntIns  ( &(S[18]),seqNum,4,insCode );
+    strcpy_n   ( &(S[24]),database   ,4    );
+    strcpy_n   ( &(S[29]),dbAccession,9    );
+    strcpy_n   ( &(S[39]),dbRes      ,3    );
+    PutInteger ( &(S[43]),dbSeq      ,5    );
+    strcpy_n   ( &(S[49]),conflict,IMin(strlen(conflict),21) );
+  }
+
+  ERROR_CODE SeqAdv::ConvertPDBASCII ( cpstr S )  {
+  IDCode idCode;
+    if (chain->chainID[0])  {
+      if (S[16]!=chain->chainID[0])
+        return Error_WrongChainID;
+    } else if (S[16]!=' ')  {
+      chain->chainID[0] = S[16];
+      chain->chainID[1] = char(0);
+    } else
+      chain->chainID[0] = char(0);
+    strcpy ( idCode,chain->GetEntryID() );
+    if (idCode[0])  {
+      if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
+        return Error_WrongEntryID;
+    } else  {
+      GetString ( idCode,&(S[7]),4 );
+      chain->SetEntryID ( idCode );
+    }
+    strcpy_ncs ( resName       ,&(S[12]),3 );
+    GetIntIns  ( seqNum,insCode,&(S[18]),4 );
+    strcpy_ncs ( database      ,&(S[24]),4 );
+    strcpy_ncs ( dbAccession   ,&(S[29]),9 );
+    strcpy_ncs ( dbRes         ,&(S[39]),3 );
+    GetInteger ( dbSeq,&(S[43]),5  );
+    CreateCopy ( conflict,&(S[49]) );
+    CutSpaces  ( conflict,SCUTKEY_END );
+    return Error_NoError;
+  }
+
+
+  void  SeqAdv::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop;
+  int          RC;
+
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_REF_SEQ_DIF,Loop );
+
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID_CODE           );
+      Loop->AddLoopTag ( CIFTAG_MON_ID                    );
+      Loop->AddLoopTag ( CIFTAG_NDB_PDB_CHAIN_ID          );
+      Loop->AddLoopTag ( CIFTAG_SEQ_NUM                   );
+      Loop->AddLoopTag ( CIFTAG_NDB_PDB_INS_CODE          );
+      Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_NAME           );
+      Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_ACCESSION_CODE );
+      Loop->AddLoopTag ( CIFTAG_DB_MON_ID                 );
+      Loop->AddLoopTag ( CIFTAG_NDB_SEQ_DB_SEQ_NUM        );
+      Loop->AddLoopTag ( CIFTAG_DETAILS                   );
+    }
+
+    Loop->AddString  ( chain->GetEntryID(),true );
+    Loop->AddString  ( resName            ,true );
+    Loop->AddString  ( chain->chainID     ,true );
+    Loop->AddInteger ( seqNum                   );
+    Loop->AddString  ( insCode            ,true );
+    Loop->AddString  ( database           ,true );
+    Loop->AddString  ( dbAccession        ,true );
+    Loop->AddString  ( dbRes              ,true );
+    Loop->AddInteger ( dbSeq                    );
+    Loop->AddString  ( conflict           ,true );
+
+  }
+
+  ERROR_CODE SeqAdv::GetCIF ( mmcif::PData CIF, int & n )  {
+  //  GetCIF(..) must be always run without reference to Chain,
+  //  see CModel::GetCIF(..).
+  mmcif::PLoop  Loop;
+  pstr          F;
+  int           RC;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_REF_SEQ_DIF );
+    if (!Loop)  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    if (n>=Loop->GetLoopLength())  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    //  Determine the ChainID first and store it locally. It will
+    // be used by CModel for generating chains and placing the
+    // primary structure data BEFORE reading the coordinate section.
+
+    F = Loop->GetString ( CIFTAG_NDB_PDB_CHAIN_ID,n,RC );
+    if ((!RC) && F)  {
+      strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+      Loop->DeleteField ( CIFTAG_NDB_PDB_CHAIN_ID,n );
+    } else
+      strcpy ( chainID,"" );
+
+    CIFGetString ( resName,Loop,CIFTAG_MON_ID,n,sizeof(ResName),
+                   pstr("UNK") );
+
+    CIFGetIntegerD ( seqNum,Loop,CIFTAG_SEQ_NUM );
+
+    CIFGetString ( insCode,Loop,CIFTAG_NDB_PDB_INS_CODE,
+                   n,sizeof(InsCode),pstr(" ") );
+
+    CIFGetString ( database,Loop,CIFTAG_NDB_SEQ_DB_NAME,n,
+                   sizeof(DBName),pstr(" ") );
+
+    CIFGetString ( dbAccession,Loop,CIFTAG_NDB_SEQ_DB_ACCESSION_CODE,
+                   n,sizeof(DBAcCode),pstr(" ") );
+
+    CIFGetString ( dbRes,Loop,CIFTAG_DB_MON_ID,n,sizeof(ResName),
+                   pstr("   ") );
+
+    CIFGetIntegerD ( dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM );
+  //  if (CIFGetInteger1(dbSeq,Loop,CIFTAG_NDB_SEQ_DB_SEQ_NUM,n))
+  //    dbSeq = MinInt4;
+
+    F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
+    if ((!RC) && F)  {
+      CreateCopy ( conflict,F );
+      Loop->DeleteField ( CIFTAG_DETAILS,n );
+    } else
+      CreateCopy ( conflict,pstr(" ") );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  SeqAdv::Copy ( PContainerClass SeqAdv )  {
+
+    ContainerClass::Copy ( SeqAdv );
+
+    seqNum = PSeqAdv(SeqAdv)->seqNum;
+    dbSeq  = PSeqAdv(SeqAdv)->dbSeq;
+    strcpy  ( resName    ,PSeqAdv(SeqAdv)->resName     );
+    strcpy  ( insCode    ,PSeqAdv(SeqAdv)->insCode     );
+    strcpy  ( database   ,PSeqAdv(SeqAdv)->database    );
+    strcpy  ( dbAccession,PSeqAdv(SeqAdv)->dbAccession );
+    strcpy  ( dbRes      ,PSeqAdv(SeqAdv)->dbRes       );
+    CreateCopy ( conflict,PSeqAdv(SeqAdv)->conflict    );
+
+  }
+
+  void  SeqAdv::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte    ( &Version );
+    f.WriteInt     ( &seqNum  );
+    f.WriteInt     ( &dbSeq   );
+    f.WriteTerLine ( resName    ,false );
+    f.WriteTerLine ( insCode    ,false );
+    f.WriteTerLine ( database   ,false );
+    f.WriteTerLine ( dbAccession,false );
+    f.WriteTerLine ( dbRes      ,false );
+    f.CreateWrite  ( conflict );
+  }
+
+  void  SeqAdv::read  ( io::RFile f ) {
+  byte Version;
+    f.ReadByte    ( &Version );
+    f.ReadInt     ( &seqNum  );
+    f.ReadInt     ( &dbSeq   );
+    f.ReadTerLine ( resName    ,false );
+    f.ReadTerLine ( insCode    ,false );
+    f.ReadTerLine ( database   ,false );
+    f.ReadTerLine ( dbAccession,false );
+    f.ReadTerLine ( dbRes      ,false );
+    f.CreateRead  ( conflict );
+  }
+
+  MakeStreamFunctions(SeqAdv)
+
+
+
+  //  ================  SeqRes  ===================
+
+  SeqRes::SeqRes() : io::Stream()  {
+    InitSeqRes();
+  }
+
+  SeqRes::SeqRes ( io::RPStream Object ) : io::Stream(Object)  {
+    InitSeqRes();
+  }
+
+  SeqRes::~SeqRes()  {
+    FreeMemory();
+  }
+
+  void  SeqRes::SetChain ( PChain Chain_Owner )  {
+    chain = Chain_Owner;
+    if (chain)  strcpy ( chainID,chain->chainID );
+          else  strcpy ( chainID,"" );
+  }
+
+  void  SeqRes::InitSeqRes()  {
+    chain   = NULL;
+    numRes  = -1;
+    resName = NULL;
+    serNum  = 0;
+    strcpy ( chainID,"" );
+  }
+
+  void  SeqRes::FreeMemory()  {
+    if (resName)  delete[] resName;
+    resName = NULL;
+    numRes  = -1;
+    serNum  = 0;
+  }
+
+  void  SeqRes::PDBASCIIDump ( io::RFile f )  {
+  //  writes the ASCII PDB SEQRES lines into file f
+  char S[100];
+  int  i,k,sN;
+    if (numRes<0)  return;
+    strcpy     ( S,"SEQRES" );
+    PadSpaces  ( S,80 );
+    if (chain->chainID[0])
+      S[11] = chain->chainID[0];
+    PutInteger ( &(S[13]),numRes,4 );
+    if (resName)  {
+      i  = 0;
+      sN = 1;
+      while (i<numRes)  {
+        PutInteger ( &(S[7]),sN,3 );
+        k = 19;
+        while ((i<numRes) && (k<70))  {
+          if (resName[i][0])
+                strcpy_n ( &(S[k]),resName[i],3 );
+          else  strcpy_n ( &(S[k]),pstr("   "),3 );
+          i++;
+          k += 4;
+        }
+        while (k<70)  {
+          strcpy_n ( &(S[k]),pstr("   "),3 );
+          k += 4;
+        }
+        f.WriteLine ( S );
+        sN++;
+      }
+    } else  {
+      S[9] = '0';
+      strcpy_n ( &(S[19]),pstr("UNK"),3 );
+      f.WriteLine ( S );
+    }
+  }
+
+  ERROR_CODE SeqRes::ConvertPDBASCII ( cpstr S )  {
+  int i,k,sN,nR;
+    if (chain->chainID[0])  {
+      if (S[11]!=chain->chainID[0])
+        return Error_WrongChainID;
+    } else if (S[11]!=' ')  {
+      chain->chainID[0] = S[11];
+      chain->chainID[1] = char(0);
+    } else
+      chain->chainID[0] = char(0);
+    GetInteger ( sN,&(S[8]) ,3 );
+    GetInteger ( nR,&(S[13]),4 );
+    if (sN==0)  {
+      FreeMemory();
+      numRes = nR;
+    } else  {
+      serNum++;
+      if (sN!=serNum)
+        return Error_SEQRES_serNum;
+      if (sN==1)  {
+        FreeMemory();
+        resName = new ResName[nR];
+        for (i=0;i<nR;i++)
+          resName[i][0] = char(0);
+        numRes  = nR;
+        serNum  = sN;
+      } else if (nR!=numRes)
+        return Error_SEQRES_numRes;
+      i = 0;
+      while ((i<nR) && (resName[i][0]))  i++;
+      if (i>=nR)
+        return Error_SEQRES_extraRes;
+      k = 19;
+      while ((i<nR) && (k<70))  {
+        GetString ( resName[i],&(S[k]),3 );
+        if (!strcmp(resName[i],"   "))  resName[i][0] = char(0);
+                                  else  i++;
+        k += 4;
+      }
+    }
+    return Error_NoError;
+  }
+
+
+  void  SeqRes::MakeCIF ( mmcif::PData CIF )  {
+  //  Note that SeqRes only adds sequence to the CIF loop common
+  // to all chains. Therefore this loop should be wiped off from
+  // CIF structure before putting first sequence into it.
+  mmcif::PLoop Loop;
+  int          RC,i;
+
+    if (numRes<0)  return;
+
+    RC = CIF->AddLoop ( CIFCAT_NDB_POLY_SEQ_SCHEME,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_ID     );
+      Loop->AddLoopTag ( CIFTAG_MON_ID );
+    }
+
+    if (resName)
+      for (i=0;i<numRes;i++)  {
+        Loop->AddString  ( chain->chainID,true );
+        Loop->AddString  ( resName[i]    ,true );
+      }
+    else
+      for (i=0;i<numRes;i++)  {
+        Loop->AddString  ( chain->GetEntryID(),true );
+        Loop->AddString  ( pstr("UNK")        ,true );
+      }
+
+  }
+
+  ERROR_CODE SeqRes::GetCIF ( mmcif::PData CIF )  {
+  //   Tries to get sequence from the CIF structure. A sequence
+  // for first met chain is extracted and then removed from
+  // the CIF structure, so that sequential calls will extract
+  // all sequencies. Chain ID is stored locally in chainID;
+  // reference to parent chain is neither used nor checked.
+  //   Returns 0 if sequence was extracted and 1 otherwise.
+  mmcif::PLoop Loop;
+  ResName    * rN;
+  ChainID      chID;
+  pstr         F;
+  cpstr        CHAIN_ID;
+  int          RC,i,l;
+  CIF_MODE     CIFMode;
+  bool         isMon;
+
+    FreeMemory();
+
+    CIFMode = CIF_NDB;
+    Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
+    if (!Loop)  {
+      CIFMode = CIF_PDBX;
+      Loop = CIF->GetLoop ( CIFName(CAT_POLY_SEQ_SCHEME,CIFMode) );
+      if (!Loop)  return Error_NoLoop;
+    }
+
+    l = Loop->GetLoopLength();
+    if (l<=0)  return Error_NoLoop;
+
+    rN         = new ResName[l];
+    chainID[0] = char(1);
+    numRes     = 0;
+    isMon      = false;
+    CHAIN_ID   = CIFName(TAG_SEQ_CHAIN_ID,CIFMode);
+    for (i=0;i<l;i++)  {
+      F = Loop->GetString ( CHAIN_ID,i,RC );
+      if (!RC)  {
+        if (F)  strcpy ( chID,F );
+          else  chID[0] = char(0);
+        if (chainID[0]==char(1))  strcpy ( chainID,chID );
+        if (!strcmp(chainID,chID))  {
+          CIFGetString ( rN[numRes],Loop,CIFTAG_MON_ID,i,
+                         sizeof(ResName),pstr("UNK") );
+          Loop->DeleteField ( CHAIN_ID,i );
+          if (strcmp(rN[numRes],"UNK")) isMon = true;
+          numRes++;
+        }
+      }
+    }
+
+    if (numRes==0)  {
+      numRes = -1;
+      delete[] rN;
+      return Error_EmptyCIFLoop;
+    }
+
+    if (isMon)  {
+      resName = new ResName[numRes];
+      for (i=0;i<numRes;i++)
+        strcpy ( resName[i],rN[i] );
+    }
+
+    delete[] rN;
+
+    return Error_NoError;
+
+  }
+
+  void  SeqRes::Copy ( PSeqRes SeqRes )  {
+  int i;
+
+    FreeMemory();
+
+    numRes = SeqRes->numRes;
+    serNum = SeqRes->serNum;
+
+    if (SeqRes->resName)  {
+      resName = new ResName[numRes];
+      for (i=0;i<numRes;i++)
+        strcpy ( resName[i],SeqRes->resName[i] );
+    }
+
+  }
+
+  void  SeqRes::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    f.WriteInt  ( &numRes  );
+    f.WriteInt  ( &serNum  );
+    if (resName)  i = 1;
+            else  i = 0;
+    f.WriteInt ( &i );
+    if (resName)
+      for (i=0;i<numRes;i++)
+        f.WriteTerLine ( resName[i],false );
+  }
+
+  void  SeqRes::read  ( io::RFile f ) {
+  int  i;
+  byte Version;
+    FreeMemory();
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &numRes  );
+    f.ReadInt  ( &serNum  );
+    f.ReadInt  ( &i       );
+    if (i)  {
+      resName = new ResName[numRes];
+      for (i=0;i<numRes;i++)
+        f.ReadTerLine ( resName[i],false );
+    }
+  }
+
+
+  MakeStreamFunctions(SeqRes)
+
+
+
+  //  ================  ModRes  ===================
+
+  ModRes::ModRes() : ContainerChain()  {
+    InitModRes();
+  }
+
+  ModRes::ModRes ( PChain Chain_Owner )
+        : ContainerChain(Chain_Owner)  {
+    InitModRes();
+  }
+
+  ModRes::ModRes ( PChain Chain_Owner, cpstr S )
+        : ContainerChain(Chain_Owner)  {
+    InitModRes();
+    ConvertPDBASCII ( S );
+  }
+
+  ModRes::ModRes ( io::RPStream Object ) : ContainerChain(Object)  {
+    InitModRes();
+  }
+
+  ModRes::~ModRes()  {
+    if (comment)  delete[] comment;
+  }
+
+  void  ModRes::InitModRes()  {
+    strcpy     ( resName,"---" );
+    seqNum  = 0;
+    strcpy     ( insCode,"-"   );
+    comment = NULL;
+    CreateCopy ( comment,pstr(" ") );
+    strcpy     ( stdRes ,"---" );
+  }
+
+  void  ModRes::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB MODRES line number N
+  //  from the class' data
+    strcpy     ( S,"MODRES" );
+    PadSpaces  ( S,80 );
+    strcpy_n   ( &(S[7]) ,chain->GetEntryID(),4  );
+    strcpy_n   ( &(S[12]),resName      ,3  );
+    if (chain->chainID[0])  S[16] = chain->chainID[0];
+    PutIntIns  ( &(S[18]),seqNum,4,insCode );
+    strcpy_n   ( &(S[24]),stdRes       ,3  );
+    strcpy_n   ( &(S[29]),comment,IMin(strlen(comment),41) );
+  }
+
+  ERROR_CODE ModRes::ConvertPDBASCII ( cpstr S )  {
+  IDCode idCode;
+    if (chain->chainID[0])  {
+      if (S[16]!=chain->chainID[0])
+        return Error_WrongChainID;
+    } else if (S[16]!=' ')  {
+      chain->chainID[0] = S[16];
+      chain->chainID[1] = char(0);
+    } else
+      chain->chainID[0] = char(0);
+    strcpy ( idCode,chain->GetEntryID() );
+    if (idCode[0])  {
+      if (strncmp(&(S[7]),idCode,4) && (!ignoreNonCoorPDBErrors))
+        return Error_WrongEntryID;
+    } else  {
+      GetString ( idCode,&(S[7]),4 );
+      chain->SetEntryID ( idCode );
+    }
+    GetString  ( resName       ,&(S[12]),3 );
+    GetIntIns  ( seqNum,insCode,&(S[18]),4 );
+    GetString  ( stdRes        ,&(S[24]),3 );
+    CreateCopy ( comment       ,&(S[29])   );
+    CutSpaces  ( comment,SCUTKEY_END       );
+    return Error_NoError;
+  }
+
+  void  ModRes::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(CIF);
+  UNUSED_ARGUMENT(N);
+  /*  -- apparently wrong use of _struct_conn, to be revised
+  mmcif::PLoop Loop;
+  int         RC;
+
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
+
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID               );
+      Loop->AddLoopTag ( CIFTAG_NDB_PDB_ID                 );
+      Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_COMP_ID        );
+      Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_ASYM_ID        );
+      Loop->AddLoopTag ( CIFTAG_PTNR1_LABEL_SEQ_ID         );
+      Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_LABEL_INS_CODE   );
+      Loop->AddLoopTag ( CIFTAG_NDB_PTNR1_STANDARD_COMP_ID );
+      Loop->AddLoopTag ( CIFTAG_DETAILS                    );
+    }
+
+    Loop->AddString  ( pstr("MODRES")           );
+    Loop->AddString  ( chain->GetEntryID(),true );
+    Loop->AddString  ( resName            ,true );
+    Loop->AddString  ( chain->chainID     ,true );
+    Loop->AddInteger ( seqNum                   );
+    Loop->AddString  ( insCode            ,true );
+    Loop->AddString  ( stdRes             ,true );
+    Loop->AddString  ( comment            ,true );
+
+  */
+
+  }
+
+  ERROR_CODE ModRes::GetCIF ( mmcif::PData CIF, int & n )  {
+  UNUSED_ARGUMENT(CIF);
+  //  GetCIF(..) must be always run without reference to Chain,
+  //  see CModel::GetCIF(..).
+
+  /*  -- apparently wrong use of _struct_conn, to be revised
+  mmcif::PLoop   Loop;
+  pstr          F;
+  int           l,RC;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
+    if (!Loop)  {
+      n = -1;
+      return;
+    }
+
+    l = Loop->GetLoopLength();
+    while (n<l)  {
+      F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
+      if ((!RC) && F)  {
+        if (!strcmp(F,"MODRES"))  break;
+      }
+      n++;
+    }
+    if (n>=l)  {
+      n = -1;
+      return;
+    }
+
+    Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
+
+    //  Determine the ChainID first and store it locally. It will
+    // be used by CModel for generating chains and placing the
+    // primary structure data BEFORE reading the coordinate section.
+    F = Loop->GetString ( CIFTAG_PTNR1_LABEL_ASYM_ID,n,RC );
+    if ((!RC) && F)  {
+      strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+      Loop->DeleteField ( CIFTAG_PTNR1_LABEL_ASYM_ID,n );
+    } else
+      strcpy ( chainID,"" );
+
+
+    CIFGetString ( resName,Loop,CIFTAG_PTNR1_LABEL_COMP_ID,n,
+                   sizeof(ResName),pstr("UNK") );
+
+    if (CIFGetInteger(seqNum,Loop,CIFTAG_PTNR1_LABEL_SEQ_ID,n))
+      return;
+
+    CIFGetString ( insCode,Loop,CIFTAG_NDB_PTNR1_LABEL_INS_CODE,
+                   n,sizeof(InsCode),pstr(" ") );
+
+    CIFGetString ( stdRes,Loop,CIFTAG_NDB_PTNR1_STANDARD_COMP_ID,n,
+                   sizeof(ResName),pstr("UNK") );
+
+    F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
+    if ((!RC) && F)  {
+      CreateCopy ( comment,F );
+      Loop->DeleteField ( CIFTAG_DETAILS,n );
+    } else
+      CreateCopy ( comment,pstr(" ") );
+
+    n++;
+
+  */
+
+    n = -1;
+
+    return Error_EmptyCIF;
+
+  }
+
+  void  ModRes::Copy ( PContainerClass ModRes )  {
+    seqNum = PModRes(ModRes)->seqNum;
+    strcpy ( resName,PModRes(ModRes)->resName );
+    strcpy ( insCode,PModRes(ModRes)->insCode );
+    strcpy ( stdRes ,PModRes(ModRes)->stdRes  );
+    CreateCopy ( comment,PModRes(ModRes)->comment );
+  }
+
+  void  ModRes::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte    ( &Version );
+    f.WriteInt     ( &seqNum  );
+    f.WriteTerLine ( resName,false );
+    f.WriteTerLine ( insCode,false );
+    f.WriteTerLine ( stdRes ,false );
+    f.CreateWrite  ( comment  );
+  }
+
+  void  ModRes::read  ( io::RFile f ) {
+  byte Version;
+    f.ReadByte    ( &Version );
+    f.ReadInt     ( &seqNum  );
+    f.ReadTerLine ( resName,false );
+    f.ReadTerLine ( insCode,false );
+    f.ReadTerLine ( stdRes ,false );
+    f.CreateRead  ( comment  );
+  }
+
+  MakeStreamFunctions(ModRes)
+
+
+
+  //  ================  HetRec  ======================
+
+  HetRec::HetRec() : ContainerChain()  {
+    InitHetRec();
+  }
+
+  HetRec::HetRec ( PChain Chain_Owner )
+        : ContainerChain(Chain_Owner)  {
+    InitHetRec();
+  }
+
+  HetRec::HetRec ( PChain Chain_Owner, cpstr S )
+        : ContainerChain(Chain_Owner)  {
+    InitHetRec();
+    ConvertPDBASCII ( S );
+  }
+
+  HetRec::HetRec ( io::RPStream Object ) : ContainerChain(Object)  {
+    InitHetRec();
+  }
+
+  HetRec::~HetRec()  {
+    if (comment)  delete[] comment;
+  }
+
+  void  HetRec::InitHetRec()  {
+    strcpy ( hetID  ,"---" );
+    strcpy ( insCode,"-"   );
+    seqNum      = 0;
+    numHetAtoms = 0;
+    comment     = NULL;
+    CreateCopy ( comment,pstr(" ") );
+  }
+
+  void  HetRec::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB MODRES line number N
+  //  from the class' data
+    strcpy     ( S,"HET" );
+    PadSpaces  ( S,80 );
+    strcpy_n   ( &(S[7]) ,hetID,3  );
+    if (chain->chainID[0])  S[12] = chain->chainID[0];
+    PutIntIns  ( &(S[13]),seqNum,4,insCode );
+    PutInteger ( &(S[20]),numHetAtoms,5    );
+    strcpy_n   ( &(S[30]),comment,IMin(strlen(comment),40) );
+  }
+
+  ERROR_CODE HetRec::ConvertPDBASCII ( cpstr S )  {
+    if (chain->chainID[0])  {
+      if (S[12]!=chain->chainID[0])
+        return Error_WrongChainID;
+    } else if (S[12]!=' ')  {
+      chain->chainID[0] = S[12];
+      chain->chainID[1] = char(0);
+    } else
+      chain->chainID[0] = char(0);
+    GetString  ( hetID         ,&(S[7]) ,3 );
+    GetIntIns  ( seqNum,insCode,&(S[13]),4 );
+    GetInteger ( numHetAtoms   ,&(S[20]),5 );
+    CreateCopy ( comment       ,&(S[30])   );
+    CutSpaces  ( comment,SCUTKEY_END       );
+    return Error_NoError;
+  }
+
+  void  HetRec::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop;
+  int         RC;
+
+    RC = CIF->AddLoop ( CIFCAT_NDB_NONSTANDARD_LIST,Loop );
+
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_ID              );
+      Loop->AddLoopTag ( CIFTAG_AUTH_ASYM_ID    );
+      Loop->AddLoopTag ( CIFTAG_AUTH_SEQ_ID     );
+      Loop->AddLoopTag ( CIFTAG_INS_CODE        );
+      Loop->AddLoopTag ( CIFTAG_NUMBER_ATOMS_NH );
+      Loop->AddLoopTag ( CIFTAG_DETAILS         );
+    }
+
+    Loop->AddString  ( hetID         ,true );
+    Loop->AddString  ( chain->chainID,true );
+    Loop->AddInteger ( seqNum              );
+    Loop->AddString  ( insCode       ,true );
+    Loop->AddInteger ( numHetAtoms         );
+    Loop->AddString  ( comment       ,true );
+
+  }
+
+  ERROR_CODE HetRec::GetCIF ( mmcif::PData CIF, int & n )  {
+  //  GetCIF(..) must be always run without reference to Chain,
+  //  see CModel::GetCIF(..).
+  mmcif::PLoop   Loop;
+  pstr           F;
+  int            RC;
+  ERROR_CODE     rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_NDB_NONSTANDARD_LIST );
+    if (!Loop)  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    if (n>=Loop->GetLoopLength())  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    //  Determine the ChainID first and store it locally. It will
+    // be used by CModel for generating chains and placing the
+    // primary structure data BEFORE reading the coordinate section.
+    F = Loop->GetString ( CIFTAG_AUTH_ASYM_ID,n,RC );
+    if ((!RC) && F)  {
+      strcpy_n0 ( chainID,F,sizeof(ChainID)-1 );
+      Loop->DeleteField ( CIFTAG_AUTH_ASYM_ID,n );
+    } else
+      strcpy ( chainID,"" );
+
+
+    CIFGetString ( hetID,Loop,CIFTAG_ID,n,sizeof(ResName),
+                   pstr("UNK") );
+
+    rc = CIFGetInteger ( seqNum,Loop,CIFTAG_AUTH_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( insCode,Loop,CIFTAG_INS_CODE,n,sizeof(InsCode),
+                   pstr(" ") );
+
+    rc = CIFGetInteger ( numHetAtoms,Loop,CIFTAG_NUMBER_ATOMS_NH,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    F = Loop->GetString ( CIFTAG_DETAILS,n,RC );
+    if ((!RC) && F)  {
+      CreateCopy ( comment,F );
+      Loop->DeleteField ( CIFTAG_DETAILS,n );
+    } else
+      CreateCopy ( comment,pstr(" ") );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  HetRec::Copy ( PContainerClass Het )  {
+    seqNum      = PHetRec(Het)->seqNum;
+    numHetAtoms = PHetRec(Het)->numHetAtoms;
+    strcpy     ( hetID  ,PHetRec(Het)->hetID   );
+    strcpy     ( insCode,PHetRec(Het)->insCode );
+    CreateCopy ( comment,PHetRec(Het)->comment );
+  }
+
+  void  HetRec::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte    ( &Version      );
+    f.WriteInt     ( &seqNum       );
+    f.WriteInt     ( &numHetAtoms  );
+    f.WriteTerLine ( hetID  ,false );
+    f.WriteTerLine ( insCode,false );
+    f.CreateWrite  ( comment       );
+  }
+
+  void  HetRec::read  ( io::RFile f ) {
+  byte Version;
+    f.ReadByte    ( &Version      );
+    f.ReadInt     ( &seqNum       );
+    f.ReadInt     ( &numHetAtoms  );
+    f.ReadTerLine ( hetID  ,false );
+    f.ReadTerLine ( insCode,false );
+    f.CreateRead  ( comment       );
+  }
+
+  MakeStreamFunctions(HetRec)
+
+
+
+  //  =====================   Chain   =======================
+
+  Chain::Chain() : UDData() {
+    InitChain();
+    SetChain ( pstr("") );
+  }
+
+  Chain::Chain ( PProModel Model, const ChainID chID ) : UDData()  {
+    InitChain();
+    SetChain ( chID );
+    if (Model)  Model->AddChain ( this );
+  }
+
+  Chain::Chain ( io::RPStream Object ) : UDData(Object)  {
+    InitChain();
+    SetChain ( pstr("") );
+  }
+
+  void  Chain::InitChain()  {
+    nResidues      = 0;
+    resLen         = 0;
+    residue        = NULL;
+    model          = NULL;
+    chainID[0]     = char(0);
+    prevChainID[0] = char(0);
+    nWeights       = 0;
+    Weight         = 0.0;
+    Exclude        = true;
+  }
+
+  void  Chain::SetChain ( const ChainID chID )  {
+    strcpy ( chainID,chID );
+    if (chID[0]==' ')  chainID[0] = char(0);
+    DBRef .SetChain ( this );
+    seqAdv.SetChain ( this );
+    seqRes.SetChain ( this );
+    modRes.SetChain ( this );
+    Het   .SetChain ( this );
+  }
+
+  void  Chain::SetChainID ( const ChainID chID )  {
+    strcpy ( chainID,chID );
+    if (chID[0]==' ')  chainID[0] = char(0);
+  }
+
+  Chain::~Chain()  {
+    FreeMemory();
+    if (model)  model->_ExcludeChain ( chainID );
+  }
+
+  void  Chain::FreeMemory()  {
+    DeleteAllResidues();
+    if (residue)  delete[] residue;
+    resLen    = 0;
+    nResidues = 0;
+    residue   = NULL;
+    FreeAnnotations();
+  }
+
+  void  Chain::FreeAnnotations()  {
+    DBRef .FreeContainer();
+    seqAdv.FreeContainer();
+    seqRes.FreeMemory   ();
+    modRes.FreeContainer();
+    Het   .FreeContainer();
+  }
+
+  void Chain::SetModel ( PProModel Model )  {
+    model = Model;
+  }
+
+  PManager Chain::GetCoordHierarchy()  {
+    if (model)  return model->GetCoordHierarchy();
+    return NULL;
+  }
+
+  void Chain::CheckInAtoms()  {
+  int i;
+    if (GetCoordHierarchy())
+      for (i=0;i<nResidues;i++)
+        if (residue[i])
+          residue[i]->CheckInAtoms();
+  }
+
+  ERROR_CODE Chain::ConvertDBREF ( cpstr PDBString ) {
+  PContainerChain ContainerChain;
+  ERROR_CODE      RC;
+    ContainerChain = new DBReference(this);
+    RC = ContainerChain->ConvertPDBASCII ( PDBString );
+    if (RC)  {
+      delete ContainerChain;
+      return RC;
+    }
+    DBRef.AddData ( ContainerChain );
+    return Error_NoError;
+  }
+
+  ERROR_CODE Chain::ConvertSEQADV ( cpstr PDBString ) {
+  PContainerChain ContainerChain;
+  ERROR_CODE      RC;
+    ContainerChain = new SeqAdv(this);
+    RC = ContainerChain->ConvertPDBASCII ( PDBString );
+    if (RC)  {
+      delete ContainerChain;
+      return RC;
+    }
+    seqAdv.AddData ( ContainerChain );
+    return Error_NoError;
+  }
+
+  ERROR_CODE Chain::ConvertSEQRES ( cpstr PDBString ) {
+    return seqRes.ConvertPDBASCII ( PDBString );
+  }
+
+  ERROR_CODE Chain::ConvertMODRES ( cpstr PDBString ) {
+  PContainerChain ContainerChain;
+  ERROR_CODE      RC;
+    ContainerChain = new ModRes(this);
+    RC = ContainerChain->ConvertPDBASCII ( PDBString );
+    if (RC)  {
+      delete ContainerChain;
+      return RC;
+    }
+    modRes.AddData ( ContainerChain );
+    return Error_NoError;
+  }
+
+  ERROR_CODE  Chain::ConvertHET ( cpstr PDBString ) {
+  PContainerChain ContainerChain;
+  ERROR_CODE      RC;
+    ContainerChain = new HetRec(this);
+    RC = ContainerChain->ConvertPDBASCII ( PDBString );
+    if (RC)  {
+      delete ContainerChain;
+      return RC;
+    }
+    Het.AddData ( ContainerChain );
+    return Error_NoError;
+  }
+
+
+  void  Chain::PDBASCIIDump ( io::RFile f )  {
+  // this function was for test purposes and is not used
+  // for normal function of MMDB
+    DBRef .PDBASCIIDump ( f );
+    seqAdv.PDBASCIIDump ( f );
+    seqRes.PDBASCIIDump ( f );
+    modRes.PDBASCIIDump ( f );
+    Het   .PDBASCIIDump ( f );
+  }
+
+  void  Chain::PDBASCIIAtomDump ( io::RFile f )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])
+        residue[i]->PDBASCIIAtomDump ( f );
+  }
+
+  void  Chain::MakeAtomCIF ( mmcif::PData CIF )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])
+        residue[i]->MakeAtomCIF ( CIF );
+  }
+
+
+  int  Chain::GetNumberOfResidues()  {
+    return nResidues;
+  }
+
+  PResidue Chain::GetResidue ( int resNo )  {
+    if ((0<=resNo) && (resNo<nResidues))
+          return residue[resNo];
+    else  return NULL;
+  }
+
+
+  PResidue Chain::GetResidueCreate ( const ResName resName,
+                                      int           seqNum,
+                                      const InsCode insCode,
+                                      bool          Enforce )  {
+  //   Returns pointer on residue, whose name, sequence number and
+  // insert code are given in resName, seqNum and insCode, respectively.
+  // If such a residue is absent in the chain, one is created at
+  // the end of the chain.
+  int i;
+
+    // check if such a residue is already in the chain
+    if (insCode[0])  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) &&
+              (!strcmp(insCode,residue[i]->insCode)))  {
+            if (!strcmp(resName,residue[i]->name))
+              return residue[i]; // it is there; just return the pointer
+            else if (!Enforce)
+              return NULL;       // duplicate seqNum and insCode!
+          }
+        }
+    } else  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) &&
+              (!residue[i]->insCode[0]))  {
+            if (!strcmp(resName,residue[i]->name))
+              return residue[i]; // it is there; just return the pointer
+            else if (!Enforce)
+              return NULL;       // duplicate seqNum and insCode!
+          }
+        }
+    }
+
+    // expand the residue array, if necessary
+    if (nResidues>=resLen)
+      ExpandResidueArray ( 100 );
+
+    // create new residue
+    residue[nResidues] = newResidue();
+    residue[nResidues]->SetChain ( this );
+    residue[nResidues]->SetResID ( resName,seqNum,insCode );
+    residue[nResidues]->index = nResidues;
+    nResidues++;
+
+    return residue[nResidues-1];
+
+  }
+
+  void  Chain::ExpandResidueArray ( int inc )  {
+  PPResidue Residue1;
+  int        i;
+    resLen  += inc;
+    Residue1 = new PResidue[resLen];
+    for (i=0;i<nResidues;i++)
+      Residue1[i] = residue[i];
+    if (residue) delete[] residue;
+    residue = Residue1;
+    for (i=nResidues;i<resLen;i++)
+      residue[i] = NULL;
+  }
+
+  PResidue Chain::GetResidue ( int seqNum, const InsCode insCode )  {
+  //   Returns pointer on residue, whose sequence number and
+  // insert code are given in seqNum and insCode, respectively.
+  // If such a residue is absent in the chain, returns NULL.
+  int     i;
+  bool isInsCode;
+    if (insCode)  isInsCode = insCode[0]!=char(0);
+            else  isInsCode = false;
+    if (isInsCode)  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) &&
+              (!strcmp(insCode,residue[i]->insCode)))
+            return residue[i];
+        }
+    } else  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))
+            return residue[i];
+        }
+    }
+    return NULL;
+  }
+
+  int  Chain::GetResidueNo ( int seqNum, const InsCode insCode )  {
+  //   GetResidueNo(..) returns the residue number in the chain's
+  // residues table. Residues are numbered as 0..nres-1 as they appear
+  // in the coordinate file.
+  //   If residue is not found, the function returns -1.
+  int      i;
+  bool isInsCode;
+    if (insCode)  isInsCode = insCode[0]!=char(0);
+            else  isInsCode = false;
+    if (isInsCode)  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) &&
+              (!strcmp(insCode,residue[i]->insCode)))
+            return i;
+        }
+    } else  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))
+            return i;
+        }
+    }
+    return -1;
+  }
+
+  void Chain::GetResidueTable ( PPResidue & resTable,
+                                int & NumberOfResidues )  {
+    resTable         = residue;
+    NumberOfResidues = nResidues;
+  }
+
+  int  Chain::_ExcludeResidue ( const ResName resName, int seqNum,
+                                const InsCode insCode )  {
+  //   ExcludeResidue(..) excludes (but does not dispose!) a residue
+  // from the chain. Returns 1 if the chain gets empty and 0 otherwise.
+  int  i,k;
+
+    if (!Exclude)  return 0;
+
+    // find the residue
+    k = -1;
+    for (i=0;(i<nResidues) && (k<0);i++)
+      if ((seqNum==residue[i]->seqNum)           &&
+          (!strcmp(insCode,residue[i]->insCode)) &&
+          (!strcmp(resName,residue[i]->name)))
+        k = i;
+
+    if (k>=0)  {
+      for (i=k+1;i<nResidues;i++)  {
+        residue[i-1] = residue[i];
+        if (residue[i-1])
+          residue[i-1]->index = i-1;
+      }
+      nResidues--;
+      residue[nResidues] = NULL;
+    }
+
+    if (nResidues<=0)  return 1;
+                 else  return 0;
+
+  }
+
+
+
+  //  ------------------  Deleting residues  --------------------------
+
+  int  Chain::DeleteResidue ( int resNo )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])  {
+        Exclude = false;
+        delete residue[resNo];
+        residue[resNo] = NULL;
+        Exclude = true;
+        return 1;
+      }
+    }
+    return 0;
+  }
+
+  int  Chain::DeleteResidue ( int seqNum, const InsCode insCode )  {
+  int i;
+    if (insCode[0])  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) &&
+              (!strcmp(insCode,residue[i]->insCode)))  {
+            Exclude = false;
+            delete residue[i];
+            residue[i] = NULL;
+            Exclude = true;
+            return 1;
+          }
+        }
+    } else  {
+      for (i=0;i<nResidues;i++)
+        if (residue[i])  {
+          if ((seqNum==residue[i]->seqNum) && (!residue[i]->insCode[0]))  {
+            Exclude = false;
+            delete residue[i];
+            residue[i] = NULL;
+            Exclude = true;
+            return 1;
+          }
+        }
+    }
+    return 0;
+  }
+
+
+  int  Chain::DeleteAllResidues()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  {
+        delete residue[i];
+        residue[i] = NULL;
+        k++;
+      }
+    nResidues = 0;
+    Exclude = true;
+    return k;
+  }
+
+
+  int  Chain::DeleteSolvent()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  {
+        if (residue[i]->isSolvent())  {
+          delete residue[i];
+          residue[i] = NULL;
+          k++;
+        }
+      }
+    Exclude = true;
+    return k;
+  }
+
+
+  void Chain::TrimResidueTable()  {
+  int i,j;
+    Exclude = false;
+    j = 0;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  {
+        if (residue[i]->nAtoms>0)  {
+          if (j<i)  {
+            residue[j] = residue[i];
+            residue[j]->index = j;
+            residue[i] = NULL;
+          }
+          j++;
+        } else  {
+          delete residue[i];
+          residue[i] = NULL;
+        }
+      }
+    nResidues = j;
+    Exclude   = true;
+  }
+
+  int  Chain::AddResidue ( PResidue res )  {
+  //  modify both CModel::Copy methods simultaneously!
+  //
+  //  Copy(PCModel,PPAtom,int&) copies atoms into array 'atom'
+  // starting from position atom_index. 'atom' should be able to
+  // accept all new atoms - no checks on the length of 'atom'
+  // is being made. This function should not be used in applications.
+    return InsResidue ( res,nResidues );
+  }
+
+  /*
+  PCmmdbRoot mmdbRoot;
+  PChain    chain1;
+  int        i;
+
+    for (i=0;i<nResidues;i++)
+      if (residue[i]==res)  return -i;  // this residue is already there
+
+    if (res)  {
+
+      mmdbRoot = PCmmdbRoot(GetCoordHierarchy());
+
+      // get space for new residue
+      if (nResidues>=resLen)
+        ExpandResidueArray ( 100 );
+
+      if (res->GetCoordHierarchy())  {
+        residue[nResidues] = newResidue();
+        residue[nResidues]->SetChain ( this );
+        residue[nResidues]->SetResID ( res->name,res->seqNum,res->insCode );
+        if (mmdbRoot)  {
+          // get space for new atoms
+          mmdbRoot->AddAtomArray ( res->GetNumberOfAtoms(true) );
+          residue[nResidues]->Copy ( res,mmdbRoot->Atom,mmdbRoot->nAtoms );
+        } else  {
+          for (i=0;i<res->nAtoms;i++)
+            residue[nResidues]->AddAtom ( res->atom[i] );
+        }
+      } else  {
+        residue[nResidues] = res;
+        chain1 = res->GetChain();
+        if (chain1)
+          for (i=0;i<chain1->nResidues;i++)
+            if (chain1->residue[i]==res)  {
+              chain1->residue[i] = NULL;
+              break;
+            }
+        residue[nResidues]->SetChain ( this );
+        if (mmdbRoot)
+          residue[nResidues]->CheckInAtoms();
+      }
+      nResidues++;
+
+    }
+
+    return nResidues;
+
+  }
+  */
+
+  int  Chain::InsResidue ( PResidue res, int seqNum,
+                            const InsCode insCode )  {
+    return InsResidue ( res,GetResidueNo(seqNum,insCode) );
+  }
+
+  int  Chain::InsResidue ( PResidue res, int pos )  {
+  //   Inserts residue res onto position pos of the chain,
+  // pos=0..nResidues-1 . Residues pos..nResidues-1 are
+  // shifted up the chain.
+  //   The function places new atoms on the top of atom
+  // index. It is advisable to call
+  // CmmdbRoot::PDBCleanup ( PDBCLEAN_INDEX ) after all
+  // insertions are done.
+  PRoot   mmdbRoot;
+  PChain  chain1;
+  int     i,pp;
+
+    pp = IMax ( 0,IMin(nResidues,pos) );
+
+    for (i=0;i<nResidues;i++)
+      if (residue[i]==res)  return -i;  // this residue is already there
+
+    if (res)  {
+
+      mmdbRoot = PRoot(GetCoordHierarchy());
+
+      // get space for new residue
+      if (nResidues>=resLen)
+        ExpandResidueArray ( 100 );
+
+      // shift residues to the end of the chain as necessary
+      for (i=nResidues;i>pp;i--)
+        residue[i] = residue[i-1];
+
+      // insert the new residue
+      if (res->GetCoordHierarchy())  {
+        residue[pp] = newResidue();
+        residue[pp]->SetChain ( this );
+        residue[pp]->SetResID ( res->name,res->seqNum,res->insCode );
+        if (mmdbRoot)  {
+          // get space for new atoms
+          mmdbRoot->AddAtomArray ( res->GetNumberOfAtoms(true) );
+          residue[pp]->_copy ( res,mmdbRoot->atom,mmdbRoot->nAtoms );
+        } else  {
+          for (i=0;i<res->nAtoms;i++)
+            residue[pp]->AddAtom ( res->atom[i] );
+        }
+      } else  {
+        residue[pp] = res;
+        chain1 = res->GetChain();
+        if (chain1)
+          for (i=0;i<chain1->nResidues;i++)
+            if (chain1->residue[i]==res)  {
+              chain1->residue[i] = NULL;
+              break;
+            }
+        residue[pp]->SetChain ( this );
+        if (mmdbRoot)
+          residue[pp]->CheckInAtoms();
+      }
+      nResidues++;
+
+    }
+
+    return nResidues;
+
+  }
+
+
+  // --------------------  Extracting atoms  -----------------------
+
+  int Chain::GetNumberOfAtoms ( bool countTers )  {
+  int i,na;
+    na = 0;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  na += residue[i]->GetNumberOfAtoms ( countTers );
+    return na;
+  }
+
+  int Chain::GetNumberOfAtoms ( int seqNo, const InsCode insCode )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res)  return res->nAtoms;
+    return 0;
+  }
+
+  int Chain::GetNumberOfAtoms ( int resNo )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])  return residue[resNo]->nAtoms;
+    }
+    return 0;
+  }
+
+  PAtom Chain::GetAtom ( int            seqNo,
+                         const InsCode  insCode,
+                         const AtomName aname,
+                         const Element  elmnt,
+                         const AltLoc   aloc )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res) return res->GetAtom ( aname,elmnt,aloc );
+    return NULL;
+  }
+
+  PAtom Chain::GetAtom ( int seqNo, const InsCode insCode,
+                         int atomNo )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res)  {
+      if ((0<=atomNo) && (atomNo<res->nAtoms))
+        return res->atom[atomNo];
+    }
+    return NULL;
+  }
+
+  PAtom Chain::GetAtom ( int            resNo,
+                         const AtomName aname,
+                         const Element  elmnt,
+                         const AltLoc   aloc )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])
+        return residue[resNo]->GetAtom ( aname,elmnt,aloc );
+    }
+    return NULL;
+  }
+
+  PAtom Chain::GetAtom ( int resNo, int atomNo )  {
+  PResidue res;
+    if ((0<=resNo) && (resNo<nResidues))  {
+      res = residue[resNo];
+      if (res)  {
+        if ((0<=atomNo) && (atomNo<res->nAtoms))
+          return res->atom[atomNo];
+      }
+    }
+    return NULL;
+  }
+
+  void Chain::GetAtomTable ( int seqNo, const InsCode insCode,
+                           PPAtom & atomTable, int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    res = GetResidue ( seqNo,insCode );
+    if (res)  {
+      atomTable     = res->atom;
+      NumberOfAtoms = res->nAtoms;
+    }
+  }
+
+  void Chain::GetAtomTable ( int resNo, PPAtom & atomTable,
+                              int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    if ((0<=resNo) && (resNo<nResidues))  {
+      res = residue[resNo];
+      if (res)  {
+        atomTable     = res->atom;
+        NumberOfAtoms = res->nAtoms;
+      }
+    }
+  }
+
+
+  void Chain::GetAtomTable1 ( int seqNo, const InsCode insCode,
+                               PPAtom & atomTable, int & NumberOfAtoms )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void Chain::GetAtomTable1 ( int resNo, PPAtom & atomTable,
+                               int & NumberOfAtoms )  {
+  PResidue res;
+    if ((0<=resNo) && (resNo<nResidues))
+         res = residue[resNo];
+    else res = NULL;
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  int Chain::DeleteAtom ( int            seqNo,
+                           const InsCode  insCode,
+                           const AtomName aname,
+                           const Element  elmnt,
+                           const AltLoc   aloc )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res) return res->DeleteAtom ( aname,elmnt,aloc );
+    return 0;
+  }
+
+  int Chain::DeleteAtom ( int seqNo, const InsCode insCode,
+                           int atomNo )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res) return res->DeleteAtom ( atomNo );
+    return 0;
+  }
+
+  int Chain::DeleteAtom ( int            resNo,
+                           const AtomName aname,
+                           const Element  elmnt,
+                           const AltLoc   aloc )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])
+        return residue[resNo]->DeleteAtom ( aname,elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int Chain::DeleteAtom ( int resNo, int atomNo )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])
+        return residue[resNo]->DeleteAtom ( atomNo );
+    }
+    return 0;
+  }
+
+
+  int Chain::DeleteAllAtoms ( int seqNo, const InsCode insCode )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res) return res->DeleteAllAtoms();
+    return 0;
+  }
+
+  int Chain::DeleteAllAtoms ( int resNo )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])
+        return residue[resNo]->DeleteAllAtoms();
+    }
+    return 0;
+  }
+
+  int Chain::DeleteAllAtoms()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])
+        k += residue[i]->DeleteAllAtoms();
+    return k;
+  }
+
+  int Chain::DeleteAltLocs()  {
+  //  This function leaves only alternative location with maximal
+  // occupancy, if those are equal or unspecified, the one with
+  // "least" alternative location indicator.
+  //  The function returns the number of deleted. All tables remain
+  // untrimmed, so that explicit trimming or calling FinishStructEdit()
+  // is required.
+  int i,n;
+
+    n = 0;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  n += residue[i]->DeleteAltLocs();
+
+    return n;
+
+  }
+
+
+  int Chain::AddAtom ( int seqNo, const InsCode insCode,
+                        PAtom atom )  {
+  PResidue res;
+    res = GetResidue ( seqNo,insCode );
+    if (res) return res->AddAtom ( atom );
+    return 0;
+  }
+
+  int Chain::AddAtom ( int resNo, PAtom atom )  {
+    if ((0<=resNo) && (resNo<nResidues))  {
+      if (residue[resNo])
+        return residue[resNo]->AddAtom ( atom );
+    }
+    return 0;
+  }
+
+
+  void  Chain::Copy ( PChain chain )  {
+  // modify both Chain::_copy and Chain::Copy methods simultaneously!
+  int i;
+
+    FreeMemory();
+
+    if (chain)  {
+
+      CopyAnnotations ( chain );
+
+      nResidues = chain->nResidues;
+      resLen    = nResidues;
+      if (nResidues>0)  {
+        residue = new PResidue[nResidues];
+        for (i=0;i<nResidues;i++)  {
+          residue[i] = newResidue();
+          residue[i]->SetChain ( this );
+          residue[i]->Copy ( chain->residue[i] );
+        }
+      }
+
+    }
+
+  }
+
+  void  Chain::CopyAnnotations ( PChain chain )  {
+    if (chain)  {
+      strcpy ( chainID    ,chain->chainID     );
+      strcpy ( prevChainID,chain->prevChainID );
+      DBRef .Copy ( &(chain->DBRef)  );
+      seqAdv.Copy ( &(chain->seqAdv) );  //  SEQADV records
+      seqRes.Copy ( &(chain->seqRes) );  //  SEQRES data
+      modRes.Copy ( &(chain->modRes) );  //  MODRES records
+      Het   .Copy ( &(chain->Het)    );  //  HET    records
+    }
+  }
+
+
+  void  Chain::_copy ( PChain chain )  {
+  // modify both Chain::_copy and Chain::Copy methods simultaneously!
+  int i;
+
+    FreeMemory();
+
+    strcpy ( chainID    ,chain->chainID     );
+    strcpy ( prevChainID,chain->prevChainID );
+
+    DBRef .Copy ( &(chain->DBRef)  );
+    seqAdv.Copy ( &(chain->seqAdv) );  //  SEQADV records
+    seqRes.Copy ( &(chain->seqRes) );  //  SEQRES data
+    modRes.Copy ( &(chain->modRes) );  //  MODRES records
+    Het   .Copy ( &(chain->Het)    );  //  HET    records
+
+    nResidues = chain->nResidues;
+    resLen    = nResidues;
+    if (nResidues>0)  {
+      residue = new PResidue[nResidues];
+      for (i=0;i<nResidues;i++)  {
+        residue[i] = newResidue();
+        residue[i]->SetChain ( this );
+        residue[i]->_copy ( chain->residue[i] );
+      }
+    }
+
+  }
+
+  void  Chain::_copy ( PChain chain, PPAtom atom, int & atom_index )  {
+  // modify both Chain::_copy and Chain::Copy methods simultaneously!
+  int i;
+
+    FreeMemory();
+
+    strcpy ( chainID    ,chain->chainID     );
+    strcpy ( prevChainID,chain->prevChainID );
+
+    DBRef .Copy ( &(chain->DBRef)  );
+    seqAdv.Copy ( &(chain->seqAdv) );  //  SEQADV records
+    seqRes.Copy ( &(chain->seqRes) );  //  SEQRES data
+    modRes.Copy ( &(chain->modRes) );  //  MODRES records
+    Het   .Copy ( &(chain->Het)    );  //  HET    records
+
+    nResidues = chain->nResidues;
+    resLen    = nResidues;
+    if (nResidues>0)  {
+      residue = new PResidue[nResidues];
+      for (i=0;i<nResidues;i++)
+        if (chain->residue[i])  {
+          residue[i] = newResidue();
+          residue[i]->SetChain ( this );
+          residue[i]->_copy ( chain->residue[i],atom,atom_index );
+        } else
+          residue[i] = NULL;
+    }
+
+  }
+
+  /*
+  void  Chain::Duplicate ( PChain Chain )  {
+  int i;
+
+    FreeMemory();
+
+    strcpy ( chainID    ,chain->chainID     );
+    strcpy ( prevChainID,chain->prevChainID );
+
+    DBReference.Copy ( &(chain->DBReference) );
+    SeqAdv     .Copy ( &(chain->SeqAdv)      );  //  SEQADV records
+    SeqRes     .Copy ( &(chain->SeqRes)      );  //  SEQRES data
+    ModRes     .Copy ( &(chain->ModRes)      );  //  MODRES records
+    Het        .Copy ( &(chain->Het)         );  //  HET    records
+
+    nResidues = chain->nResidues;
+    resLen    = nResidues;
+    if (nResidues>0)  {
+      Residue = new PResidue[nResidues];
+      for (i=0;i<nResidues;i++)  {
+        residue[i] = newResidue();
+        residue[i]->SetChain ( this );
+        residue[i]->Duplicate ( chain->residue[i] );
+      }
+    }
+
+  }
+  */
+
+  cpstr  Chain::GetEntryID()  {
+    if (model)  return model->GetEntryID();
+          else  return pstr("");
+  }
+
+  void  Chain::SetEntryID ( const IDCode idCode )  {
+    if (model) model->SetEntryID ( idCode );
+  }
+
+  int   Chain::GetModelNum()  {
+    if (model)  return model->GetSerNum();
+    return 0;
+  }
+
+  cpstr  Chain::GetChainID ( pstr ChID )  {
+    ChID[0] = char(0);
+    if (model)
+         sprintf ( ChID,"/%i/",model->GetSerNum() );
+    else strcpy  ( ChID,"/-/" );
+    strcat ( ChID,chainID );
+    return ChID;
+  }
+
+
+  void  Chain::GetAtomStatistics  ( RAtomStat AS )  {
+    AS.Init();
+    CalAtomStatistics ( AS );
+    AS.Finish();
+  }
+
+  void  Chain::CalAtomStatistics ( RAtomStat AS )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])
+        residue[i]->CalAtomStatistics ( AS );
+  }
+
+  void  Chain::ApplyTransform ( mat44 & TMatrix )  {
+  // transforms all coordinates by multiplying with matrix TMatrix
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  residue[i]->ApplyTransform ( TMatrix );
+  }
+
+  bool Chain::isSolventChain()  {
+  // returns true if chain contains only solvent molecules
+  bool B,P;
+  int     i;
+    B = true;
+    P = false;
+    for (i=0;(i<nResidues) && B;i++)
+      if (residue[i])  {
+        P = true;
+        B = residue[i]->isSolvent();
+      }
+    return (B && P);
+  }
+
+  bool Chain::isInSelection ( int selHnd )  {
+  PRoot mmdbRoot = (PRoot)GetCoordHierarchy();
+  PMask mask;
+    if (mmdbRoot)  {
+      mask = mmdbRoot->GetSelMask ( selHnd );
+      if (mask)  return CheckMask ( mask );
+    }
+    return false;
+  }
+
+  bool Chain::isAminoacidChain()  {
+  // returns true if chain contains at least one aminoacid residue
+  bool B,P;
+  int     i;
+    B = false;
+    P = false;
+    for (i=0;(i<nResidues) && (!B);i++)
+      if (residue[i])  {
+        P = true;
+        B = residue[i]->isAminoacid();
+      }
+    return (B && P);
+  }
+
+  bool Chain::isNucleotideChain()  {
+  // returns true if chain contains at least one nucleotide residue
+  bool B,P;
+  int     i;
+    B = false;
+    P = false;
+    for (i=0;(i<nResidues) && (!B);i++)
+      if (residue[i])  {
+        P = true;
+        B = residue[i]->isNucleotide();
+      }
+    return (B && P);
+  }
+
+  int  Chain::CheckID ( const ChainID chID )  {
+    if (chID)  {
+      if (!strcmp(chID,chainID))  return 1;
+    }
+    return 0;
+  }
+
+  int  Chain::CheckIDS ( cpstr CID )  {
+  ChainID  chn;
+  InsCode  inscode;
+  ResName  resname;
+  AtomName atm;
+  Element  elm;
+  AltLoc   aloc;
+  int      mdl,sn,rc;
+
+    rc = ParseAtomPath ( CID,mdl,chn,sn,inscode,resname,
+                         atm,elm,aloc,NULL );
+    if (rc>=0)  {
+      if (!strcmp(chn,chainID))  return 1;
+    }
+    return 0;
+
+  }
+
+  int  Chain::GetNumberOfDBRefs()  {
+    return  DBRef.Length();
+  }
+
+  PDBReference  Chain::GetDBRef ( int dbRefNo )  {
+    return  (PDBReference)DBRef.GetContainerClass ( dbRefNo );
+  }
+
+
+  void  Chain::MaskAtoms ( PMask mask )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  residue[i]->MaskAtoms ( mask );
+  }
+
+  void  Chain::MaskResidues ( PMask mask )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  residue[i]->SetMask ( mask );
+  }
+
+  void  Chain::UnmaskAtoms ( PMask mask )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  residue[i]->UnmaskAtoms ( mask );
+  }
+
+  void  Chain::UnmaskResidues ( PMask mask )  {
+  int i;
+    for (i=0;i<nResidues;i++)
+      if (residue[i])  residue[i]->RemoveMask ( mask );
+  }
+
+
+
+
+  // -------  user-defined data handlers
+
+  int  Chain::PutUDData ( int UDDhandle, int iudd )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::putUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Chain::PutUDData ( int UDDhandle, realtype rudd )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::putUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Chain::PutUDData ( int UDDhandle, cpstr sudd )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::putUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Chain::GetUDData ( int UDDhandle, int & iudd )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::getUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Chain::GetUDData ( int UDDhandle, realtype & rudd )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::getUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Chain::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::getUDData ( UDDhandle,sudd,maxLen );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Chain::GetUDData ( int UDDhandle, pstr & sudd )  {
+    if (UDDhandle & UDRF_CHAIN)
+          return  UDData::getUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+
+  //  -------------------------------------------------------------------
+
+  DefineClass(SortResidues)
+
+  class QSortResidues : public QuickSort  {
+    public :
+      QSortResidues() : QuickSort() {}
+      int  Compare ( int i, int j );
+      void Swap    ( int i, int j );
+      void Sort    ( PPResidue res, int nresidues );
+  };
+
+  int QSortResidues::Compare ( int i, int j )  {
+  int diff;
+    diff = ((PPResidue)data)[i]->seqNum - ((PPResidue)data)[j]->seqNum;
+    if (diff==0)
+      diff = strcmp( (PPResidue(data))[i]->insCode,
+                     (PPResidue(data))[j]->insCode );
+    if (diff>0)  return  1;
+    if (diff<0)  return -1;
+    return 0;
+  }
+
+  void QSortResidues::Swap ( int i, int j )  {
+  PResidue res;
+    res = ((PPResidue)data)[i];
+    ((PPResidue)data)[i] = ((PPResidue)data)[j];
+    ((PPResidue)data)[j] = res;
+  }
+
+  void QSortResidues::Sort ( PPResidue res, int nresidues )  {
+    QuickSort::Sort ( &(res[0]),nresidues );
+  }
+
+  void  Chain::SortResidues()  {
+  QSortResidues SR;
+    TrimResidueTable();
+    SR.Sort ( residue,nResidues );
+  }
+
+  int  Chain::GetNofModResidues()  {
+    return modRes.Length();
+  }
+
+  PModRes  Chain::GetModResidue ( int modResNo )  {
+    return  PModRes(modRes.GetContainerClass(modResNo));
+  }
+
+  void  Chain::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+
+    f.WriteByte ( &Version );
+
+    UDData::write ( f );
+
+    f.WriteTerLine ( chainID    ,false );
+    f.WriteTerLine ( prevChainID,false );
+
+    DBRef .write ( f );  //  Database reference
+    seqAdv.write ( f );  //  SEQADV records
+    seqRes.write ( f );  //  SEQRES data
+    modRes.write ( f );  //  MODRES records
+    Het   .write ( f );  //  HET    records
+
+    f.WriteInt ( &nResidues );
+    for (i=0;i<nResidues;i++)
+      residue[i]->write ( f );
+
+  }
+
+  void  Chain::read ( io::RFile f )  {
+  //   The Atom array in CmmdbRoot must be already read
+  // prior to calling this function!
+  int  i;
+  byte Version;
+
+    FreeMemory();
+
+    f.ReadByte ( &Version );
+
+    UDData::read ( f );
+
+    f.ReadTerLine ( chainID    ,false );
+    f.ReadTerLine ( prevChainID,false );
+
+    DBRef .read ( f );   //  Database reference
+    seqAdv.read ( f );   //  SEQADV records
+    seqRes.read ( f );   //  SEQRES data
+    modRes.read ( f );   //  MODRES records
+    Het   .read ( f );   //  HET    records
+
+    SetChain ( chainID );
+
+    f.ReadInt ( &nResidues );
+    resLen = nResidues;
+    if (nResidues>0)  {
+      residue = new PResidue[nResidues];
+      for (i=0;i<nResidues;i++)  {
+        residue[i] = newResidue();
+        residue[i]->SetChain ( this );
+        residue[i]->read ( f );
+      }
+    }
+
+  }
+
+
+  MakeFactoryFunctions(Chain)
+
+}  // namespace mmdb
+
+
+// ===================================================================
+
+  /*
+void  TestChain() {
+//  reads from 'in.chain', writes into
+//  'out.chain' and 'abin.chain'
+CFile    f;
+char     S[81];
+PChain  Chain;
+
+  Chain = newChain();
+
+  f.assign ( "in.chain",true );
+  if (f.reset()) {
+    while (!f.FileEnd()) {
+      f.ReadLine ( S,sizeof(S) );
+      chain->ConvertPDBString ( S );
+    }
+    f.shut();
+  } else {
+    printf ( " Can't open input file 'in.chain' \n" );
+    delete Chain;
+    return;
+  }
+
+  f.assign ( "out.chain",true );
+  if (f.rewrite()) {
+    chain->PDBASCIIDump ( f );
+    f.shut();
+  } else {
+    printf ( " Can't open output file 'out.chain' \n" );
+    delete Chain;
+    return;
+  }
+
+
+  f.assign ( "mmdb.chain.bin",false );
+  if (f.rewrite()) {
+    chain->write ( f );
+    f.shut();
+  } else {
+    printf ( "  Can't open binary chain file for writing.\n" );
+    delete Chain;
+    return;
+  }
+
+  delete Chain;
+  printf ( "   Chain deleted.\n" );
+
+  Chain = newChain();
+  if (f.reset()) {
+    chain->read ( f );
+    f.shut();
+  } else {
+    printf ( "  Can't open binary chain file for reading.\n" );
+    delete Chain;
+    return;
+  }
+
+  f.assign ( "abin.chain",true );
+  if (f.rewrite()) {
+    chain->PDBASCIIDump ( f );
+    f.shut();
+  } else
+    printf ( " Can't open output file 'abin.chain' \n" );
+
+  delete Chain;
+
+}
+  */
diff --git a/mmdb2/mmdb_chain.h b/mmdb2/mmdb_chain.h
new file mode 100644
index 0000000..db46f0e
--- /dev/null
+++ b/mmdb2/mmdb_chain.h
@@ -0,0 +1,662 @@
+//  $Id: mmdb_chain.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Chain <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::ProModel     ( a virtue of Model           )
+//       ~~~~~~~~~  mmdb::DBReference  ( DBREF  records               )
+//             mmdb::ChainContainer ( container of in-chain classes   )
+//             mmdb::ContainerChain ( chain containered class template)
+//             mmdb::SeqAdv         ( SEQADV records                  )
+//             mmdb::SeqRes         ( SEQRES records                  )
+//             mmdb::ModRes         ( MODRES records                  )
+//             mmdb::HetRec         ( HET    records                  )
+//             mmdb::Chain          ( chain class                     )
+//
+//  Copyright (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Chain__
+#define __MMDB_Chain__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_utils.h"
+#include "mmdb_atom.h"
+#include "mmdb_defs.h"
+
+namespace mmdb  {
+
+  //  ====================  ProModel  ======================
+
+  //    This class is a virtue needed only for defining certain
+  // functions of Model, which are used by Chain and
+  // Residue
+
+  DefineClass(ProModel);
+  DefineStreamFunctions(ProModel);
+
+  DefineClass(Manager);
+
+  class ProModel : public UDData  {
+
+    friend class Chain;
+
+    public :
+
+      ProModel  () : UDData () {}
+      ProModel  ( io::RPStream Object ) : UDData ( Object ) {}
+      ~ProModel () {}
+
+      virtual cpstr GetEntryID () { return ""; }
+      virtual void  SetEntryID ( const IDCode ) {}
+
+      virtual int   AddChain ( PChain ) { return 0; }
+
+      // returns pointer to Root
+      virtual PManager GetCoordHierarchy() { return NULL; }
+
+      //  GetNumberOfModels() returns TOTAL number of models
+      virtual int GetNumberOfModels() { return 0;    }
+
+      //  GetNumberOfAllAtoms() returns TOTAL number of atoms in
+      // all models
+      virtual int GetNumberOfAllAtoms() { return 0;    }
+
+      //  returns pointer to the general Atom array
+      virtual PPAtom     GetAllAtoms() { return NULL; }
+
+      virtual int  GetSerNum       () { return 0; }
+
+      virtual void ExpandAtomArray ( int )  {}
+      virtual void AddAtomArray    ( int )  {}
+
+    protected :
+
+      virtual int  _ExcludeChain ( const ChainID ) { return 0; }
+
+  };
+
+
+
+  //  ====================  ChainContainer  ======================
+
+  DefineClass(ChainContainer);
+  DefineStreamFunctions(ChainContainer);
+
+  class ChainContainer : public ClassContainer  {
+
+    public :
+
+      ChainContainer  () : ClassContainer () {}
+      ChainContainer  ( io::RPStream Object )
+                          : ClassContainer ( Object ) {}
+      ~ChainContainer () {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+      void  SetChain ( PChain Chain_Owner ); // must be set before using
+                                              // the Container
+
+      // special functions used in Model::GetCIF(..)
+      cpstr Get1stChainID ();
+      void  MoveByChainID ( const ChainID chainID,
+                            PChainContainer chainContainer );
+
+    protected :
+      PChain chain;
+
+  };
+
+
+  //  ==================  ContainerChain  =====================
+
+  DefineClass(ContainerChain);
+  DefineStreamFunctions(ContainerChain);
+
+  class ContainerChain : public ContainerClass {
+
+    friend class ChainContainer;
+
+    public :
+
+      ContainerChain ();
+      ContainerChain ( PChain Chain_Owner  );
+      ContainerChain ( io::RPStream Object ) : ContainerClass(Object) {}
+
+      void SetChain   ( PChain Chain_Owner );
+
+    protected :
+      PChain  chain;
+      ChainID chainID;  // just a copy of Chain->chainID
+
+  };
+
+
+  //  ==================  DBReference  ========================
+
+  DefineClass(DBReference);
+  DefineStreamFunctions(DBReference);
+
+  class DBReference : public ContainerChain  {
+
+    public :
+
+      int      seqBeg;      // initial seq num of the PDB seq-ce segment
+      InsCode  insBeg;      // initial ins code of the PDB seq-ce segm-t
+      int      seqEnd;      // ending seq number of the PDB seq-ce segm-t
+      InsCode  insEnd;      // ending ins code of the PDB seq-ce segment
+      DBName   database;    // sequence database name
+      DBAcCode dbAccession; // sequence database accession code
+      DBIdCode dbIdCode;    // sequence database identification code
+      int      dbseqBeg;    // initial seq number of the database segment
+      InsCode  dbinsBeg;    // ins code of initial residue of the segment
+      int      dbseqEnd;    // ending seq number of the database segment
+      InsCode  dbinsEnd;   // ins code of the ending residue of the seg-t
+
+      DBReference ();
+      DBReference ( PChain Chain_Owner );
+      DBReference ( PChain Chain_Owner, cpstr S );
+      DBReference ( io::RPStream Object );
+      ~DBReference();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_DBReference; }
+
+      void  Copy  ( PContainerClass DBRef );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitDBReference();
+
+  };
+
+
+  //  ====================  SeqAdv  ===========================
+
+  DefineClass(SeqAdv);
+  DefineStreamFunctions(SeqAdv);
+
+  class SeqAdv : public ContainerChain  {
+
+    public :
+
+      ResName  resName;     // residue name in conflict
+      int      seqNum;      // residue sequence number
+      InsCode  insCode;     // residue insertion code
+      DBName   database;    // sequence database name
+      DBAcCode dbAccession; // sequence database accession code
+      ResName  dbRes;       // sequence database residue name
+      int      dbSeq;       // sequence database sequence number
+      pstr     conflict;    // conflict comment
+
+      SeqAdv ();
+      SeqAdv ( PChain Chain_Owner );
+      SeqAdv ( PChain Chain_Owner, cpstr S );
+      SeqAdv ( io::RPStream Object );
+      ~SeqAdv();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_SeqAdv; }
+
+      void  Copy  ( PContainerClass seqAdv );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitSeqAdv();
+
+  };
+
+
+  //  ==================  SeqRes  ========================
+
+  DefineClass(SeqRes);
+  DefineStreamFunctions(SeqRes);
+
+  class SeqRes : public io::Stream  {
+
+    friend class Model;
+    friend class Chain;
+
+    public :
+
+      int       numRes;   // number of residues in the chain
+      PResName  resName;  // residue names
+
+      SeqRes ();
+      SeqRes ( io::RPStream Object );
+      ~SeqRes();
+
+      void       SetChain        ( PChain Chain_Owner );
+      void       PDBASCIIDump    ( io::RFile f );
+      ERROR_CODE ConvertPDBASCII ( cpstr  S );
+
+      void  MakeCIF     ( mmcif::PData CIF );
+      ERROR_CODE GetCIF ( mmcif::PData CIF );
+
+      void  Copy  ( PSeqRes seqRes );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      PChain  chain;
+      ChainID chainID;
+      int     serNum;
+
+      void InitSeqRes();
+      void FreeMemory();
+
+  };
+
+
+  //  ==================  ModRes  ========================
+
+  DefineClass(ModRes);
+  DefineStreamFunctions(ModRes);
+
+  class ModRes : public ContainerChain  {
+
+    public :
+
+      ResName  resName;     // residue name used
+      int      seqNum;      // residue sequence number
+      InsCode  insCode;     // residue insertion code
+      ResName  stdRes;      // standard residue name
+      pstr     comment;     // description of the residue modification
+
+      ModRes ();
+      ModRes ( PChain Chain_Owner );
+      ModRes ( PChain Chain_Owner, cpstr S );
+      ModRes ( io::RPStream Object );
+      ~ModRes();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_ModRes; }
+
+      void  Copy  ( PContainerClass modRes );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitModRes();
+
+  };
+
+
+  //  ==================  HetRec  ===========================
+
+  DefineClass(HetRec);
+  DefineStreamFunctions(HetRec);
+
+  class HetRec : public ContainerChain  {
+
+    public :
+
+      ResName  hetID;       // Het identifier (right-justified)
+      int      seqNum;      // sequence number
+      InsCode  insCode;     // insertion code
+      int      numHetAtoms; // number of HETATM records for the
+                            // group present in the entry
+      pstr     comment;     // text describing Het group
+
+      HetRec ();
+      HetRec ( PChain Chain_Owner );
+      HetRec ( PChain Chain_Owner, cpstr S );
+      HetRec ( io::RPStream Object );
+      ~HetRec();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_Het; }
+
+      void  Copy  ( PContainerClass Het );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitHetRec();
+
+  };
+
+
+  //  =================  Chain  =======================
+
+  DefineFactoryFunctions(Chain);
+
+  class Chain : public UDData  {
+
+    friend class DBReference;
+    friend class SeqAdv;
+    friend class SeqRes;
+    friend class ModRes;
+    friend class HetRec;
+    friend class Residue;
+    friend class Atom;
+    friend class Model;
+    friend class Root;
+    friend class SelManager;
+    friend class BondManager;
+    friend class CoorManager;
+    friend class Manager;
+
+    public :
+
+      ChainContainer DBRef;    // database reference
+      ChainContainer seqAdv;   // SEQADV records
+      SeqRes         seqRes;   // Sequence residues, SEQRES records
+      ChainContainer modRes;   // modification descriptions
+      ChainContainer Het;      // non-standard residues descriptions
+
+      Chain ();  // SetModel() MUST be used after this constructor!
+      Chain ( PProModel model, const ChainID chID );
+      Chain ( io::RPStream Object );
+      ~Chain();
+
+      void FreeAnnotations();
+
+      void SetModel ( PProModel    model );
+      void SetChain ( const ChainID chID );
+
+      PManager GetCoordHierarchy();   // PRoot
+
+      //   ConvertXXXXX(..) functions do not check for record name
+      // and assume that PDBString is at least 81 symbols long
+      // (including the terminating null).
+      ERROR_CODE ConvertDBREF  ( cpstr PDBString );
+      ERROR_CODE ConvertSEQADV ( cpstr PDBString );
+      ERROR_CODE ConvertSEQRES ( cpstr PDBString );
+      ERROR_CODE ConvertMODRES ( cpstr PDBString );
+      ERROR_CODE ConvertHET    ( cpstr PDBString );
+
+      // This function should be used for testing purposes only.
+      // A full PDB ASCII dump for all models and chains involved
+      // is done by Root class.
+      void  PDBASCIIDump     ( io::RFile f );
+
+      void  PDBASCIIAtomDump ( io::RFile f );
+      void  MakeAtomCIF      ( mmcif::PData CIF );
+
+
+      //  -----------------  Extracting residues  -------------------------
+
+      int GetNumberOfResidues(); // returns number of res-s in the chain
+      PResidue GetResidue ( int resNo );  // returns resNo-th residue
+                                          // in the chain;
+                                          // 0<=resNo<nResidues
+
+      //   GetResidue(..) returns pointer on residue, whose sequence
+      // number and insert code are given in seqNum and insCode,
+      // respectively. If such a residue is absent in the chain,
+      // returns NULL.
+      PResidue GetResidue ( int seqNum, const InsCode insCode );
+
+      //   GetResidueNo(..) returns the residue number in the chain's
+      // residues table. Residues are numbered as 0..nres-1 as they
+      // appear in the coordinate file.
+      //   If residue is not found, the function returns -1.
+      int  GetResidueNo ( int seqNum, const InsCode insCode );
+
+      void GetResidueTable ( PPResidue & resTable,
+                             int & NumberOfResidues );
+
+      //   GetResidueCreate(..) returns pointer on residue, whose name,
+      // sequence number and insertion code are given by resName, seqNum
+      // and insCode, respectively. If such a residue is absent in the
+      // chain, one is created at the end of chain.
+      //   If a residue with given sequence number and insertion code
+      // is present in the chain but has a different name, the function
+      // returns NULL unless Enforce is set True. In the latter case,
+      // a new residue is still created at the end of chain, but there
+      // is no guarantee that any function operating on the sequence
+      // number and insertion code will work properly.
+      PResidue GetResidueCreate ( const ResName resName, int seqNum,
+                                  const InsCode insCode, bool Enforce );
+
+
+      //  ------------------  Deleting residues  ----------------------
+
+      int  DeleteResidue ( int resNo ); // returns num of deleted res-s
+      int  DeleteResidue ( int seqNum, const InsCode insCode );
+      int  DeleteAllResidues();
+      int  DeleteSolvent    ();
+      void TrimResidueTable ();  // do not forget to call after all dels
+
+      //  -------------------  Adding residues  -----------------------
+
+      //   AddResidue(..) adds residue to the chain, InsResidue inserts
+      // the residue on the specified position of the chain (other
+      // residues are shifted up to the end of chain). Position in the
+      // chain may be specified by a serial number (that is position in
+      // the residue table) or by seqNum and insCode of one of the
+      // chain's residues (the new residue is then inserted before that
+      // one). If the chain is associated with a coordinate hierarchy,
+      // and residue 'res' is not, the latter is checked in
+      // automatically. If residue 'res' belongs to any coordinate
+      // hierarchy (even though that of the residue), it is *copied*
+      // rather than simply taken over, and is checked in.
+      //   If the chain is not associated with a coordinate hierarchy,
+      // all added residues will be checked in automatically once the
+      // chain is checked in.
+      int  AddResidue ( PResidue res );
+      int  InsResidue ( PResidue res, int pos );
+      int  InsResidue ( PResidue res, int seqNum, const InsCode insCode );
+
+      //  --------------------  Extracting atoms  ---------------------
+
+      int  GetNumberOfAtoms ( bool countTers );
+      int  GetNumberOfAtoms ( int seqNo, const InsCode insCode );
+      int  GetNumberOfAtoms ( int resNo );
+
+      PAtom GetAtom ( int            seqNo,
+                      const InsCode  insCode,
+                      const AtomName aname,
+                      const Element  elmnt,
+                      const AltLoc   aloc );
+      PAtom GetAtom ( int seqNo, const InsCode insCode, int atomNo );
+      PAtom GetAtom ( int            resNo,
+                      const AtomName aname,
+                      const Element  elmnt,
+                      const AltLoc   aloc );
+      PAtom GetAtom ( int resNo, int atomNo );
+
+      void GetAtomTable ( int seqNo, const InsCode insCode,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int resNo,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+
+      //   GetAtomTable1(..) returns atom table without TER atoms and
+      // without NULL atom pointers. NumberOfAtoms returns the actual
+      // number of atom pointers in atomTable.
+      //   atomTable is allocated withing the function. If it was
+      // not set to NULL before calling the function, the latter will
+      // attempt to deallocate it first.
+      //   The application is responsible for deleting atomTable,
+      // however it must not touch atom pointers, i.e. use simply
+      // "delete[] atomTable;". Never pass atomTable from
+      // GetAtomTable(..) into this function, unless you set it to NULL
+      // before doing that.
+      void GetAtomTable1 ( int seqNo, const InsCode insCode,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int resNo,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+
+      //  ---------------------  Deleting atoms  ----------------------
+
+      int DeleteAtom ( int            seqNo,
+                       const InsCode  insCode,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int            seqNo,
+                       const InsCode  insCode,
+                       int            atomNo );
+      int DeleteAtom ( int            resNo,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int resNo, int atomNo );
+
+      int DeleteAllAtoms ( int seqNo, const InsCode insCode );
+      int DeleteAllAtoms ( int resNo );
+      int DeleteAllAtoms ();
+
+      //  DeleteAltLocs() leaves only alternative location with maximal
+      // occupancy, if those are equal or unspecified, the one with
+      // "least" alternative location indicator.
+      //  The function returns the number of deleted. All tables remain
+      // untrimmed, so that explicit trimming or calling
+      // FinishStructEdit() is required.
+      int DeleteAltLocs();
+
+      //  ----------------------  Adding atoms  -----------------------
+
+      int AddAtom ( int seqNo, const InsCode insCode, PAtom atom );
+      int AddAtom ( int resNo, PAtom atom );
+
+      //  -------------------------------------------------------------
+
+      void  ApplyTransform ( mat44 & TMatrix );  // transforms all
+                                           // coordinates by multiplying
+                                           // with matrix TMatrix
+
+      int    GetModelNum();
+      PModel GetModel () { return (PModel)model; }
+      cpstr  GetChainID () { return chainID; }
+      void   SetChainID ( const ChainID chID );
+      cpstr  GetChainID ( pstr  ChID );  // returns /m/c
+
+      void  GetAtomStatistics ( RAtomStat AS );
+      void  CalAtomStatistics ( RAtomStat AS );
+
+      int   CheckID    ( const ChainID chID );
+      int   CheckIDS   ( cpstr CID  );
+
+      cpstr GetEntryID ();
+      void  SetEntryID ( const IDCode idCode );
+
+      int   GetNumberOfDBRefs ();
+      PDBReference  GetDBRef ( int dbRefNo );  // 0..nDBRefs-1
+
+      void  MaskAtoms      ( PMask Mask );
+      void  MaskResidues   ( PMask Mask );
+      void  UnmaskAtoms    ( PMask Mask );
+      void  UnmaskResidues ( PMask Mask );
+
+      void  SortResidues   ();
+
+      int      GetNofModResidues();
+      PModRes  GetModResidue    ( int modResNo );  // 0.. on
+
+      bool   isSolventChain   ();
+      bool   isInSelection    ( int selHnd );
+      bool   isAminoacidChain ();
+      bool   isNucleotideChain();
+
+
+      // -------  user-defined data handlers
+      int   PutUDData ( int UDDhandle, int      iudd );
+      int   PutUDData ( int UDDhandle, realtype rudd );
+      int   PutUDData ( int UDDhandle, cpstr    sudd );
+
+      int   GetUDData ( int UDDhandle, int      & iudd );
+      int   GetUDData ( int UDDhandle, realtype & rudd );
+      int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+      int   GetUDData ( int UDDhandle, pstr     & sudd );
+
+      void  Copy            ( PChain chain );
+      void  CopyAnnotations ( PChain chain );
+
+      void  write ( io::RFile f );    // writes header to PDB binary file
+      void  read  ( io::RFile f );    // reads header from PDB binary file
+
+    protected :
+
+      ChainID    chainID;     // chain ID
+      ChainID    prevChainID; // if chain is renamed, its original
+                              // name may be saved here.
+      PProModel  model;       // pointer to model class
+
+      int        nWeights;    // used externally for sorting
+      realtype   Weight;      //   chains
+
+      int        nResidues;   // number of residues
+      PPResidue  residue;     // array of residues
+
+      bool       Exclude;     // used internally
+
+      void  InitChain ();
+      void  FreeMemory();
+
+      void  ExpandResidueArray ( int inc );
+      //   _ExcludeResidue(..) excludes (but does not dispose!) a residue
+      // from the chain. Returns 1 if the chain gets empty and 0
+      // otherwise.
+      int   _ExcludeResidue ( const ResName resName, int seqNum,
+                              const InsCode insCode );
+      void  _copy ( PChain chain );
+      void  _copy ( PChain chain, PPAtom atom, int & atom_index );
+      void  CheckInAtoms();
+
+    private :
+      int  resLen;      // length of Residue array
+
+  };
+
+
+  extern void  TestChain();  //  reads from 'in.chain', writes into
+                             //  'out.chain' and 'abin.chain'
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_cifdefs.cpp b/mmdb2/mmdb_cifdefs.cpp
new file mode 100644
index 0000000..270a0ad
--- /dev/null
+++ b/mmdb2/mmdb_cifdefs.cpp
@@ -0,0 +1,369 @@
+//  $Id: mmdb_cifdefs.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    21.11.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_Defs <implementation>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Namespace:  mmdb::
+//
+//      CIF Definitions
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include "mmdb_cifdefs.h"
+
+namespace mmdb  {
+
+  // ------------------------------------------------------------------
+
+  cpstr CIFName ( int NameID, CIF_MODE Mode )  {
+  //  Gives CIF name according to CIF Mode.
+
+    switch (Mode)  {
+
+      case CIF_NDB :
+
+        switch (NameID)  {
+          case CAT_POLY_SEQ_SCHEME        :
+                    return CIFCAT_NDB_POLY_SEQ_SCHEME;
+          case TAG_ID_CODE                :
+                    return CIFTAG_NDB_PDB_ID_CODE;
+          case TAG_CHAIN_ID               :
+                    return CIFTAG_NDB_CHAIN_ID;
+          case TAG_SEQ_ALIGN_BEG          :
+                    return CIFTAG_SEQ_ALIGN_BEG;
+          case TAG_SEQ_ALIGN_BEG_INS_CODE :
+                    return CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE;
+          case TAG_SEQ_ALIGN_END          :
+                    return CIFTAG_SEQ_ALIGN_END;
+          case TAG_SEQ_ALIGN_END_INS_CODE :
+                    return CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE;
+          case TAG_DB_ACCESSION           :
+                    return CIFTAG_NDB_DB_ACCESSION;
+          case TAG_DB_ALIGN_BEG           :
+                    return CIFTAG_DB_ALIGN_BEG;
+          case TAG_DB_ALIGN_BEG_INS_CODE  :
+                    return CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE;
+          case TAG_DB_ALIGN_END           :
+                    return CIFTAG_DB_ALIGN_END;
+          case TAG_DB_ALIGN_END_INS_CODE  :
+                    return CIFTAG_NDB_DB_ALIGN_END_INS_CODE;
+          case TAG_SEQ_CHAIN_ID           :
+                    return CIFTAG_ID;
+          default : return pstr("ERROR_IN_CIF_NAME_1");
+        }
+
+      case CIF_PDBX :
+
+        switch (NameID)  {
+          case CAT_POLY_SEQ_SCHEME        :
+                    return CIFCAT_PDBX_POLY_SEQ_SCHEME;
+          case TAG_ID_CODE                :
+                    return CIFTAG_PDBX_PDB_ID_CODE;
+          case TAG_CHAIN_ID               :
+                    return CIFTAG_PDBX_STRAND_ID;
+          case TAG_SEQ_ALIGN_BEG          :
+                    return CIFTAG_SEQ_ALIGN_BEG;
+          case TAG_SEQ_ALIGN_BEG_INS_CODE :
+                    return CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE;
+          case TAG_SEQ_ALIGN_END          :
+                    return CIFTAG_SEQ_ALIGN_END;
+          case TAG_SEQ_ALIGN_END_INS_CODE :
+                    return CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE;
+          case TAG_DB_ACCESSION           :
+                    return CIFTAG_PDBX_DB_ACCESSION;
+          case TAG_DB_ALIGN_BEG           :
+                    return CIFTAG_DB_ALIGN_BEG;
+          case TAG_DB_ALIGN_BEG_INS_CODE  :
+                    return CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE;
+          case TAG_DB_ALIGN_END           :
+                    return CIFTAG_DB_ALIGN_END;
+          case TAG_DB_ALIGN_END_INS_CODE  :
+                    return CIFTAG_PDBX_DB_ALIGN_END_INS_CODE;
+          case TAG_SEQ_CHAIN_ID           :
+                    return CIFTAG_ASYM_ID;
+          default : return pstr("ERROR_IN_CIF_NAME_2");
+        }
+
+      default : return pstr("ERROR_IN_CIF_NAME_3");
+
+    }
+
+  }
+
+  cpstr CIFCAT_ATOM_SITE                  = cpstr("_atom_site");
+  cpstr CIFCAT_ATOM_SITE_ANISOTROP        = cpstr("_atom_site_anisotrop");
+  cpstr CIFCAT_ATOM_SITES                 = cpstr("_atom_sites");
+  cpstr CIFCAT_AUDIT_AUTHOR               = cpstr("_audit_author");
+  cpstr CIFCAT_CELL                       = cpstr("_cell");
+  cpstr CIFCAT_CHEM_COMP                  = cpstr("_chem_comp");
+  cpstr CIFCAT_CITATION                   = cpstr("_citation");
+  cpstr CIFCAT_DATABASE                   = cpstr("_database");
+  cpstr CIFCAT_DATABASE_PDB_CAVEAT        = cpstr("_database_pdb_caveat");
+  cpstr CIFCAT_DATABASE_PDB_MATRIX        = cpstr("_database_pdb_matrix");
+  cpstr CIFCAT_DATABASE_PDB_REV           = cpstr("_database_pdb_rev");
+  cpstr CIFCAT_DATABASE_PDB_TVECT         = cpstr("_database_pdb_tvect");
+  cpstr CIFCAT_ENTITY                     = cpstr("_entity");
+  cpstr CIFCAT_EXPTL                      = cpstr("_exptl");
+  cpstr CIFCAT_NDB_DATABASE_REMARK        = cpstr("_ndb_database_remark");
+  cpstr CIFCAT_NDB_NONSTANDARD_LIST       = cpstr("_ndb_nonstandard_list");
+  cpstr CIFCAT_NDB_POLY_SEQ_SCHEME        = cpstr("_ndb_poly_seq_scheme");
+  cpstr CIFCAT_PDBX_POLY_SEQ_SCHEME       = cpstr("_pdbx_poly_seq_scheme");
+  cpstr CIFCAT_REFINE                     = cpstr("_refine");
+  cpstr CIFCAT_SPRSDE                     = cpstr("_ndb_database_pdb_obs_spr");
+  cpstr CIFCAT_STRUCT                     = cpstr("_struct");
+  cpstr CIFCAT_STRUCT_ASYM                = cpstr("_struct_asym");
+  cpstr CIFCAT_STRUCT_CONF                = cpstr("_struct_conf");
+  cpstr CIFCAT_STRUCT_CONN                = cpstr("_struct_conn");
+  cpstr CIFCAT_STRUCT_LINKR               = cpstr("_struct_linkr");
+  cpstr CIFCAT_STRUCT_KEYWORDS            = cpstr("_struct_keywords");
+  cpstr CIFCAT_STRUCT_NCS_OPER            = cpstr("_struct_ncs_oper");
+  cpstr CIFCAT_STRUCT_REF                 = cpstr("_struct_ref");
+  cpstr CIFCAT_STRUCT_REF_SEQ             = cpstr("_struct_ref_seq");
+  cpstr CIFCAT_STRUCT_REF_SEQ_DIF         = cpstr("_struct_ref_seq_dif");
+  cpstr CIFCAT_STRUCT_SHEET               = cpstr("_struct_sheet");
+  cpstr CIFCAT_STRUCT_SHEET_RANGE         = cpstr("_struct_sheet_range");
+  cpstr CIFCAT_STRUCT_SHEET_ORDER         = cpstr("_struct_sheet_order");
+  cpstr CIFCAT_STRUCT_SHEET_HBOND         = cpstr("_struct_sheet_hbond");
+  cpstr CIFCAT_SYMMETRY                   = cpstr("_symmetry");
+  cpstr CIFCAT_OBSLTE                     = cpstr("_ndb_database_pdb_obs_spr");
+
+
+  cpstr CIFTAG_ANGLE_ALPHA                   = cpstr("angle_alpha");
+  cpstr CIFTAG_ANGLE_BETA                    = cpstr("angle_beta");
+  cpstr CIFTAG_ANGLE_GAMMA                   = cpstr("angle_gamma");
+  cpstr CIFTAG_ASYM_ID                       = cpstr("asym_id");
+  cpstr CIFTAG_ATOM_TYPE_SYMBOL              = cpstr("atom_type_symbol");
+  cpstr CIFTAG_AUTH_ASYM_ID                  = cpstr("auth_asym_id");
+  cpstr CIFTAG_AUTH_ATOM_ID                  = cpstr("auth_atom_id");
+  cpstr CIFTAG_AUTH_COMP_ID                  = cpstr("auth_comp_id");
+  cpstr CIFTAG_AUTH_SEQ_ID                   = cpstr("auth_seq_id");
+  cpstr CIFTAG_B_ISO_OR_EQUIV                = cpstr("B_iso_or_equiv");
+  cpstr CIFTAG_B_ISO_OR_EQUIV_ESD            = cpstr("B_iso_or_equiv_esd");
+  cpstr CIFTAG_BEG_LABEL_ASYM_ID             = cpstr("beg_label_asym_id");
+  cpstr CIFTAG_BEG_LABEL_COMP_ID             = cpstr("beg_label_comp_id");
+  cpstr CIFTAG_BEG_LABEL_SEQ_ID              = cpstr("beg_label_seq_id");
+  cpstr CIFTAG_CARTN_X                       = cpstr("cartn_x");
+  cpstr CIFTAG_CARTN_X_ESD                   = cpstr("cartn_x_esd");
+  cpstr CIFTAG_CARTN_Y                       = cpstr("cartn_y");
+  cpstr CIFTAG_CARTN_Y_ESD                   = cpstr("cartn_y_esd");
+  cpstr CIFTAG_CARTN_Z                       = cpstr("cartn_z");
+  cpstr CIFTAG_CARTN_Z_ESD                   = cpstr("cartn_z_esd");
+  cpstr CIFTAG_PDBX_FORMAL_CHARGE            = cpstr("pdbx_formal_charge");
+  cpstr CIFTAG_CODE                          = cpstr("code");
+  cpstr CIFTAG_CODE_NDB                      = cpstr("code_NDB");
+  cpstr CIFTAG_CODE_PDB                      = cpstr("code_PDB");
+  cpstr CIFTAG_CONF_TYPE_ID                  = cpstr("conf_type_id");
+  cpstr CIFTAG_CONN_TYPE_ID                  = cpstr("conn_type_id");
+  cpstr CIFTAG_DATE                          = cpstr("date");
+  cpstr CIFTAG_DATE_ORIGINAL                 = cpstr("date_original");
+  cpstr CIFTAG_DB_ALIGN_BEG                  = cpstr("db_align_beg");
+  cpstr CIFTAG_DB_ALIGN_END                  = cpstr("db_align_end");
+  cpstr CIFTAG_DB_CODE                       = cpstr("db_code");
+  cpstr CIFTAG_DB_MON_ID                     = cpstr("db_mon_id");
+  cpstr CIFTAG_DB_NAME                       = cpstr("db_name");
+  cpstr CIFTAG_DETAILS                       = cpstr("details");
+  cpstr CIFTAG_END_LABEL_ASYM_ID             = cpstr("end_label_asym_id");
+  cpstr CIFTAG_END_LABEL_COMP_ID             = cpstr("end_label_comp_id");
+  cpstr CIFTAG_END_LABEL_SEQ_ID              = cpstr("end_label_seq_id");
+  cpstr CIFTAG_ENTITY_ID                     = cpstr("entity_id");
+  cpstr CIFTAG_ENTRY_ID                      = cpstr("entry_id");
+  cpstr CIFTAG_FORMULA                       = cpstr("formula");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX11         = cpstr("fract_transf_matrix[1][1]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX12         = cpstr("fract_transf_matrix[1][2]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX13         = cpstr("fract_transf_matrix[1][3]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX21         = cpstr("fract_transf_matrix[2][1]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX22         = cpstr("fract_transf_matrix[2][2]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX23         = cpstr("fract_transf_matrix[2][3]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX31         = cpstr("fract_transf_matrix[3][1]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX32         = cpstr("fract_transf_matrix[3][2]");
+  cpstr CIFTAG_FRACT_TRANSF_MATRIX33         = cpstr("fract_transf_matrix[3][3]");
+  cpstr CIFTAG_FRACT_TRANSF_VECTOR1          = cpstr("fract_transf_vector[1]");
+  cpstr CIFTAG_FRACT_TRANSF_VECTOR2          = cpstr("fract_transf_vector[2]");
+  cpstr CIFTAG_FRACT_TRANSF_VECTOR3          = cpstr("fract_transf_vector[3]");
+  cpstr CIFTAG_GROUP_PDB                     = cpstr("group_PDB" );
+  cpstr CIFTAG_ID                            = cpstr("id");
+  cpstr CIFTAG_INS_CODE                      = cpstr("ins_code");
+  cpstr CIFTAG_LABEL_ALT_ID                  = cpstr("label_alt_id");
+  cpstr CIFTAG_LABEL_ATOM_ID                 = cpstr("label_atom_id");
+  cpstr CIFTAG_LABEL_ASYM_ID                 = cpstr("label_asym_id");
+  cpstr CIFTAG_LABEL_COMP_ID                 = cpstr("label_comp_id");
+  cpstr CIFTAG_LABEL_ENTITY_ID               = cpstr("label_entity_id");
+  cpstr CIFTAG_LABEL_SEQ_ID                  = cpstr("label_seq_id");
+  cpstr CIFTAG_LENGTH_A                      = cpstr("length_a");
+  cpstr CIFTAG_LENGTH_B                      = cpstr("length_b");
+  cpstr CIFTAG_LENGTH_C                      = cpstr("length_c");
+  cpstr CIFTAG_LS_D_RES_HIGH                 = cpstr("ls_d_res_high");
+  cpstr CIFTAG_MATRIX11                      = cpstr("matrix[1][1]");
+  cpstr CIFTAG_MATRIX12                      = cpstr("matrix[1][2]");
+  cpstr CIFTAG_MATRIX13                      = cpstr("matrix[1][3]");
+  cpstr CIFTAG_MATRIX21                      = cpstr("matrix[2][1]");
+  cpstr CIFTAG_MATRIX22                      = cpstr("matrix[2][2]");
+  cpstr CIFTAG_MATRIX23                      = cpstr("matrix[2][3]");
+  cpstr CIFTAG_MATRIX31                      = cpstr("matrix[3][1]");
+  cpstr CIFTAG_MATRIX32                      = cpstr("matrix[3][2]");
+  cpstr CIFTAG_MATRIX33                      = cpstr("matrix[3][3]");
+  cpstr CIFTAG_METHOD                        = cpstr("method");
+  cpstr CIFTAG_MOD_TYPE                      = cpstr("mod_type");
+  cpstr CIFTAG_MON_ID                        = cpstr("mon_id");
+  cpstr CIFTAG_NAME                          = cpstr("name");
+  cpstr CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB    = cpstr("ndb_beg_label_ins_code_pdb");
+  cpstr CIFTAG_NDB_CHAIN_ID                  = cpstr("ndb_chain_id");
+  cpstr CIFTAG_NDB_COMPONENT_NO              = cpstr("ndb_component_no");
+  cpstr CIFTAG_NDB_DESCRIPTOR                = cpstr("ndb_descriptor");
+  cpstr CIFTAG_NDB_DB_ACCESSION              = cpstr("ndb_db_accession");
+  cpstr CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE     = cpstr("ndb_db_align_beg_ins_code");
+  cpstr CIFTAG_NDB_DB_ALIGN_END_INS_CODE     = cpstr("ndb_db_align_end_ins_code");
+  cpstr CIFTAG_NDB_END_LABEL_INS_CODE_PDB    = cpstr("ndb_end_label_ins_code_pdb");
+  //cpstr CIFTAG_NDB_INS_CODE                =   cpstr("ndb_ins_code");
+  cpstr CIFTAG_PDBX_PDB_INS_CODE             = cpstr("pdbx_PDB_ins_code");
+  cpstr CIFTAG_NDB_HELIX_CLASS_PDB           = cpstr("ndb_helix_class_pdb");
+  cpstr CIFTAG_NDB_KEYWORDS                  = cpstr("ndb_keywords");
+  cpstr CIFTAG_NDB_LABEL_ALT_ID              = cpstr("ndb_label_alt_id");
+  cpstr CIFTAG_NDB_LABEL_ATOM_ID             = cpstr("ndb_label_atom_id");
+  cpstr CIFTAG_NDB_LABEL_ASYM_ID             = cpstr("ndb_label_asym_id");
+  cpstr CIFTAG_NDB_LABEL_COMP_ID             = cpstr("ndb_label_comp_id");
+  cpstr CIFTAG_NDB_LABEL_INS_CODE            = cpstr("ndb_label_ins_code");
+  cpstr CIFTAG_NDB_LABEL_SEQ_NUM             = cpstr("ndb_label_seq_num");
+  cpstr CIFTAG_NDB_LENGTH                    = cpstr("ndb_length");
+  cpstr CIFTAG_NDB_MODEL                     = cpstr("ndb_model");
+  cpstr CIFTAG_NDB_PDB_CHAIN_ID              = cpstr("ndb_pdb_chain_id");
+  cpstr CIFTAG_NDB_PDB_ID                    = cpstr("ndb_pdb_id");
+  cpstr CIFTAG_NDB_PDB_ID_CODE               = cpstr("ndb_pdb_id_code");
+  cpstr CIFTAG_NDB_PDB_INS_CODE              = cpstr("ndb_pdb_ins_code");
+  cpstr CIFTAG_NDB_PTNR1_LABEL_INS_CODE      = cpstr("ndb_ptnr1_label_ins_code");
+  cpstr CIFTAG_NDB_PTNR1_STANDARD_COMP_ID    = cpstr("ndb_ptnr1_standard_comp_id");
+  cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID = cpstr("ndb_range_1_beg_label_comp_id");
+  cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID = cpstr("ndb_range_1_beg_label_asym_id");
+  cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE= cpstr("ndb_range_1_beg_label_ins_code");
+  cpstr CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID = cpstr("ndb_range_1_end_label_comp_id");
+  cpstr CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID = cpstr("ndb_range_1_end_label_asym_id");
+  cpstr CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE= cpstr("ndb_range_1_end_label_ins_code");
+  cpstr CIFTAG_NDB_SEQ_ALIGN_BEG             = cpstr("ndb_seq_align_beg");
+  cpstr CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE    = cpstr("ndb_seq_align_beg_ins_code");
+  cpstr CIFTAG_NDB_SEQ_ALIGN_END             = cpstr("ndb_seq_align_end");
+  cpstr CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE    = cpstr("ndb_seq_align_end_ins_code");
+  cpstr CIFTAG_NDB_SEQ_DB_NAME               = cpstr("ndb_seq_db_name");
+  cpstr CIFTAG_NDB_SEQ_DB_ACCESSION_CODE     = cpstr("ndb_seq_db_accession_code");
+  cpstr CIFTAG_NDB_SEQ_DB_SEQ_NUM            = cpstr("ndb_seq_db_seq_num");
+  cpstr CIFTAG_NDB_SYNONYMS                  = cpstr("ndb_synonyms");
+  cpstr CIFTAG_NUM                           = cpstr("num");
+  cpstr CIFTAG_NUMBER_ATOMS_NH               = cpstr("number_atoms_nh");
+  cpstr CIFTAG_NUMBER_STRANDS                = cpstr("number_strands");
+  cpstr CIFTAG_OCCUPANCY                     = cpstr("occupancy");
+  cpstr CIFTAG_OCCUPANCY_ESD                 = cpstr("occupancy_esd");
+  cpstr CIFTAG_ORIGX11                       = cpstr("origx[1][1]");
+  cpstr CIFTAG_ORIGX12                       = cpstr("origx[1][2]");
+  cpstr CIFTAG_ORIGX13                       = cpstr("origx[1][3]");
+  cpstr CIFTAG_ORIGX21                       = cpstr("origx[2][1]");
+  cpstr CIFTAG_ORIGX22                       = cpstr("origx[2][2]");
+  cpstr CIFTAG_ORIGX23                       = cpstr("origx[2][3]");
+  cpstr CIFTAG_ORIGX31                       = cpstr("origx[3][1]");
+  cpstr CIFTAG_ORIGX32                       = cpstr("origx[3][2]");
+  cpstr CIFTAG_ORIGX33                       = cpstr("origx[3][3]");
+  cpstr CIFTAG_ORIGX_VECTOR1                 = cpstr("origx_vector[1]");
+  cpstr CIFTAG_ORIGX_VECTOR2                 = cpstr("origx_vector[2]");
+  cpstr CIFTAG_ORIGX_VECTOR3                 = cpstr("origx_vector[3]");
+  cpstr CIFTAG_PDB_ID                        = cpstr("pdb_id");
+  cpstr CIFTAG_PDB_MON_ID                    = cpstr("pdb_mon_id");
+  cpstr CIFTAG_PDB_STRAND_ID                 = cpstr("pdb_strand_id");
+  cpstr CIFTAG_PDBX_DB_ACCESSION             = cpstr("pdbx_db_accession");
+  cpstr CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE    = cpstr("pdbx_db_align_beg_ins_code");
+  cpstr CIFTAG_PDBX_DB_ALIGN_END_INS_CODE    = cpstr("pdbx_db_align_end_ins_code");
+  cpstr CIFTAG_PDBX_PDB_ID_CODE              = cpstr("pdbx_PDB_id_code");
+  cpstr CIFTAG_PDBX_PDB_MODEL_NUM            = cpstr("pdbx_PDB_model_num");
+  cpstr CIFTAG_PDBX_STRAND_ID                = cpstr("pdbx_strand_id");
+  cpstr CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID     = cpstr("range_1_beg_label_atom_id");
+  cpstr CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID      = cpstr("range_1_beg_label_seq_id");
+  cpstr CIFTAG_RANGE_1_END_LABEL_ATOM_ID     = cpstr("range_1_end_label_atom_id");
+  cpstr CIFTAG_RANGE_1_END_LABEL_SEQ_ID      = cpstr("range_1_end_label_seq_id");
+  cpstr CIFTAG_RANGE_ID_1                    = cpstr("range_id_1");
+  cpstr CIFTAG_RANGE_ID_2                    = cpstr("range_id_2");
+  cpstr CIFTAG_RCSB_RECORD_REVISED_1         = cpstr("rcsb_record_revised_1");
+  cpstr CIFTAG_RCSB_RECORD_REVISED_2         = cpstr("rcsb_record_revised_2");
+  cpstr CIFTAG_RCSB_RECORD_REVISED_3         = cpstr("rcsb_record_revised_3");
+  cpstr CIFTAG_RCSB_RECORD_REVISED_4         = cpstr("rcsb_record_revised_4");
+  cpstr CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE   = cpstr("pdbx_seq_align_beg_ins_code");
+  cpstr CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE   = cpstr("pdbx_seq_align_end_ins_code");
+  cpstr CIFTAG_PTNR1_LABEL_ASYM_ID           = cpstr("ptnr1_label_asym_id");
+  cpstr CIFTAG_PTNR1_LABEL_COMP_ID           = cpstr("ptnr1_label_comp_id");
+  cpstr CIFTAG_PTNR1_LABEL_SEQ_ID            = cpstr("ptnr1_label_seq_id");
+  cpstr CIFTAG_REF_ID                        = cpstr("ref_id");
+  cpstr CIFTAG_REPLACES                      = cpstr("replaces");
+  cpstr CIFTAG_REPLACE_PDB_ID                = cpstr("replace_pdb_id");
+  cpstr CIFTAG_SEGMENT_ID                    = cpstr("segment_id");
+  cpstr CIFTAG_SEQ_ALIGN_BEG                 = cpstr("seq_align_beg");
+  cpstr CIFTAG_SEQ_ALIGN_END                 = cpstr("seq_align_end");
+  cpstr CIFTAG_SEQ_NUM                       = cpstr("seq_num");
+  cpstr CIFTAG_SENSE                         = cpstr("sense");
+  cpstr CIFTAG_SHEET_ID                      = cpstr("sheet_id");
+  cpstr CIFTAG_SOURCE                        = cpstr("source");
+  cpstr CIFTAG_SPACE_GROUP_NAME_H_M          = cpstr("space_group_name_H-M");
+  cpstr CIFTAG_TEXT                          = cpstr("text");
+  cpstr CIFTAG_TITLE                         = cpstr("title");
+  cpstr CIFTAG_TYPE                          = cpstr("type");
+  cpstr CIFTAG_TYPE_SYMBOL                   = cpstr("type_symbol");
+  cpstr CIFTAG_VECTOR1                       = cpstr("vector[1]");
+  cpstr CIFTAG_VECTOR2                       = cpstr("vector[2]");
+  cpstr CIFTAG_VECTOR3                       = cpstr("vector[3]");
+  cpstr CIFTAG_U11                           = cpstr("u[1][1]");
+  cpstr CIFTAG_U11_ESD                       = cpstr("u[1][1]_esd");
+  cpstr CIFTAG_U12                           = cpstr("u[1][2]");
+  cpstr CIFTAG_U12_ESD                       = cpstr("u[1][2]_esd");
+  cpstr CIFTAG_U13                           = cpstr("u[1][3]");
+  cpstr CIFTAG_U13_ESD                       = cpstr("u[1][3]_esd");
+  cpstr CIFTAG_U22                           = cpstr("u[2][2]");
+  cpstr CIFTAG_U22_ESD                       = cpstr("u[2][2]_esd");
+  cpstr CIFTAG_U23                           = cpstr("u[2][3]");
+  cpstr CIFTAG_U23_ESD                       = cpstr("u[2][3]_esd");
+  cpstr CIFTAG_U33                           = cpstr("u[3][3]");
+  cpstr CIFTAG_U33_ESD                       = cpstr("u[3][3]_esd");
+  cpstr CIFTAG_Z_PDB                         = cpstr("z_pdb");
+
+  cpstr CIFTAG_CONN_PTNR1_AUTH_ATOM_ID       = cpstr("ptnr1_auth_atom_id");
+  cpstr CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID   = cpstr("pdbx_ptnr1_auth_alt_id");
+  cpstr CIFTAG_CONN_PTNR1_AUTH_COMP_ID       = cpstr("ptnr1_auth_comp_id");
+  cpstr CIFTAG_CONN_PTNR1_AUTH_ASYM_ID       = cpstr("ptnr1_auth_asym_id");
+  cpstr CIFTAG_CONN_PTNR1_AUTH_SEQ_ID        = cpstr("ptnr1_auth_seq_id");
+  cpstr CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE  = cpstr("pdbx_ptnr1_PDB_ins_code");
+  cpstr CIFTAG_CONN_DIST                     = cpstr("link_dist");
+  cpstr CIFTAG_CONN_PTNR2_AUTH_ATOM_ID       = cpstr("ptnr2_auth_atom_id");
+  cpstr CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID   = cpstr("pdbx_ptnr2_auth_alt_id");
+  cpstr CIFTAG_CONN_PTNR2_AUTH_COMP_ID       = cpstr("ptnr2_auth_comp_id");
+  cpstr CIFTAG_CONN_PTNR2_AUTH_ASYM_ID       = cpstr("ptnr2_auth_asym_id");
+  cpstr CIFTAG_CONN_PTNR2_AUTH_SEQ_ID        = cpstr("ptnr2_auth_seq_id");
+  cpstr CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE  = cpstr("pdbx_ptnr2_PDB_ins_code");
+  cpstr CIFTAG_CONN_PTNR1_SYMMETRY           = cpstr("ptnr1_symmetry");
+  cpstr CIFTAG_CONN_PTNR2_SYMMETRY           = cpstr("ptnr2_symmetry");
+  cpstr CIFTAG_CONN_NAME                     = cpstr("link_name");
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_cifdefs.h b/mmdb2/mmdb_cifdefs.h
new file mode 100644
index 0000000..2185b85
--- /dev/null
+++ b/mmdb2/mmdb_cifdefs.h
@@ -0,0 +1,329 @@
+//  $Id: mmdb_cifdefs.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    21.11.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_Defs <interface>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Namespace:  mmdb::
+//
+//      CIF Definitions
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_CIFDefs__
+#define __MMDB_CIFDefs__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  // ------------------------------------------------------------------
+
+  //  Mode IDs
+
+  enum CIF_MODE  {
+    CIF_NDB  = 0,
+    CIF_PDBX = 1
+  };
+
+  //  CIF IDs for mode-dependent CIF names
+
+  enum CIF_ID  {
+    CAT_POLY_SEQ_SCHEME        =   1,
+    TAG_CHAIN_ID               = 101,
+    TAG_DB_ACCESSION           = 102,
+    TAG_DB_ALIGN_BEG           = 103,
+    TAG_DB_ALIGN_BEG_INS_CODE  = 104,
+    TAG_DB_ALIGN_END           = 105,
+    TAG_DB_ALIGN_END_INS_CODE  = 106,
+    TAG_ID_CODE                = 107,
+    TAG_SEQ_CHAIN_ID           = 108,
+    TAG_SEQ_ALIGN_BEG          = 109,
+    TAG_SEQ_ALIGN_BEG_INS_CODE = 110,
+    TAG_SEQ_ALIGN_END          = 111,
+    TAG_SEQ_ALIGN_END_INS_CODE = 112
+  };
+
+  //  CIFName(..) gives CIF name according to CIF Mode.
+  extern cpstr CIFName ( int NameID, CIF_MODE Mode );
+
+  // ------------------------------------------------------------------
+
+  extern cpstr CIFCAT_ATOM_SITE                  ;
+  extern cpstr CIFCAT_ATOM_SITE_ANISOTROP        ;
+  extern cpstr CIFCAT_ATOM_SITES                 ;
+  extern cpstr CIFCAT_AUDIT_AUTHOR               ;
+  extern cpstr CIFCAT_CELL                       ;
+  extern cpstr CIFCAT_CHEM_COMP                  ;
+  extern cpstr CIFCAT_CITATION                   ;
+  extern cpstr CIFCAT_DATABASE                   ;
+  extern cpstr CIFCAT_DATABASE_PDB_CAVEAT        ;
+  extern cpstr CIFCAT_DATABASE_PDB_MATRIX        ;
+  extern cpstr CIFCAT_DATABASE_PDB_REV           ;
+  extern cpstr CIFCAT_DATABASE_PDB_TVECT         ;
+  extern cpstr CIFCAT_ENTITY                     ;
+  extern cpstr CIFCAT_EXPTL                      ;
+  extern cpstr CIFCAT_NDB_DATABASE_REMARK        ;
+  extern cpstr CIFCAT_NDB_NONSTANDARD_LIST       ;
+  extern cpstr CIFCAT_NDB_POLY_SEQ_SCHEME        ;
+  extern cpstr CIFCAT_PDBX_POLY_SEQ_SCHEME       ;
+  extern cpstr CIFCAT_REFINE                     ;
+  extern cpstr CIFCAT_SPRSDE                     ;
+  extern cpstr CIFCAT_STRUCT                     ;
+  extern cpstr CIFCAT_STRUCT_ASYM                ;
+  extern cpstr CIFCAT_STRUCT_CONF                ;
+  extern cpstr CIFCAT_STRUCT_CONN                ;
+  extern cpstr CIFCAT_STRUCT_LINKR               ;
+  extern cpstr CIFCAT_STRUCT_KEYWORDS            ;
+  extern cpstr CIFCAT_STRUCT_NCS_OPER            ;
+  extern cpstr CIFCAT_STRUCT_REF                 ;
+  extern cpstr CIFCAT_STRUCT_REF_SEQ             ;
+  extern cpstr CIFCAT_STRUCT_REF_SEQ_DIF         ;
+  extern cpstr CIFCAT_STRUCT_SHEET               ;
+  extern cpstr CIFCAT_STRUCT_SHEET_RANGE         ;
+  extern cpstr CIFCAT_STRUCT_SHEET_ORDER         ;
+  extern cpstr CIFCAT_STRUCT_SHEET_HBOND         ;
+  extern cpstr CIFCAT_SYMMETRY                   ;
+  extern cpstr CIFCAT_OBSLTE                     ;
+
+
+  extern cpstr CIFTAG_ANGLE_ALPHA                   ;
+  extern cpstr CIFTAG_ANGLE_BETA                    ;
+  extern cpstr CIFTAG_ANGLE_GAMMA                   ;
+  extern cpstr CIFTAG_ASYM_ID                       ;
+  extern cpstr CIFTAG_ATOM_TYPE_SYMBOL              ;
+  extern cpstr CIFTAG_AUTH_ASYM_ID                  ;
+  extern cpstr CIFTAG_AUTH_ATOM_ID                  ;
+  extern cpstr CIFTAG_AUTH_COMP_ID                  ;
+  extern cpstr CIFTAG_AUTH_SEQ_ID                   ;
+  extern cpstr CIFTAG_B_ISO_OR_EQUIV                ;
+  extern cpstr CIFTAG_B_ISO_OR_EQUIV_ESD            ;
+  extern cpstr CIFTAG_BEG_LABEL_ASYM_ID             ;
+  extern cpstr CIFTAG_BEG_LABEL_COMP_ID             ;
+  extern cpstr CIFTAG_BEG_LABEL_SEQ_ID              ;
+  extern cpstr CIFTAG_CARTN_X                       ;
+  extern cpstr CIFTAG_CARTN_X_ESD                   ;
+  extern cpstr CIFTAG_CARTN_Y                       ;
+  extern cpstr CIFTAG_CARTN_Y_ESD                   ;
+  extern cpstr CIFTAG_CARTN_Z                       ;
+  extern cpstr CIFTAG_CARTN_Z_ESD                   ;
+  extern cpstr CIFTAG_PDBX_FORMAL_CHARGE            ;
+  extern cpstr CIFTAG_CODE                          ;
+  extern cpstr CIFTAG_CODE_NDB                      ;
+  extern cpstr CIFTAG_CODE_PDB                      ;
+  extern cpstr CIFTAG_CONF_TYPE_ID                  ;
+  extern cpstr CIFTAG_CONN_TYPE_ID                  ;
+  extern cpstr CIFTAG_DATE                          ;
+  extern cpstr CIFTAG_DATE_ORIGINAL                 ;
+  extern cpstr CIFTAG_DB_ALIGN_BEG                  ;
+  extern cpstr CIFTAG_DB_ALIGN_END                  ;
+  extern cpstr CIFTAG_DB_CODE                       ;
+  extern cpstr CIFTAG_DB_MON_ID                     ;
+  extern cpstr CIFTAG_DB_NAME                       ;
+  extern cpstr CIFTAG_DETAILS                       ;
+  extern cpstr CIFTAG_END_LABEL_ASYM_ID             ;
+  extern cpstr CIFTAG_END_LABEL_COMP_ID             ;
+  extern cpstr CIFTAG_END_LABEL_SEQ_ID              ;
+  extern cpstr CIFTAG_ENTITY_ID                     ;
+  extern cpstr CIFTAG_ENTRY_ID                      ;
+  extern cpstr CIFTAG_FORMULA                       ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX11         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX12         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX13         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX21         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX22         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX23         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX31         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX32         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_MATRIX33         ;
+  extern cpstr CIFTAG_FRACT_TRANSF_VECTOR1          ;
+  extern cpstr CIFTAG_FRACT_TRANSF_VECTOR2          ;
+  extern cpstr CIFTAG_FRACT_TRANSF_VECTOR3          ;
+  extern cpstr CIFTAG_GROUP_PDB                     ;
+  extern cpstr CIFTAG_ID                            ;
+  extern cpstr CIFTAG_INS_CODE                      ;
+  extern cpstr CIFTAG_LABEL_ALT_ID                  ;
+  extern cpstr CIFTAG_LABEL_ATOM_ID                 ;
+  extern cpstr CIFTAG_LABEL_ASYM_ID                 ;
+  extern cpstr CIFTAG_LABEL_COMP_ID                 ;
+  extern cpstr CIFTAG_LABEL_ENTITY_ID               ;
+  extern cpstr CIFTAG_LABEL_SEQ_ID                  ;
+  extern cpstr CIFTAG_LENGTH_A                      ;
+  extern cpstr CIFTAG_LENGTH_B                      ;
+  extern cpstr CIFTAG_LENGTH_C                      ;
+  extern cpstr CIFTAG_LS_D_RES_HIGH                 ;
+  extern cpstr CIFTAG_MATRIX11                      ;
+  extern cpstr CIFTAG_MATRIX12                      ;
+  extern cpstr CIFTAG_MATRIX13                      ;
+  extern cpstr CIFTAG_MATRIX21                      ;
+  extern cpstr CIFTAG_MATRIX22                      ;
+  extern cpstr CIFTAG_MATRIX23                      ;
+  extern cpstr CIFTAG_MATRIX31                      ;
+  extern cpstr CIFTAG_MATRIX32                      ;
+  extern cpstr CIFTAG_MATRIX33                      ;
+  extern cpstr CIFTAG_METHOD                        ;
+  extern cpstr CIFTAG_MOD_TYPE                      ;
+  extern cpstr CIFTAG_MON_ID                        ;
+  extern cpstr CIFTAG_NAME                          ;
+  extern cpstr CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB    ;
+  extern cpstr CIFTAG_NDB_CHAIN_ID                  ;
+  extern cpstr CIFTAG_NDB_COMPONENT_NO              ;
+  extern cpstr CIFTAG_NDB_DESCRIPTOR                ;
+  extern cpstr CIFTAG_NDB_DB_ACCESSION              ;
+  extern cpstr CIFTAG_NDB_DB_ALIGN_BEG_INS_CODE     ;
+  extern cpstr CIFTAG_NDB_DB_ALIGN_END_INS_CODE     ;
+  extern cpstr CIFTAG_NDB_END_LABEL_INS_CODE_PDB    ;
+  extern cpstr CIFTAG_PDBX_PDB_INS_CODE             ;
+  extern cpstr CIFTAG_NDB_HELIX_CLASS_PDB           ;
+  extern cpstr CIFTAG_NDB_KEYWORDS                  ;
+  extern cpstr CIFTAG_NDB_LABEL_ALT_ID              ;
+  extern cpstr CIFTAG_NDB_LABEL_ATOM_ID             ;
+  extern cpstr CIFTAG_NDB_LABEL_ASYM_ID             ;
+  extern cpstr CIFTAG_NDB_LABEL_COMP_ID             ;
+  extern cpstr CIFTAG_NDB_LABEL_INS_CODE            ;
+  extern cpstr CIFTAG_NDB_LABEL_SEQ_NUM             ;
+  extern cpstr CIFTAG_NDB_LENGTH                    ;
+  extern cpstr CIFTAG_NDB_MODEL                     ;
+  extern cpstr CIFTAG_NDB_PDB_CHAIN_ID              ;
+  extern cpstr CIFTAG_NDB_PDB_ID                    ;
+  extern cpstr CIFTAG_NDB_PDB_ID_CODE               ;
+  extern cpstr CIFTAG_NDB_PDB_INS_CODE              ;
+  extern cpstr CIFTAG_NDB_PTNR1_LABEL_INS_CODE      ;
+  extern cpstr CIFTAG_NDB_PTNR1_STANDARD_COMP_ID    ;
+  extern cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID ;
+  extern cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID ;
+  extern cpstr CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE;
+  extern cpstr CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID ;
+  extern cpstr CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID ;
+  extern cpstr CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE;
+  extern cpstr CIFTAG_NDB_SEQ_ALIGN_BEG             ;
+  extern cpstr CIFTAG_NDB_SEQ_ALIGN_BEG_INS_CODE    ;
+  extern cpstr CIFTAG_NDB_SEQ_ALIGN_END             ;
+  extern cpstr CIFTAG_NDB_SEQ_ALIGN_END_INS_CODE    ;
+  extern cpstr CIFTAG_NDB_SEQ_DB_NAME               ;
+  extern cpstr CIFTAG_NDB_SEQ_DB_ACCESSION_CODE     ;
+  extern cpstr CIFTAG_NDB_SEQ_DB_SEQ_NUM            ;
+  extern cpstr CIFTAG_NDB_SYNONYMS                  ;
+  extern cpstr CIFTAG_NUM                           ;
+  extern cpstr CIFTAG_NUMBER_ATOMS_NH               ;
+  extern cpstr CIFTAG_NUMBER_STRANDS                ;
+  extern cpstr CIFTAG_OCCUPANCY                     ;
+  extern cpstr CIFTAG_OCCUPANCY_ESD                 ;
+  extern cpstr CIFTAG_ORIGX11                       ;
+  extern cpstr CIFTAG_ORIGX12                       ;
+  extern cpstr CIFTAG_ORIGX13                       ;
+  extern cpstr CIFTAG_ORIGX21                       ;
+  extern cpstr CIFTAG_ORIGX22                       ;
+  extern cpstr CIFTAG_ORIGX23                       ;
+  extern cpstr CIFTAG_ORIGX31                       ;
+  extern cpstr CIFTAG_ORIGX32                       ;
+  extern cpstr CIFTAG_ORIGX33                       ;
+  extern cpstr CIFTAG_ORIGX_VECTOR1                 ;
+  extern cpstr CIFTAG_ORIGX_VECTOR2                 ;
+  extern cpstr CIFTAG_ORIGX_VECTOR3                 ;
+  extern cpstr CIFTAG_PDB_ID                        ;
+  extern cpstr CIFTAG_PDB_MON_ID                    ;
+  extern cpstr CIFTAG_PDB_STRAND_ID                 ;
+  extern cpstr CIFTAG_PDBX_DB_ACCESSION             ;
+  extern cpstr CIFTAG_PDBX_DB_ALIGN_BEG_INS_CODE    ;
+  extern cpstr CIFTAG_PDBX_DB_ALIGN_END_INS_CODE    ;
+  extern cpstr CIFTAG_PDBX_PDB_ID_CODE              ;
+  extern cpstr CIFTAG_PDBX_PDB_MODEL_NUM            ;
+  extern cpstr CIFTAG_PDBX_STRAND_ID                ;
+  extern cpstr CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID     ;
+  extern cpstr CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID      ;
+  extern cpstr CIFTAG_RANGE_1_END_LABEL_ATOM_ID     ;
+  extern cpstr CIFTAG_RANGE_1_END_LABEL_SEQ_ID      ;
+  extern cpstr CIFTAG_RANGE_ID_1                    ;
+  extern cpstr CIFTAG_RANGE_ID_2                    ;
+  extern cpstr CIFTAG_RCSB_RECORD_REVISED_1         ;
+  extern cpstr CIFTAG_RCSB_RECORD_REVISED_2         ;
+  extern cpstr CIFTAG_RCSB_RECORD_REVISED_3         ;
+  extern cpstr CIFTAG_RCSB_RECORD_REVISED_4         ;
+  extern cpstr CIFTAG_PDBX_SEQ_ALIGN_BEG_INS_CODE   ;
+  extern cpstr CIFTAG_PDBX_SEQ_ALIGN_END_INS_CODE   ;
+  extern cpstr CIFTAG_PTNR1_LABEL_ASYM_ID           ;
+  extern cpstr CIFTAG_PTNR1_LABEL_COMP_ID           ;
+  extern cpstr CIFTAG_PTNR1_LABEL_SEQ_ID            ;
+  extern cpstr CIFTAG_REF_ID                        ;
+  extern cpstr CIFTAG_REPLACES                      ;
+  extern cpstr CIFTAG_REPLACE_PDB_ID                ;
+  extern cpstr CIFTAG_SEGMENT_ID                    ;
+  extern cpstr CIFTAG_SEQ_ALIGN_BEG                 ;
+  extern cpstr CIFTAG_SEQ_ALIGN_END                 ;
+  extern cpstr CIFTAG_SEQ_NUM                       ;
+  extern cpstr CIFTAG_SENSE                         ;
+  extern cpstr CIFTAG_SHEET_ID                      ;
+  extern cpstr CIFTAG_SOURCE                        ;
+  extern cpstr CIFTAG_SPACE_GROUP_NAME_H_M          ;
+  extern cpstr CIFTAG_TEXT                          ;
+  extern cpstr CIFTAG_TITLE                         ;
+  extern cpstr CIFTAG_TYPE                          ;
+  extern cpstr CIFTAG_TYPE_SYMBOL                   ;
+  extern cpstr CIFTAG_VECTOR1                       ;
+  extern cpstr CIFTAG_VECTOR2                       ;
+  extern cpstr CIFTAG_VECTOR3                       ;
+  extern cpstr CIFTAG_U11                           ;
+  extern cpstr CIFTAG_U11_ESD                       ;
+  extern cpstr CIFTAG_U12                           ;
+  extern cpstr CIFTAG_U12_ESD                       ;
+  extern cpstr CIFTAG_U13                           ;
+  extern cpstr CIFTAG_U13_ESD                       ;
+  extern cpstr CIFTAG_U22                           ;
+  extern cpstr CIFTAG_U22_ESD                       ;
+  extern cpstr CIFTAG_U23                           ;
+  extern cpstr CIFTAG_U23_ESD                       ;
+  extern cpstr CIFTAG_U33                           ;
+  extern cpstr CIFTAG_U33_ESD                       ;
+  extern cpstr CIFTAG_Z_PDB                         ;
+
+  extern cpstr CIFTAG_CONN_PTNR1_AUTH_ATOM_ID       ;
+  extern cpstr CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID   ;
+  extern cpstr CIFTAG_CONN_PTNR1_AUTH_COMP_ID       ;
+  extern cpstr CIFTAG_CONN_PTNR1_AUTH_ASYM_ID       ;
+  extern cpstr CIFTAG_CONN_PTNR1_AUTH_SEQ_ID        ;
+  extern cpstr CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE  ;
+  extern cpstr CIFTAG_CONN_DIST                     ;
+  extern cpstr CIFTAG_CONN_PTNR2_AUTH_ATOM_ID       ;
+  extern cpstr CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID   ;
+  extern cpstr CIFTAG_CONN_PTNR2_AUTH_COMP_ID       ;
+  extern cpstr CIFTAG_CONN_PTNR2_AUTH_ASYM_ID       ;
+  extern cpstr CIFTAG_CONN_PTNR2_AUTH_SEQ_ID        ;
+  extern cpstr CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE  ;
+  extern cpstr CIFTAG_CONN_PTNR1_SYMMETRY           ;
+  extern cpstr CIFTAG_CONN_PTNR2_SYMMETRY           ;
+  extern cpstr CIFTAG_CONN_NAME                     ;
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_coormngr.cpp b/mmdb2/mmdb_coormngr.cpp
new file mode 100644
index 0000000..0ab4fbf
--- /dev/null
+++ b/mmdb2/mmdb_coormngr.cpp
@@ -0,0 +1,4347 @@
+//  $Id: mmdb_coormngr.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    14.07.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_coormngr <implementation>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Brick       ( space brick                  )
+//       ~~~~~~~~~  mmdb::CoorManager ( MMDB atom coordinate manager )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <math.h>
+#include <string.h>
+
+#include "mmdb_coormngr.h"
+#include "mmdb_math_linalg.h"
+#include "mmdb_tables.h"
+
+namespace mmdb  {
+
+  // ==========================  Brick  =============================
+
+  Brick::Brick()  {
+    InitBrick();
+  }
+
+  Brick::~Brick()  {
+    Clear();
+  }
+
+  void  Brick::InitBrick()  {
+    atom        = NULL;
+    id          = NULL;
+    nAtoms      = 0;
+    nAllocAtoms = 0;
+  }
+
+  void  Brick::Clear()  {
+    if (atom)  delete[] atom;
+    FreeVectorMemory ( id,0 );
+    atom        = NULL;
+    nAtoms      = 0;
+    nAllocAtoms = 0;
+  }
+
+  void  Brick::AddAtom ( PAtom A, int atomid )  {
+  int     i;
+  PPAtom  atom1;
+  ivector id1;
+    if (nAtoms>=nAllocAtoms)  {
+      nAllocAtoms = nAtoms+10;
+      atom1       = new PAtom[nAllocAtoms];
+      GetVectorMemory ( id1,nAllocAtoms,0 );
+      for (i=0;i<nAtoms;i++)  {
+        atom1[i] = atom[i];
+        id1  [i] = id  [i];
+      }
+      for (i=nAtoms;i<nAllocAtoms;i++)  {
+        atom1[i] = NULL;
+        id1  [i] = -1;
+      }
+      if (atom)  delete[] atom;
+      FreeVectorMemory ( id,0 );
+      atom = atom1;
+      id   = id1;
+    }
+    atom[nAtoms] = A;
+    id  [nAtoms] = atomid;
+    nAtoms++;
+  }
+
+
+  // ===========================  mbrick  =============================
+
+  MBrick::MBrick ( int nStructures )  {
+    InitMBrick ( nStructures );
+  }
+
+  MBrick::~MBrick()  {
+    Clear();
+  }
+
+  void  MBrick::InitMBrick ( int nStructures )  {
+  int i;
+    nStruct = nStructures;
+    atom   = new PPAtom[nStruct];
+    id     = new ivector[nStruct];
+    GetVectorMemory ( nAtoms,nStruct,0 );
+    GetVectorMemory ( nAlloAtoms,nStruct,0 );
+    for (i=0;i<nStruct;i++)  {
+      atom       [i] = NULL;
+      id         [i] = NULL;
+      nAtoms     [i] = 0;
+      nAlloAtoms[i] = 0;
+    }
+  }
+
+  void  MBrick::Clear()  {
+  int i;
+    if (atom)  {
+      for (i=0;i<nStruct;i++)
+        if (atom[i])  delete[] atom[i];
+      delete[] atom;
+      atom = NULL;
+    }
+    FreeMatrixMemory ( id,nStruct,0,0 );
+    FreeVectorMemory ( nAtoms,0 );
+    FreeVectorMemory ( nAlloAtoms,0 );
+    nStruct = 0;
+  }
+
+  void  MBrick::AddAtom ( PAtom A, int structNo, int atomid )  {
+  int     i,natoms,nalloc;
+  PPAtom  atom0,atom1;
+  ivector id0,id1;
+    natoms = nAtoms     [structNo];
+    nalloc = nAlloAtoms[structNo];
+    atom0  = atom       [structNo];
+    id0    = id         [structNo];
+    if (natoms>=nalloc)  {
+      nalloc = natoms+10;
+      atom1 = new PAtom[nalloc];
+      GetVectorMemory ( id1,nalloc,0 );
+      for (i=0;i<natoms;i++)  {
+        atom1[i] = atom0[i];
+        id1  [i] = id0  [i];
+      }
+      for (i=natoms;i<nalloc;i++)  {
+        atom1[i] = NULL;
+        id1  [i] = -1;
+      }
+      if (atom0)  delete[] atom0;
+      FreeVectorMemory ( id0,0 );
+      atom[structNo] = atom1;
+      id  [structNo] = id1;
+      nAlloAtoms[structNo] = nalloc;
+      atom0 = atom1;
+      id0   = id1;
+    }
+    atom0 [natoms]   = A;
+    id0   [natoms]   = atomid;
+    nAtoms[structNo] = natoms+1;
+  }
+
+
+
+  //  ====================  GenSym  ========================
+
+  GenSym::GenSym() : SymOps()  {
+    InitGenSym();
+  }
+
+  GenSym::GenSym ( io::RPStream Object ) : SymOps(Object)  {
+    InitGenSym();
+  }
+
+  GenSym::~GenSym()  {}  // virtual FreeMmeory is called by ~SymOps()
+
+  void GenSym::InitGenSym()  {
+    chID1    = NULL;
+    chID2    = NULL;
+    nChains  = NULL;
+    nOpAlloc = 0;
+  }
+
+  void GenSym::FreeMemory()  {
+  int i;
+    for (i=0;i<nOpAlloc;i++)  {
+      if (chID1[i]) delete[] chID1[i];
+      if (chID2[i]) delete[] chID2[i];
+    }
+    if (chID1) delete[] chID1;
+    if (chID2) delete[] chID2;
+    FreeVectorMemory ( nChains,0 );
+    nOpAlloc = 0;
+    SymOps::FreeMemory();
+  }
+
+  int GenSym::AddSymOp ( cpstr XYZOperation )  {
+  int        RC,i;
+  PChainID * ch1ID;
+  PChainID * ch2ID;
+  ivector    nChains1;
+
+    RC = SymOps::AddSymOp ( XYZOperation );
+    if (Nops>nOpAlloc)  {
+      ch1ID = new PChainID[Nops];
+      ch2ID = new PChainID[Nops];
+      GetVectorMemory ( nChains1,Nops,0 );
+      for (i=0;i<nOpAlloc;i++)  {
+        ch1ID[i]    = chID1[i];
+        ch2ID[i]    = chID2[i];
+        nChains1[i] = nChains[i];
+      }
+      for (i=nOpAlloc;i<Nops;i++)  {
+        ch1ID[i]    = NULL;
+        ch2ID[i]    = NULL;
+        nChains1[i] = 0;
+      }
+      if (chID1)  delete[] chID1;
+      if (chID2)  delete[] chID2;
+      FreeVectorMemory ( nChains,0 );
+      chID1    = ch1ID;
+      chID2    = ch2ID;
+      nChains  = nChains1;
+      nOpAlloc = Nops;
+    }
+    return RC;
+  }
+
+  int  GenSym::AddRenChain ( int Nop, const ChainID ch1,
+                                       const ChainID ch2 )  {
+  int      i;
+  PChainID c1,c2;
+    if ((0<=Nop) && (Nop<Nops))  {
+      c1 = new ChainID[nChains[Nop]+1];
+      c2 = new ChainID[nChains[Nop]+1];
+      for (i=0;i<nChains[Nop];i++)  {
+        strcpy ( c1[i],chID1[Nop][i] );
+        strcpy ( c2[i],chID2[Nop][i] );
+      }
+      strcpy ( c1[nChains[Nop]],ch1 );
+      strcpy ( c2[nChains[Nop]],ch2 );
+      if (chID1[Nop])  delete[] chID1[Nop];
+      if (chID2[Nop])  delete[] chID2[Nop];
+      chID1[Nop] = c1;
+      chID2[Nop] = c2;
+      nChains[Nop]++;
+      return SYMOP_Ok;
+    } else
+      return SYMOP_NoSymOps;
+  }
+
+  void GenSym::Copy ( PSymOps GenSym )  {
+  int i,j;
+    SymOps::Copy ( GenSym );
+    if (Nops>0)  {
+      nOpAlloc = Nops;
+      chID1 = new PChainID[Nops];
+      chID2 = new PChainID[Nops];
+      GetVectorMemory ( nChains,Nops,0 );
+      for (i=0;i<Nops;i++)  {
+        nChains[i] = PGenSym(GenSym)->nChains[i];
+        if (nChains[i]<=0)  {
+          chID1[i] = NULL;
+          chID2[i] = NULL;
+        } else  {
+          chID1[i] = new ChainID[nChains[i]];
+          chID2[i] = new ChainID[nChains[i]];
+          for (j=0;j<nChains[i];j++)  {
+            strcpy ( chID1[i][j],PGenSym(GenSym)->chID1[i][j] );
+            strcpy ( chID2[i][j],PGenSym(GenSym)->chID2[i][j] );
+          }
+        }
+      }
+    }
+  }
+
+  void  GenSym::write ( io::RFile f )  {
+  int  i,j;
+  byte Version=1;
+    f.WriteByte ( &Version  );
+    SymOps::write ( f );
+    f.WriteInt ( &nOpAlloc );
+    for (i=0;i<nOpAlloc;i++)  {
+      f.WriteInt ( &(nChains[i]) );
+      for (j=0;j<nChains[i];j++)  {
+        f.WriteTerLine ( chID1[i][j],false );
+        f.WriteTerLine ( chID2[i][j],false );
+      }
+    }
+  }
+
+  void  GenSym::read ( io::RFile f )  {
+  int  i,j;
+  byte Version;
+    f.ReadByte ( &Version  );
+    SymOps::read ( f );
+    f.ReadInt ( &nOpAlloc );
+    if (nOpAlloc>0)  {
+      chID1 = new PChainID[nOpAlloc];
+      chID2 = new PChainID[nOpAlloc];
+      GetVectorMemory ( nChains,nOpAlloc,0 );
+      for (i=0;i<nOpAlloc;i++)  {
+        f.ReadInt ( &(nChains[i]) );
+        if (nChains[i]>0)  {
+          chID1[i] = new ChainID[nChains[i]];
+          chID2[i] = new ChainID[nChains[i]];
+          for (j=0;j<nChains[i];j++)  {
+            f.ReadTerLine ( chID1[i][j],false );
+            f.ReadTerLine ( chID2[i][j],false );
+          }
+        } else  {
+          chID1[i] = NULL;
+          chID2[i] = NULL;
+        }
+      }
+    }
+  }
+
+
+  MakeStreamFunctions(GenSym)
+
+
+
+  // =======================  ContactIndex  ==========================
+
+  void Contact::Copy ( RContact c )  {
+    id1   = c.id1;
+    id2   = c.id2;
+    group = c.group;
+    dist  = c.dist;
+  }
+
+  void Contact::Swap ( RContact c )  {
+  int      ib;
+  long     lb;
+  realtype rb;
+    ib = id1;     id1   = c.id1;     c.id1   = ib;
+    ib = id2;     id2   = c.id2;     c.id2   = ib;
+    lb = group;   group = c.group;   c.group = lb;
+    rb = dist;    dist  = c.dist;    c.dist  = rb;
+  }
+
+  DefineClass(ContactIndex)
+
+  class ContactIndex  {
+
+    friend class SelManager;
+
+    public :
+
+      ContactIndex ( PContact contact,
+                      int       maxlen,
+                      int       ncontacts,
+                      int       max_alloc );
+      ~ContactIndex();
+
+      void AddContact ( int id1, int id2,   realtype dist, int group  );
+      void GetIndex   ( RPContact contact, int & ncontacts );
+
+    protected :
+
+      PContact contact_index; // contact index
+      int      max_index;     // if <=0 then dynamical index
+                              // otherwise fixed by max_index
+      int      n_contacts;    // number of contacts
+      int      alloc_index;   // physical length of contact_index
+                              // when dynamical
+      int      alloc_max;     // physical limit on allocation
+
+  };
+
+
+  ContactIndex::ContactIndex ( PContact contact,
+                               int       maxlen,
+                               int       ncontacts,
+                               int       max_alloc )  {
+    contact_index = contact;
+    max_index     = maxlen;
+    if (!contact_index)  n_contacts = 0;
+                   else  n_contacts = IMax(0,ncontacts);
+    alloc_index = n_contacts;
+    alloc_max   = n_contacts + max_alloc;
+  }
+
+  ContactIndex::~ContactIndex() {
+    if (contact_index)  delete[] contact_index;
+    contact_index = NULL;
+    n_contacts    = 0;
+    alloc_index   = 0;
+  }
+
+  void ContactIndex::AddContact ( int id1, int id2, realtype dist,
+                                  int group )  {
+  PContact cont1;
+  int      i;
+
+    if ((alloc_max<=0) || (n_contacts<alloc_max))  {
+      if (max_index>0)  {
+        if (n_contacts<max_index)  {
+          contact_index[n_contacts].id1   = id1;
+          contact_index[n_contacts].id2   = id2;
+          contact_index[n_contacts].dist  = dist;
+          contact_index[n_contacts].group = group;
+        }
+      } else  {
+        if (n_contacts>=alloc_index)  {
+          alloc_index = n_contacts+IMax(alloc_index/4+10,10);
+          if ((alloc_max>0) && (alloc_index>alloc_max))
+            alloc_index = alloc_max;
+          cont1 = new Contact[alloc_index];
+          for (i=0;i<n_contacts;i++)
+            cont1[i].Copy ( contact_index[i] );
+          if (contact_index)  delete[] contact_index;
+          contact_index = cont1;
+        }
+        contact_index[n_contacts].id1   = id1;
+        contact_index[n_contacts].id2   = id2;
+        contact_index[n_contacts].dist  = dist;
+        contact_index[n_contacts].group = group;
+      }
+      n_contacts++;
+    }
+  }
+
+  void  ContactIndex::GetIndex ( RPContact contact, int & ncontacts )  {
+    contact       = contact_index;
+    ncontacts     = n_contacts;
+    contact_index = NULL;
+    n_contacts    = 0;
+    alloc_index   = 0;
+  }
+
+
+  // ========================  MContact  =============================
+
+  MContact::MContact ( int nStructures )  {
+  int i;
+    nStruct = nStructures;
+    if (nStruct>0)  {
+      atom = new PPAtom[nStruct];
+      id   = new ivector[nStruct];
+      GetVectorMemory ( nAtoms,nStruct,0 );
+      GetVectorMemory ( nAlloc,nStruct,0 );
+      for (i=0;i<nStruct;i++)  {
+        atom  [i] = NULL;
+        id    [i] = NULL;
+        nAtoms[i] = 0;
+        nAlloc[i] = 0;
+      }
+    } else  {
+      atom   = NULL;
+      nAtoms = NULL;
+      nAlloc = NULL;
+    }
+  }
+
+  MContact::~MContact()  {
+  int i;
+    if (atom)  {
+      for (i=0;i<nStruct;i++)
+        if (atom[i])  delete[] atom[i];
+      delete[] atom;
+      atom = NULL;
+    }
+    FreeMatrixMemory ( id,nStruct,0,0 );
+    FreeVectorMemory ( nAtoms,0 );
+    FreeVectorMemory ( nAlloc,0 );
+    nStruct = 0;
+  }
+
+  void MContact::AddContact ( PAtom A, int structNo, int atomid )  {
+  PPAtom  A1,A2;
+  ivector id1,id2;
+  int     nat,nal,i;
+    A1  = atom  [structNo];
+    id1 = id    [structNo];
+    nat = nAtoms[structNo];
+    nal = nAlloc[structNo];
+    if (nat>=nal)  {
+      nal = nat+10;
+      A2  = new PAtom[nal];
+      GetVectorMemory ( id2,nal,0 );
+      for (i=0;i<nat;i++)  {
+        A2 [i] = A1 [i];
+        id2[i] = id1[i];
+      }
+      for (i=nat;i<nal;i++)  {
+        A2 [i] = NULL;
+        id2[i] = 0;
+      }
+      if (A1)  delete[] A1;
+      FreeVectorMemory ( id1,0 );
+      atom[structNo] = A2;
+      id  [structNo] = id2;
+      A1  = A2;
+      id1 = id2;
+      nAlloc[structNo] = nal;
+    }
+    A1 [nat] = A;
+    id1[nat] = atomid;
+    nAtoms[structNo] = nat+1;
+  }
+
+
+  void  DeleteMContacts ( PPMContact & mcontact, int nContacts )  {
+  int i;
+    if (mcontact)  {
+      for (i=0;i<nContacts;i++)
+        if (mcontact[i])  delete mcontact[i];
+      delete[] mcontact;
+      mcontact = NULL;
+    }
+  }
+
+
+  //  ====================   CoorManager   =====================
+
+  CoorManager::CoorManager() : Root()  {
+    InitMMDBCoorManager();
+  }
+
+  CoorManager::CoorManager ( io::RPStream Object ) : Root(Object)  {
+    InitMMDBCoorManager();
+  }
+
+  CoorManager::~CoorManager()  {
+    RemoveBricks ();
+    RemoveMBricks();
+  }
+
+  void  CoorManager::ResetManager()  {
+    Root::ResetManager();
+    RemoveBricks       ();
+    RemoveMBricks      ();
+    InitMMDBCoorManager();
+  }
+
+  void  CoorManager::InitMMDBCoorManager()  {
+
+    CoorIDCode  = CID_Ok;
+
+    brick_size  = 6.0;  // angstroms
+    xbrick_0    = 0.0;
+    ybrick_0    = 0.0;
+    zbrick_0    = 0.0;
+    nbrick_x    = 0;
+    nbrick_y    = 0;
+    nbrick_z    = 0;
+    brick       = NULL;
+
+    mbrick_size = 6.0;  // angstroms
+    xmbrick_0   = 0.0;
+    ymbrick_0   = 0.0;
+    zmbrick_0   = 0.0;
+    nmbrick_x   = 0;
+    nmbrick_y   = 0;
+    nmbrick_z   = 0;
+    mbrick      = NULL;
+
+  }
+
+
+  int  CoorManager::SetDefaultCoorID ( cpstr CID )  {
+    return DefPath.SetPath ( CID );
+  }
+
+  PModel CoorManager::GetFirstDefinedModel()  {
+  PModel mdl;
+  int    i;
+    mdl = NULL;
+    for (i=0;(i<nModels) && (!mdl);i++)
+      mdl = model[i];
+    return mdl;
+  }
+
+  int CoorManager::GetFirstModelNum()  {
+  PModel mdl;
+  int    i;
+    mdl = NULL;
+    for (i=0;(i<nModels) && (!mdl);i++)
+      mdl = model[i];
+    if (mdl)  return mdl->GetSerNum();
+    return 1;
+  }
+
+
+  PModel CoorManager::GetModel ( int modelNo )  {
+    if ((modelNo>=1) && (modelNo<=nModels))
+          return model[modelNo-1];
+    else  return NULL;
+  }
+
+  PModel CoorManager::GetModel ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & APATH_WC_ModelNo))  {
+      CoorIDCode = CID_WrongPath;
+      return NULL;
+    }
+
+    if ((modno>=1) && (modno<=nModels))
+          return model[modno-1];
+    else  return NULL;
+
+  }
+
+  void CoorManager::GetModelTable ( PPModel & modelTable,
+                                         int & NumberOfModels )  {
+    NumberOfModels = nModels;
+    modelTable     = model;
+  }
+
+  int CoorManager::DeleteModel ( int modelNo )  {
+    if ((modelNo>=1) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        Exclude = false;
+        delete model[modelNo-1];
+        model[modelNo-1] = NULL;
+        Exclude = true;
+        return 1;
+      }
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteModel ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & APATH_WC_ModelNo))  {
+      CoorIDCode = CID_WrongPath;
+      return 0;
+    }
+
+    if ((modno>=1) && (modno<=nModels))  {
+      if (model[modno-1])  {
+        Exclude = false;
+        delete model[modno-1];
+        model[modno-1] = NULL;
+        Exclude = true;
+        return 1;
+      }
+    }
+
+    return 0;
+
+  }
+
+
+  int CoorManager::DeleteSolvent()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  {
+        k += model[i]->DeleteSolvent();
+        model[i]->TrimChainTable();
+        if (model[i]->nChains<=0)  {
+          delete model[i];
+          model[i] = NULL;
+        }
+      }
+    Exclude = true;
+    return k;
+  }
+
+
+  //  ----------------  Adding/Inserting models  ---------------
+
+  int  CoorManager::AddModel ( PModel mdl )  {
+  PPModel model1;
+  int     i,nnat,nat1;
+
+    for (i=0;i<nModels;i++)
+      if (model[i]==mdl)  return -i;
+
+    nnat = mdl->GetNumberOfAtoms ( true );
+    AddAtomArray ( nnat );         // get space for new atoms
+
+    if (mdl->GetCoordHierarchy())  {
+      SwitchModel ( nModels+1 ); // get one more model at the end
+      nat1 = nAtoms;
+      model[nModels-1]->_copy ( mdl,atom,nat1 );
+      model[nModels-1]->serNum = nModels;
+      nAtoms = nat1;
+    } else  {
+      model1 = new PModel[nModels+1];
+      for (i=0;i<nModels;i++)
+        model1[i] = model[i];
+      if (model)  delete[] model;
+      model = model1;
+      model[nModels] = mdl;
+      model[nModels]->SetMMDBManager ( PManager(this),nModels+1 );
+      model[nModels]->CheckInAtoms();
+      nModels++;
+    }
+
+    return nModels;
+
+  }
+
+  int  CoorManager::InsModel ( PModel mdl, int modelNo )  {
+    AddModel     ( mdl );
+    RotateModels ( modelNo,nModels,1 );
+    return nModels;
+  }
+
+  void CoorManager::RotateModels ( int modelNo1, int modelNo2,
+                                   int rotdir )  {
+  PModel mdl;
+  PPAtom A;
+  int    m1,m2,i11,i12,i21,i22,nat,i,k;
+
+    m1 = IMax ( 0,modelNo1-1 );
+    m2 = IMin ( nModels,modelNo2) - 1;
+    if (m1>m2)  ISwap ( m1,m2 );
+
+    if (m1!=m2)  {
+
+      if (model[m1] && model[m2])  {
+        model[m1]->GetAIndexRange ( i11,i12 );
+        model[m2]->GetAIndexRange ( i21,i22 );
+        if ((i11<i12) && (i21<i22) && (i12<i22))  {
+          i11--;    i12--;
+          i21--;    i22--;
+          if (rotdir<0)  {
+            //  rotate anticlockwise
+            nat = i12-i11+1;
+            A = new PAtom[nat];
+            k = 0;
+            for (i=i11;i<=i12;i++)
+              A[k++] = atom[i];
+            k = i11;
+            for (i=i12+1;i<=i22;i++)  {
+              atom[k] = atom[i];
+              if (atom[k])  atom[k]->index = k+1;
+              k++;
+            }
+            for (i=0;i<nat;i++)  {
+              atom[k] = A[i];
+              if (atom[k])  atom[k]->index = k+1;
+              k++;
+            }
+          } else  {
+            //  rotate anticlockwise
+            nat = i22-i21+1;
+            A = new PAtom[nat];
+            k = 0;
+            for (i=i21;i<=i22;i++)
+              A[k++] = atom[i];
+            k = i22;
+            for (i=i21-1;i>=i11;i--)  {
+              atom[k] = atom[i];
+              if (atom[k])  atom[k]->index = k+1;
+              k--;
+            }
+            for (i=nat-1;i>=0;i--)  {
+              atom[k] = A[i];
+              if (atom[k])  atom[k]->index = k+1;
+              k--;
+            }
+          }
+          delete[] A;
+        }
+      }
+
+      if (rotdir<0)  {
+        //  rotate anticlockwise
+        mdl = model[m1];
+        for (i=m1;i<m2;i++)  {
+          model[i] = model[i+1];
+          model[i]->serNum = i+1;
+        }
+        model[m2] = mdl;
+        model[m2]->serNum = m2+1;
+      } else  {
+        //  rotate clockwise
+        mdl = model[m2];
+        for (i=m2;i>m1;i--)  {
+          model[i] = model[i-1];
+          model[i]->serNum = i+1;
+        }
+        model[m1] = mdl;
+        model[m1]->serNum = m1+1;
+      }
+
+    }
+
+  }
+
+
+  void CoorManager::SwapModels ( int modelNo1, int modelNo2 )  {
+  PModel mdl;
+  PPAtom A;
+  int    m1,m2,i11,i12,i21,i22,i,k,n;
+
+    n = 0;  // tp depress "uninitialized" warning
+
+    m1 = IMax ( 0,modelNo1-1 );
+    m2 = IMin ( nModels,modelNo2) - 1;
+    if (m1>m2)  ISwap ( m1,m2 );
+
+    if (m1!=m2)  {
+
+      if (model[m1])
+        model[m1]->GetAIndexRange ( i11,i12 );
+      else  {
+        n = m1;
+        while ((!model[n]) && (n<m2))  n++;
+        if (n<m2)  {
+          model[n]->GetAIndexRange ( i11,i12 );
+          i12 = i11-1;
+        } else
+          n = -1;
+      }
+
+      if (n>=0)  {
+        if (model[m2])
+          model[m2]->GetAIndexRange ( i21,i22 );
+        else  {
+          n = m2;
+          while ((!model[n]) && (m1<n))  n--;
+          if (m1<n)  {
+            model[n]->GetAIndexRange ( i21,i22 );
+            i22 = i21-1;
+          } else
+            n = -1;
+        }
+      }
+
+      if (n>=0)  {
+
+        i11--;    i12--;
+        i21--;    i22--;
+
+        A = new PAtom[atmLen];
+        k = 0;
+
+        for (i=0     ;i<i11   ;i++)  A[k++] = atom[i];
+        for (i=i21   ;i<=i22  ;i++)  A[k++] = atom[i];
+        for (i=i12+1 ;i<i21   ;i++)  A[k++] = atom[i];
+        for (i=i11   ;i<=i12  ;i++)  A[k++] = atom[i];
+
+        for (i=0     ;i<nAtoms;i++)  if (A[i]) A[i]->index = i+1;
+        for (i=nAtoms;i<atmLen;i++)  A[i] = NULL;
+
+        if (atom)  delete[] atom;
+        atom = A;
+
+      }
+
+      mdl       = model[m2];
+      model[m2] = model[m1];
+      model[m1] = mdl;
+
+      model[m1]->serNum = m1+1;
+      model[m2]->serNum = m2+1;
+
+    }
+
+  }
+
+
+  PChain CoorManager::GetChain ( int modelNo, const ChainID chainID )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetChain ( chainID );
+    }
+    return NULL;
+  }
+
+  PChain CoorManager::GetChain ( int modelNo, int chainNo )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetChain ( chainNo );
+    }
+    return NULL;
+  }
+
+  PChain CoorManager::GetChain ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID)))  {
+      CoorIDCode = CID_WrongPath;
+      return NULL;
+    }
+    return GetChain ( modno,chname );
+
+  }
+
+  void  CoorManager::GetChainTable ( int modelNo,
+                                          PPChain & chainTable,
+                                          int & NumberOfChains )  {
+    chainTable     = NULL;
+    NumberOfChains = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        chainTable     = model[modelNo-1]->chain;
+        NumberOfChains = model[modelNo-1]->nChains;
+      }
+    }
+  }
+
+  void  CoorManager::GetChainTable ( cpstr CID,
+                                          PPChain & chainTable,
+                                          int & NumberOfChains )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    chainTable     = NULL;
+    NumberOfChains = 0;
+    CoorIDCode     = CID_Ok;
+
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & APATH_WC_ModelNo))  {
+      CoorIDCode = CID_WrongPath;
+      return;
+    }
+
+    if ((0<modno) && (modno<=nModels))  {
+      if (model[modno-1])  {
+        chainTable     = model[modno-1]->chain;
+        NumberOfChains = model[modno-1]->nChains;
+      }
+    }
+  }
+
+
+  int CoorManager::DeleteChain ( int modelNo, const ChainID chID )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteChain ( chID );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteChain ( int modelNo, int chainNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteChain ( chainNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllChains ( int modelNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllChains();
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllChains()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  k += model[i]->DeleteAllChains();
+    return k;
+  }
+
+  int CoorManager::AddChain ( int modelNo, PChain chain )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddChain ( chain );
+    }
+    return 0;
+  }
+
+
+  PResidue CoorManager::GetResidue ( int           modelNo,
+                                     const ChainID chainID,
+                                     int           seqNo,
+                                     const InsCode insCode )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
+    }
+    return NULL;
+  }
+
+  PResidue CoorManager::GetResidue ( int modelNo, int chainNo,
+                                     int seqNo,
+                                     const InsCode insCode )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
+    }
+    return NULL;
+  }
+
+  PResidue CoorManager::GetResidue ( int modelNo,
+                                     const ChainID chainID,
+                                     int resNo )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetResidue ( chainID,resNo );
+    }
+    return NULL;
+  }
+
+  PResidue CoorManager::GetResidue ( int modelNo, int chainNo,
+                                     int resNo )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetResidue ( chainNo,resNo );
+    }
+    return NULL;
+  }
+
+  PResidue CoorManager::GetResidue ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+                         APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
+      CoorIDCode = CID_WrongPath;
+      return NULL;
+    }
+    return GetResidue ( modno,chname,sn,ic );
+
+  }
+
+
+  int CoorManager::GetResidueNo ( int           modelNo,
+                                  const ChainID chainID,
+                                  int           seqNo,
+                                  const InsCode insCode )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetResidueNo ( chainID,seqNo,insCode );
+    }
+    return -3;
+  }
+
+  int CoorManager::GetResidueNo ( int modelNo, int chainNo,
+                                  int seqNo,
+                                  const InsCode insCode )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->GetResidueNo ( chainNo,seqNo,insCode );
+    }
+    return -3;
+  }
+
+  void CoorManager::GetResidueTable ( PPResidue & resTable,
+                                      int & NumberOfResidues )  {
+  //    resTable has to be NULL or it will be reallocated. The
+  //  application is responsible for deallocating the resTable (but not
+  //  of its residues!). This does not apply to other GetResidueTable
+  //  functions.
+  PPChain   chain;
+  PPResidue res;
+  int       i,j,k,n,nChains,nResidues;
+
+    if (resTable)  {
+      delete[] resTable;
+      resTable = NULL;
+    }
+
+    NumberOfResidues = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  {
+        model[i]->GetChainTable ( chain,nChains );
+        for (j=0;j<model[i]->nChains;j++)
+          if (chain[j])  {
+            chain[j]->GetResidueTable ( res,nResidues );
+            NumberOfResidues += nResidues;
+          }
+      }
+
+    if (NumberOfResidues>0)  {
+      resTable = new PResidue[NumberOfResidues];
+      k = 0;
+      for (i=0;i<nModels;i++)
+        if (model[i])  {
+          model[i]->GetChainTable ( chain,nChains );
+          for (j=0;j<model[i]->nChains;j++)
+            if (chain[j])  {
+              chain[j]->GetResidueTable ( res,nResidues );
+              for (n=0;n<nResidues;n++)
+                if (res[n])  resTable[k++] = res[n];
+            }
+        }
+      NumberOfResidues = k;
+    }
+
+  }
+
+  void CoorManager::GetResidueTable ( int modelNo,
+                                           const ChainID chainID,
+                                           PPResidue & resTable,
+                                           int & NumberOfResidues )  {
+  PChain chain;
+    resTable         = NULL;
+    NumberOfResidues = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        chain = model[modelNo-1]->GetChain ( chainID );
+        if (chain)  {
+          resTable         = chain->residue;
+          NumberOfResidues = chain->nResidues;
+        }
+      }
+    }
+  }
+
+  void CoorManager::GetResidueTable ( int modelNo, int chainNo,
+                                           PPResidue & resTable,
+                                           int & NumberOfResidues )  {
+  PChain chain;
+    resTable         = NULL;
+    NumberOfResidues = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        chain = model[modelNo-1]->GetChain ( chainNo );
+        if (chain)  {
+          resTable         = chain->residue;
+          NumberOfResidues = chain->nResidues;
+        }
+      }
+    }
+  }
+
+  void CoorManager::GetResidueTable ( cpstr CID,
+                                           PPResidue & resTable,
+                                           int & NumberOfResidues )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+  PChain  chain;
+
+    resTable         = NULL;
+    NumberOfResidues = 0;
+    CoorIDCode       = CID_Ok;
+
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID)))  {
+      CoorIDCode = CID_WrongPath;
+      return;
+    }
+
+    if ((0<modno) && (modno<=nModels))  {
+      if (model[modno-1])  {
+        chain = model[modno-1]->GetChain ( chname );
+        if (chain)  {
+          resTable         = chain->residue;
+          NumberOfResidues = chain->nResidues;
+        }
+      }
+    }
+
+  }
+
+
+  int CoorManager::DeleteResidue ( int           modelNo,
+                                        const ChainID chainID,
+                                        int           seqNo,
+                                        const InsCode insCode )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteResidue ( chainID,seqNo,insCode );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteResidue ( int           modelNo,
+                                        const ChainID chainID,
+                                        int           resNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteResidue ( chainID,resNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteResidue ( int modelNo, int chainNo,
+                                        int seqNo,
+                                        const InsCode insCode )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteResidue ( chainNo,seqNo,insCode );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteResidue ( int modelNo, int chainNo,
+                                        int resNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteResidue ( chainNo,resNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllResidues ( int modelNo,
+                                            const ChainID chainID )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllResidues ( chainID );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllResidues ( int modelNo, int chainNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllResidues ( chainNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllResidues ( int modelNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllResidues();
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllResidues()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  k += model[i]->DeleteAllResidues();
+    return k;
+  }
+
+  int CoorManager::AddResidue ( int modelNo, const ChainID chainID,
+                                     PResidue res )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddResidue ( chainID,res );
+    }
+    return 0;
+  }
+
+  int CoorManager::AddResidue ( int modelNo, int chainNo,
+                                     PResidue res )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddResidue ( chainNo,res );
+    }
+    return 0;
+  }
+
+
+
+  int  CoorManager::GetNumberOfChains ( int modelNo )  {
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return  model[modelNo-1]->nChains;
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfChains ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & APATH_WC_ModelNo))  {
+      CoorIDCode = CID_WrongPath;
+      return 0;
+    }
+
+    if ((0<modno) && (modno<=nModels))  {
+      if (model[modno-1])
+        return  model[modno-1]->nChains;
+    }
+
+    return 0;
+
+  }
+
+  int  CoorManager::GetNumberOfResidues ( int modelNo,
+                                               const ChainID chainID )  {
+  PChain chain;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        chain = model[modelNo-1]->GetChain ( chainID );
+        if (chain)  return chain->nResidues;
+      }
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfResidues ( int modelNo, int chainNo )  {
+  PChain chain;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        if ((0<=chainNo) && (chainNo<model[modelNo-1]->nChains))  {
+          chain = model[modelNo-1]->chain[chainNo];
+          if (chain)  return chain->nResidues;
+        }
+      }
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfResidues ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+  PChain  chain;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID)))  {
+      CoorIDCode = CID_WrongPath;
+      return 0;
+    }
+
+    if ((0<modno) && (modno<=nModels))  {
+      if (model[modno-1])  {
+        chain = model[modno-1]->GetChain ( chname );
+        if (chain)  return chain->nResidues;
+      }
+    }
+
+    return 0;
+
+  }
+
+
+  int  CoorManager::GetNumberOfAtoms ( int           modelNo,
+                                            const ChainID chainID,
+                                            int           seqNo,
+                                            const InsCode insCode )  {
+  PChain   chain;
+  PResidue res;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        chain = model[modelNo-1]->GetChain ( chainID );
+        if (chain)  {
+          res = chain->GetResidue ( seqNo,insCode );
+          if (res)  return res->nAtoms;
+        }
+      }
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfAtoms ( int modelNo, int chainNo,
+                                            int seqNo,
+                                            const InsCode insCode )  {
+  PChain   chain;
+  PResidue res;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        if ((0<=chainNo) && (chainNo<model[modelNo-1]->nChains))  {
+          chain = model[modelNo-1]->chain[chainNo];
+          if (chain)  {
+            res = chain->GetResidue ( seqNo,insCode );
+            if (res)  return res->nAtoms;
+          }
+        }
+      }
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfAtoms ( int           modelNo,
+                                            const ChainID chainID,
+                                            int           resNo )  {
+  PChain   chain;
+  PResidue res;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        chain = model[modelNo-1]->GetChain ( chainID );
+        if (chain)  {
+          if ((0<=resNo) && (resNo<chain->nResidues))  {
+            res = chain->residue[resNo];
+            if (res)  return res->nAtoms;
+          }
+        }
+      }
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfAtoms ( int modelNo, int chainNo,
+                                            int resNo )  {
+  PChain   chain;
+  PResidue res;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        if ((0<=chainNo) && (chainNo<model[modelNo-1]->nChains))  {
+          chain = model[modelNo-1]->chain[chainNo];
+          if (chain)  {
+            if ((0<=resNo) && (resNo<chain->nResidues))  {
+              res = chain->residue[resNo];
+              if (res)  return res->nAtoms;
+            }
+          }
+        }
+      }
+    }
+    return 0;
+  }
+
+  int  CoorManager::GetNumberOfAtoms ( cpstr CID )  {
+  // returns number of atoms in residues identified by CID
+  int       modno,sn,rc;
+  ChainID   chname;
+  InsCode   ic;
+  ResName   resname;
+  AtomName  aname;
+  Element   elname;
+  AltLoc    aloc;
+  PChain   chain;
+  PResidue res;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+                         APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
+      CoorIDCode = CID_WrongPath;
+      return 0;
+    }
+
+    if ((0<modno) && (modno<=nModels))  {
+      if (model[modno-1])  {
+        chain = model[modno-1]->GetChain ( chname );
+        if (chain)  {
+          res = chain->GetResidue ( sn,ic );
+          if (res)  return res->nAtoms;
+        }
+      }
+    }
+
+    return 0;
+
+  }
+
+
+  // --------------------  Extracting atoms  -----------------------
+
+  PAtom  CoorManager::GetAtom (
+                     int            modelNo, // model serial number 1...
+                     const ChainID  chID,    // chain ID
+                     int            seqNo,   // residue sequence number
+                     const InsCode  insCode, // residue insertion code
+                     const AtomName aname,   // atom name
+                     const Element  elmnt,   // chemical element code or '*'
+                     const AltLoc   aloc     // alternate location indicator
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    chn = mdl->GetChain ( chID );
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    res = chn->GetResidue ( seqNo,insCode );
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    atm = res->GetAtom ( aname,elmnt,aloc );
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int           modelNo, // model serial number 1...
+                       const ChainID chID,    // chain ID
+                       int           seqNo,   // residue sequence number
+                       const InsCode insCode, // residue insertion code
+                       int           atomNo   // atom number 0..
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    chn = mdl->GetChain ( chID );
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    res = chn->GetResidue ( seqNo,insCode );
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    if ((0<=atomNo) && (atomNo<res->nAtoms))
+          atm = res->atom[atomNo];
+    else  atm = NULL;
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int            modelNo, // model serial number 1...
+                       const ChainID  chID,    // chain ID
+                       int            resNo,   // residue number 0..
+                       const AtomName aname,   // atom name
+                       const Element  elmnt,   // chemical element code or '*'
+                       const AltLoc   aloc     // alternate location indicator
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    chn = mdl->GetChain ( chID );
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    if ((0<=resNo) && (resNo<chn->nResidues))
+          res = chn->residue[resNo];
+    else  res = NULL;
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    atm = res->GetAtom ( aname,elmnt,aloc );
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int           modelNo, // model serial number 1...
+                       const ChainID chID,    // chain ID
+                       int           resNo,   // residue number 0..
+                       int           atomNo   // atom number 0..
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    chn = mdl->GetChain ( chID );
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    if ((0<=resNo) && (resNo<chn->nResidues))
+          res = chn->residue[resNo];
+    else  res = NULL;
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    if ((0<=atomNo) && (atomNo<res->nAtoms))
+          atm = res->atom[atomNo];
+    else  atm = NULL;
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int            modelNo, // model serial number 1...
+                       int            chNo,    // chain number 0..
+                       int            seqNo,   // residue sequence number
+                       const InsCode  insCode, // residue insertion code
+                       const AtomName aname,   // atom name
+                       const Element  elmnt,   // chemical element code or '*'
+                       const AltLoc   aloc     // alternate location indicator
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    if ((0<=chNo) && (chNo<mdl->nChains))
+          chn = mdl->chain[chNo];
+    else  chn = NULL;
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    res = chn->GetResidue ( seqNo,insCode );
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    atm = res->GetAtom ( aname,elmnt,aloc );
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int           modelNo, // model serial number 1...
+                       int           chNo,    // chain number 0...
+                       int           seqNo,   // residue sequence number
+                       const InsCode insCode, // residue insertion code
+                       int           atomNo   // atom number 0...
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    if ((0<=chNo) && (chNo<mdl->nChains))
+          chn = mdl->chain[chNo];
+    else  chn = NULL;
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    res = chn->GetResidue ( seqNo,insCode );
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    if ((0<=atomNo) && (atomNo<res->nAtoms))
+          atm = res->atom[atomNo];
+    else  atm = NULL;
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int            modelNo, // model serial number 1...
+                       int            chNo,    // chain number 0...
+                       int            resNo,   // residue number 0...
+                       const AtomName aname,   // atom name
+                       const Element  elmnt,   // chemical element code or '*'
+                       const AltLoc   aloc     // alternate location indicator
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    if ((0<=chNo) && (chNo<mdl->nChains))
+          chn = mdl->chain[chNo];
+    else  chn = NULL;
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    if ((0<=resNo) && (resNo<chn->nResidues))
+          res = chn->residue[resNo];
+    else  res = NULL;
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    atm = res->GetAtom ( aname,elmnt,aloc );
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+  PAtom CoorManager::GetAtom (
+                       int modelNo, // model serial number 1...
+                       int chNo,    // chain number 0...
+                       int resNo,   // residue number 0...
+                       int atomNo   // atom number 0...
+                   )  {
+  PModel   mdl;
+  PChain   chn;
+  PResidue res;
+  PAtom    atm;
+
+    if ((1<=modelNo) && (modelNo<=nModels))
+          mdl = model[modelNo-1];
+    else  mdl = NULL;
+    if (!mdl)  {
+      CoorIDCode = CID_NoModel;
+      return NULL;
+    }
+
+    if ((0<=chNo) && (chNo<mdl->nChains))
+          chn = mdl->chain[chNo];
+    else  chn = NULL;
+    if (!chn)  {
+      CoorIDCode = CID_NoChain;
+      return NULL;
+    }
+
+    if ((0<=resNo) && (resNo<chn->nResidues))
+          res = chn->residue[resNo];
+    else  res = NULL;
+    if (!res)  {
+      CoorIDCode = CID_NoResidue;
+      return NULL;
+    }
+
+    if ((0<=atomNo) && (atomNo<res->nAtoms))
+          atm = res->atom[atomNo];
+    else  atm = NULL;
+    if (!atm)  CoorIDCode = CID_NoAtom;
+         else  CoorIDCode = CID_Ok;
+
+    return atm;
+
+  }
+
+
+  PAtom CoorManager::GetAtom ( cpstr CID )  {
+  int      modno,sn,rc;
+  ChainID  chname;
+  InsCode  ic;
+  ResName  resname;
+  AtomName aname;
+  Element  elname;
+  AltLoc   aloc;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & APATH_Incomplete))  {
+      CoorIDCode = CID_WrongPath;
+      return NULL;
+    }
+
+    return GetAtom ( modno,chname,sn,ic,aname,elname,aloc );
+
+  }
+
+
+  void CoorManager::GetAtomTable ( PPAtom & atomTable,
+                                        int & NumberOfAtoms )  {
+    atomTable     = atom;
+    NumberOfAtoms = nAtoms;
+  }
+
+  void CoorManager::GetAtomTable ( int           modelNo,
+                                        const ChainID chainID,
+                                        int           seqNo,
+                                        const InsCode insCode,
+                                        PPAtom &     atomTable,
+                                        int &         NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        res = model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
+        if (res)  {
+          atomTable     = res->atom;
+          NumberOfAtoms = res->nAtoms;
+        }
+      }
+    }
+  }
+
+  void CoorManager::GetAtomTable ( int           modelNo,
+                                        int           chainNo,
+                                        int           seqNo,
+                                        const InsCode insCode,
+                                        PPAtom &     atomTable,
+                                        int &         NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        res = model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
+        if (res)  {
+          atomTable     = res->atom;
+          NumberOfAtoms = res->nAtoms;
+        }
+      }
+    }
+  }
+
+  void CoorManager::GetAtomTable ( int           modelNo,
+                                        const ChainID chainID,
+                                        int           resNo,
+                                        PPAtom &     atomTable,
+                                        int &         NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        res = model[modelNo-1]->GetResidue ( chainID,resNo );
+        if (res)  {
+          atomTable     = res->atom;
+          NumberOfAtoms = res->nAtoms;
+        }
+      }
+    }
+  }
+
+  void CoorManager::GetAtomTable ( int modelNo, int chainNo,
+                                        int resNo, PPAtom & atomTable,
+                                        int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])  {
+        res = model[modelNo-1]->GetResidue ( chainNo,resNo );
+        if (res)  {
+          atomTable     = res->atom;
+          NumberOfAtoms = res->nAtoms;
+        }
+      }
+    }
+  }
+
+  void CoorManager::GetAtomTable ( cpstr CID,
+                                        PPAtom & atomTable,
+                                        int & NumberOfAtoms )  {
+  int       modno,sn,rc;
+  ChainID   chname;
+  InsCode   ic;
+  ResName   resname;
+  AtomName  aname;
+  Element   elname;
+  AltLoc    aloc;
+  PResidue res;
+
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+                         APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
+      CoorIDCode = CID_WrongPath;
+      return;
+    }
+
+    res = GetResidue ( modno,chname,sn,ic );
+    if (res)  {
+      atomTable     = res->atom;
+      NumberOfAtoms = res->nAtoms;
+    }
+
+  }
+
+
+  void CoorManager::GetAtomTable1 ( PPAtom & atomTable,
+                                         int & NumberOfAtoms )  {
+  int i,j;
+    if (atomTable)  delete[] atomTable;
+    if (nAtoms>0)  {
+      atomTable = new PAtom[nAtoms];
+      j = 0;
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)
+            atomTable[j++] = atom[i];
+        }
+      NumberOfAtoms = j;
+    } else  {
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void CoorManager::GetAtomTable1 ( int           modelNo,
+                                         const ChainID chainID,
+                                         int           seqNo,
+                                         const InsCode insCode,
+                                         PPAtom &     atomTable,
+                                         int &         NumberOfAtoms )  {
+  PResidue res;
+    res = NULL;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        res = model[modelNo-1]->GetResidue ( chainID,seqNo,insCode );
+    }
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void CoorManager::GetAtomTable1 ( int           modelNo,
+                                         int           chainNo,
+                                         int           seqNo,
+                                         const InsCode insCode,
+                                         PPAtom &     atomTable,
+                                         int &         NumberOfAtoms )  {
+  PResidue res;
+    res = NULL;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        res = model[modelNo-1]->GetResidue ( chainNo,seqNo,insCode );
+    }
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void CoorManager::GetAtomTable1 ( int           modelNo,
+                                         const ChainID chainID,
+                                         int           resNo,
+                                         PPAtom &     atomTable,
+                                         int &         NumberOfAtoms )  {
+  PResidue res;
+    res = NULL;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        res = model[modelNo-1]->GetResidue ( chainID,resNo );
+    }
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void CoorManager::GetAtomTable1 ( int modelNo, int chainNo,
+                                         int resNo,
+                                         PPAtom & atomTable,
+                                         int & NumberOfAtoms )  {
+  PResidue res;
+    res = NULL;
+    if ((0<modelNo) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        res = model[modelNo-1]->GetResidue ( chainNo,resNo );
+    }
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void CoorManager::GetAtomTable1 ( cpstr CID, PPAtom & atomTable,
+                                         int & NumberOfAtoms )  {
+  int       modno,sn,rc;
+  ChainID   chname;
+  InsCode   ic;
+  ResName   resname;
+  AtomName  aname;
+  Element   elname;
+  AltLoc    aloc;
+  PResidue res;
+
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+
+    CoorIDCode = CID_Ok;
+    rc = ParseAtomPath ( CID,modno,chname,sn,ic,resname,
+                         aname,elname,aloc,&DefPath );
+    if ((rc<0) || (rc & (APATH_WC_ModelNo | APATH_WC_ChainID |
+                         APATH_WC_SeqNum  | APATH_WC_InsCode)))  {
+      CoorIDCode = CID_WrongPath;
+      return;
+    }
+
+    res = GetResidue ( modno,chname,sn,ic );
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+
+  }
+
+
+
+  int CoorManager::DeleteAtom ( int            modelNo,
+                                     const ChainID  chID,
+                                     int            seqNo,
+                                     const InsCode  insCode,
+                                     const AtomName aname,
+                                     const Element  elmnt,
+                                     const AltLoc   aloc )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chID,seqNo,insCode,
+                                              aname,elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int           modelNo,
+                                     const ChainID chID,
+                                     int           seqNo,
+                                     const InsCode insCode,
+                                     int           atomNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chID,seqNo,insCode,atomNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int            modelNo,
+                                     const ChainID  chID,
+                                     int            resNo,
+                                     const AtomName aname,
+                                     const Element  elmnt,
+                                     const AltLoc   aloc )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chID,resNo,
+                                              aname,elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int           modelNo,
+                                     const ChainID chID,
+                                     int           resNo,
+                                     int           atomNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chID,resNo,atomNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int modelNo, int chNo, int seqNo,
+                                     const InsCode  insCode,
+                                     const AtomName aname,
+                                     const Element  elmnt,
+                                     const AltLoc   aloc )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chNo,seqNo,insCode,
+                                              aname,elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int modelNo, int chNo, int seqNo,
+                                     const InsCode insCode, int atomNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chNo,seqNo,insCode,atomNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int modelNo, int chNo, int resNo,
+                                     const AtomName aname,
+                                     const Element  elmnt,
+                                     const AltLoc   aloc )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chNo,resNo,
+                                              aname,elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAtom ( int modelNo, int chNo, int resNo,
+                                     int atomNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAtom ( chNo,resNo,atomNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int           modelNo,
+                                         const ChainID chID,
+                                         int           seqNo,
+                                         const InsCode insCode )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms ( chID,seqNo,insCode );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int modelNo, const ChainID chID,
+                                         int resNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms ( chID,resNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int modelNo, const ChainID chID )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms ( chID );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int modelNo, int chNo, int seqNo,
+                                         const InsCode insCode )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms ( chNo,seqNo,insCode );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int modelNo, int chNo,
+                                         int resNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms ( chNo,resNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int modelNo, int chNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms ( chNo );
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms ( int modelNo )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->DeleteAllAtoms();
+    }
+    return 0;
+  }
+
+  int CoorManager::DeleteAllAtoms()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  k += model[i]->DeleteAllAtoms();
+    return k;
+  }
+
+
+  /*
+  int CoorManager::DeleteAltLocs()  {
+  //  This function leaves only alternative location with maximal
+  // occupancy, if those are equal or unspecified, the one with
+  // "least" alternative location indicator.
+  //  The function returns the number of deleted atoms and optimizes
+  // the atom index.
+  ChainID  chID;
+  ResName  rName;
+  InsCode  iCode;
+  AtomName aname;
+  AltLoc   aLoc,aL;
+  realtype occupancy,occ;
+  int      seqNum;
+  int      i,j,k,i1,i2,n;
+
+    k = 0;
+    n = 0;
+    i = 0;
+    while (i<nAtoms)  {
+
+      if (atom[i])  {
+        seqNum    = atom[i]->GetSeqNum   ();
+        occupancy = atom[i]->GetOccupancy();
+        strcpy ( chID ,atom[i]->GetChainID() );
+        strcpy ( rName,atom[i]->GetResName() );
+        strcpy ( iCode,atom[i]->GetInsCode() );
+        strcpy ( aname,atom[i]->name   );
+        strcpy ( aLoc ,atom[i]->altLoc );
+        j  = i+1;
+        i1 = -1;
+        i2 = i;
+        while (j<nAtoms)
+          if (atom[j])  {
+            if ((atom[j]->GetSeqNum()==seqNum)         &&
+                (!strcmp(atom[j]->name,aname))         &&
+                (!strcmp(atom[j]->GetInsCode(),iCode)) &&
+                (!strcmp(atom[j]->GetResName(),rName)) &&
+                (!strcmp(atom[j]->GetChainID(),chID )))  {
+              occ = atom[j]->GetOccupancy();
+              if (occ>occupancy)  {
+                occupancy = occ;
+                i1 = j;
+              }
+              if (aLoc[0])  {
+                strcpy ( aL,atom[j]->altLoc );
+                if (!aL[0])  {
+                  aLoc[0] = char(0);
+                  i2 = j;
+                } else if (strcmp(aL,aLoc)<0)  {
+                  strcpy ( aLoc,aL );
+                  i2 = j;
+                }
+              }
+              j++;
+            } else
+              break;
+          } else
+            j++;
+        if (i1<0)  {
+          if (atom[i]->WhatIsSet & ASET_Occupancy)  i1 = i;
+                                              else  i1 = i2;
+        }
+        while (i<j)  {
+          if (atom[i])  {
+            if (i!=i1)  {
+              delete atom[i];
+              atom[i] = NULL;
+              n++;
+            } else  {
+              if (k<i)  {
+                atom[k] = atom[i];
+                atom[k]->index = k+1;
+              }
+              k++;
+            }
+          }
+          i++;
+        }
+
+      } else
+        i++;
+
+    }
+
+    nAtoms = k;
+    return n;
+
+  }
+  */
+
+  int CoorManager::DeleteAltLocs()  {
+  //  This function leaves only alternative location with maximal
+  // occupancy, if those are equal or unspecified, the one with
+  // "least" alternative location indicator.
+  //  The function returns the number of deleted atoms. All tables
+  // remain untrimmed, so that explicit trimming or calling
+  // FinishStructEdit() at some point is required.
+  int i,n;
+
+    n = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  n += model[i]->DeleteAltLocs();
+
+    return n;
+
+  }
+
+  int CoorManager::AddAtom ( int           modelNo,
+                                  const ChainID chID,
+                                  int           seqNo,
+                                  const InsCode insCode,
+                                  PAtom atom )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddAtom ( chID,seqNo,insCode,atom );
+    }
+    return 0;
+  }
+
+  int CoorManager::AddAtom ( int modelNo, const ChainID chID,
+                                  int resNo, PAtom atom )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddAtom ( chID,resNo,atom );
+    }
+    return 0;
+  }
+
+  int CoorManager::AddAtom ( int modelNo, int chNo,
+                                  int seqNo, const InsCode insCode,
+                                  PAtom atom )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddAtom ( chNo,seqNo,insCode,atom );
+    }
+    return 0;
+  }
+
+  int CoorManager::AddAtom ( int modelNo, int chNo,
+                                  int resNo, PAtom atom )  {
+    if ((modelNo>0) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return model[modelNo-1]->AddAtom ( chNo,resNo,atom );
+    }
+    return 0;
+  }
+
+
+  void  CoorManager::RemoveBricks()  {
+  int i,j,k;
+    if (brick)  {
+      for (i=0;i<nbrick_x;i++)
+        if (brick[i])  {
+          for (j=0;j<nbrick_y;j++)
+            if (brick[i][j])  {
+              for (k=0;k<nbrick_z;k++)
+                if (brick[i][j][k])  delete brick[i][j][k];
+              delete[] brick[i][j];
+            }
+          delete[] brick[i];
+        }
+      delete[] brick;
+    }
+    brick    = NULL;
+    nbrick_x = 0;
+    nbrick_y = 0;
+    nbrick_z = 0;
+  }
+
+  void  CoorManager::GetBrickCoor ( PAtom A,
+                                         int & nx, int & ny, int & nz ) {
+    nx = (int)floor((A->x-xbrick_0)/brick_size);
+    ny = (int)floor((A->y-ybrick_0)/brick_size);
+    nz = (int)floor((A->z-zbrick_0)/brick_size);
+    if ((ny<0) || (nz<0) || (nx>=nbrick_x) ||
+        (ny>=nbrick_y) || (nz>=nbrick_z))  nx = -1;
+  }
+
+  void  CoorManager::GetBrickCoor ( realtype x, realtype y,
+                                    realtype z, int & nx,
+                                         int & ny, int & nz ) {
+    nx = (int)floor((x-xbrick_0)/brick_size);
+    ny = (int)floor((y-ybrick_0)/brick_size);
+    nz = (int)floor((z-zbrick_0)/brick_size);
+    if ((ny<0) || (nz<0) || (nx>=nbrick_x) ||
+        (ny>=nbrick_y) || (nz>=nbrick_z))  nx = -1;
+  }
+
+  void  CoorManager::GetBrickDimension (
+                        int & nxmax, int & nymax, int & nzmax )  {
+    if (!brick)  {
+      nxmax = 0;  nymax = 0;  nzmax = 0;
+    } else  {
+      nxmax = nbrick_x;
+      nymax = nbrick_y;
+      nzmax = nbrick_z;
+    }
+  }
+
+  PBrick CoorManager::GetBrick ( int nx, int ny, int nz )  {
+    if (!brick)  return NULL;
+    if ((nx>=0) && (nx<nbrick_x) &&
+        (ny>=0) && (ny<nbrick_y) &&
+        (nz>=0) && (nz<nbrick_z))  {
+      if (!brick[nx])     return NULL;
+      if (!brick[nx][ny]) return NULL;
+      return brick[nx][ny][nz];
+    }
+    return NULL;
+  }
+
+  void  CoorManager::MakeBricks ( PPAtom  atmvec,  int avlen,
+                                       realtype Margin,
+                                       realtype BrickSize )  {
+  //    Makes bricking for atoms contained in vector atmvec of length
+  // avlen, with brick size BrickSize (in angstroms). The previous
+  // bricking, if there was any, is removed.
+  int      i,j, nx,ny,nz, alen;
+  realtype x1,x2, y1,y2, z1,z2, dx,dy,dz;
+  PPAtom  A;
+
+    RemoveBricks();
+
+    brick_size = BrickSize;
+
+    if (atmvec)  {
+      A    = atmvec;
+      alen = avlen;
+    } else  {
+      A    = atom;
+      alen = nAtoms;
+    }
+
+    if (alen>0)  {
+      //  find the range of coordinates
+      x1 = MaxReal;
+      x2 = -x1;
+      y1 = MaxReal;
+      y2 = -y1;
+      z1 = MaxReal;
+      z2 = -z1;
+      for (i=0;i<alen;i++)
+        if (A[i])  {
+          if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+            if (A[i]->x<x1)  x1 = A[i]->x;
+            if (A[i]->x>x2)  x2 = A[i]->x;
+            if (A[i]->y<y1)  y1 = A[i]->y;
+            if (A[i]->y>y2)  y2 = A[i]->y;
+            if (A[i]->z<z1)  z1 = A[i]->z;
+            if (A[i]->z>z2)  z2 = A[i]->z;
+          }
+        }
+      if (x1<MaxReal)  {
+        x1 -= Margin; x2 += Margin;
+        y1 -= Margin; y2 += Margin;
+        z1 -= Margin; z2 += Margin;
+        dx = x2-x1;  nbrick_x = mround(dx/brick_size+0.0001)+1;
+        dy = y2-y1;  nbrick_y = mround(dy/brick_size+0.0001)+1;
+        dz = z2-z1;  nbrick_z = mround(dz/brick_size+0.0001)+1;
+        xbrick_0 = x1 - (nbrick_x*brick_size-dx)/2.0;
+        ybrick_0 = y1 - (nbrick_y*brick_size-dy)/2.0;
+        zbrick_0 = z1 - (nbrick_z*brick_size-dz)/2.0;
+        for (i=0;i<alen;i++)
+          if (A[i])  {
+            if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+              GetBrickCoor ( A[i],nx,ny,nz );
+              if (nx>=0)  {
+                if (!brick)  {
+                  brick = new PPPBrick[nbrick_x];
+                  for (j=0;j<nbrick_x;j++)
+                    brick[j] = NULL;
+                }
+                if (!brick[nx])  {
+                  brick[nx] = new PPBrick[nbrick_y];
+                  for (j=0;j<nbrick_y;j++)
+                    brick[nx][j] = NULL;
+                }
+                if (!brick[nx][ny])  {
+                  brick[nx][ny] = new PBrick[nbrick_z];
+                  for (j=0;j<nbrick_z;j++)
+                    brick[nx][ny][j] = NULL;
+                }
+                if (!brick[nx][ny][nz])
+                  brick[nx][ny][nz] = new Brick();
+                brick[nx][ny][nz]->AddAtom ( A[i],i );
+              } else
+                printf ( " error in "
+                         "CoorManager::MakeBricks!!!\n" );
+            }
+          }
+      }
+    }
+
+  }
+
+
+  void  CoorManager::RemoveMBricks()  {
+  int i,j,k;
+    if (mbrick)  {
+      for (i=0;i<nmbrick_x;i++)
+        if (mbrick[i])  {
+          for (j=0;j<nmbrick_y;j++)
+            if (mbrick[i][j])  {
+              for (k=0;k<nmbrick_z;k++)
+                if (mbrick[i][j][k])  delete mbrick[i][j][k];
+              delete[] mbrick[i][j];
+            }
+          delete[] mbrick[i];
+        }
+      delete[] mbrick;
+    }
+    mbrick    = NULL;
+    nmbrick_x = 0;
+    nmbrick_y = 0;
+    nmbrick_z = 0;
+  }
+
+  void  CoorManager::GetMBrickCoor ( PAtom A,
+                                       int & nx, int & ny, int & nz )  {
+    nx = (int)floor((A->x-xmbrick_0)/mbrick_size);
+    ny = (int)floor((A->y-ymbrick_0)/mbrick_size);
+    nz = (int)floor((A->z-zmbrick_0)/mbrick_size);
+    if ((ny<0) || (nz<0) || (nx>=nmbrick_x) ||
+        (ny>=nmbrick_y)  || (nz>=nmbrick_z))  nx = -nx-1;
+  }
+
+  void  CoorManager::GetMBrickCoor (
+                                  realtype x, realtype y, realtype z,
+                                  int   & nx, int   & ny, int   & nz )  {
+    nx = (int)floor((x-xmbrick_0)/mbrick_size);
+    ny = (int)floor((y-ymbrick_0)/mbrick_size);
+    nz = (int)floor((z-zmbrick_0)/mbrick_size);
+    if ((ny<0) || (nz<0) || (nx>=nmbrick_x) ||
+          (ny>=nmbrick_y) || (nz>=nmbrick_z))  nx = -nx-1;
+  }
+
+  void  CoorManager::GetMBrickDimension (
+                        int & nxmax, int & nymax, int & nzmax )  {
+    if (!brick)  {
+      nxmax = 0;  nymax = 0;  nzmax = 0;
+    } else  {
+      nxmax = nmbrick_x;
+      nymax = nmbrick_y;
+      nzmax = nmbrick_z;
+    }
+  }
+
+  PMBrick CoorManager::GetMBrick ( int nx, int ny, int nz )  {
+    if (!mbrick)  return NULL;
+    if ((nx>=0) && (nx<nmbrick_x) &&
+        (ny>=0) && (ny<nmbrick_y) &&
+        (nz>=0) && (nz<nmbrick_z))  {
+      if (!mbrick[nx])     return NULL;
+      if (!mbrick[nx][ny]) return NULL;
+      return mbrick[nx][ny][nz];
+    }
+    return NULL;
+  }
+
+  void  CoorManager::MakeMBricks ( PPAtom * atmvec,  ivector avlen,
+                                   int nStructures, realtype Margin,
+                                   realtype BrickSize )  {
+  //    Makes bricking for atoms contained in vectors atmvec with lengths
+  // given in avlen, with brick size BrickSize (in angstroms).
+  // The previous bricking, if there was any, is removed.
+  int      i,j,k, nx,ny,nz;
+  realtype x1,x2, y1,y2, z1,z2, dx,dy,dz;
+  PAtom   A;
+
+    RemoveMBricks();
+
+    mbrick_size = BrickSize;
+
+    //  find the range of coordinates
+    x1 = MaxReal;
+    x2 = -x1;
+    y1 = MaxReal;
+    y2 = -y1;
+    z1 = MaxReal;
+    z2 = -z1;
+    for (i=0;i<nStructures;i++)
+      for (j=0;j<avlen[i];j++)  {
+        A = atmvec[i][j];
+        if (A)  {
+          if ((!A->Ter) && (A->WhatIsSet & ASET_Coordinates))  {
+            if (A->x<x1)  x1 = A->x;
+            if (A->x>x2)  x2 = A->x;
+            if (A->y<y1)  y1 = A->y;
+            if (A->y>y2)  y2 = A->y;
+            if (A->z<z1)  z1 = A->z;
+            if (A->z>z2)  z2 = A->z;
+          }
+        }
+      }
+    if (x1<MaxReal)  {
+      x1 -= Margin; x2 += Margin;
+      y1 -= Margin; y2 += Margin;
+      z1 -= Margin; z2 += Margin;
+      dx = x2-x1;  nmbrick_x = mround(dx/mbrick_size+0.0001)+1;
+      dy = y2-y1;  nmbrick_y = mround(dy/mbrick_size+0.0001)+1;
+      dz = z2-z1;  nmbrick_z = mround(dz/mbrick_size+0.0001)+1;
+      xmbrick_0 = x1 - (nmbrick_x*mbrick_size-dx)/2.0;
+      ymbrick_0 = y1 - (nmbrick_y*mbrick_size-dy)/2.0;
+      zmbrick_0 = z1 - (nmbrick_z*mbrick_size-dz)/2.0;
+      /*
+      mbrick = new PPPMBrick[nmbrick_x];
+      for (i=0;i<nmbrick_x;i++)  {
+        mbrick[i] = new PPMBrick[nmbrick_y];
+        for (j=0;j<nmbrick_y;j++)  {
+          mbrick[i][j] = new PMBrick[nmbrick_z];
+          for (k=0;k<nmbrick_z;k++)
+            mbrick[i][j][k] = new mbrick(nStructures);
+        }
+      }
+      */
+      for (i=0;i<nStructures;i++)
+        for (j=0;j<avlen[i];j++)  {
+          A = atmvec[i][j];
+          if (A)  {
+            if ((!A->Ter) && (A->WhatIsSet & ASET_Coordinates))  {
+              GetMBrickCoor ( A,nx,ny,nz );
+              if (nx>=0)  {
+                if (!mbrick)  {
+                  mbrick = new PPPMBrick[nmbrick_x];
+                  for (k=0;k<nmbrick_x;k++)
+                    mbrick[k] = NULL;
+                }
+                if (!mbrick[nx])  {
+                  mbrick[nx] = new PPMBrick[nmbrick_y];
+                  for (k=0;k<nmbrick_y;k++)
+                    mbrick[nx][k] = NULL;
+                }
+                if (!mbrick[nx][ny])  {
+                  mbrick[nx][ny] = new PMBrick[nmbrick_z];
+                  for (k=0;k<nmbrick_z;k++)
+                    mbrick[nx][ny][k] = NULL;
+                }
+                if (!mbrick[nx][ny][nz])
+                  mbrick[nx][ny][nz] = new MBrick(nStructures);
+                mbrick[nx][ny][nz]->AddAtom ( A,i,j );
+              } else
+                printf ( " error in "
+                         "CoorManager::MakeMBricks!!!\n" );
+            }
+          }
+        }
+    }
+
+  }
+
+
+  int  CoorManager::GenerateSymMates ( PGenSym genSym )  {
+  //
+  //   The function generates symmetry mates according to symmetry
+  // operations found in GenSym. Results of first symmetry operation
+  // (number 0) always replaces the existing set of atoms, others
+  // are added as additional sets.
+  //   If GenSym is set to NULL, the function generates all
+  // symmetry mates for the unit cell taking the symmetry information
+  // from cryst.SymOps.
+  //   The newly generated chains are added to each model. These
+  // chains have many-character chain names, composed as 'x_n',
+  // where 'x' is the original name and 'n' is a unique number, which
+  // coincides with the symmetry operation (order) number; number '_0'
+  // (for the very first symmetry operatyion) is missing. Another
+  // side effect is the disorder in atoms' serial numbers.
+  //   The hierarchy should therefore be cleaned after
+  // generating the symmetry mates. An appropriate way to do
+  // that is to issue the following call:
+  //
+  //   PDBCleanup ( PDBCLEAN_TER | PDBCLEAN_ALTCODE_STRONG |
+  //                PDBCLEAN_CHAIN_STRONG | PDBCLEAN_SERIAL );
+  //
+  PPCoorManager Mate;
+  int           i,j,k,n,nMates,nMates1,nAtoms1;
+  PPAtom        Atom1;
+  PPModel       Model1;
+
+    if (genSym)  nMates = genSym->GetNofSymOps();
+           else  nMates = cryst.GetNumberOfSymOps();
+    if (nMates<=0)  return GSM_NoSymOps;
+
+    if (!cryst.areMatrices())       return GSM_NoTransfMatrices;
+    if (!cryst.isCellParameters())  return GSM_NoCell;
+
+    nMates1 = nMates-1;
+    if (nMates1>0)  {
+
+      //  Generate symmetry mates in parallel hierarchies
+      Mate = new PCoorManager[nMates1];
+      for (i=0;i<nMates1;i++)  {
+        Mate[i] = new CoorManager();
+        Mate[i]->Copy ( this );
+        Mate[i]->ApplySymTransform ( i+1,genSym );
+      }
+
+      //  apply 1st symmetry operation:
+      if (genSym)  ApplySymTransform ( 0,genSym );
+
+      //  Gather all symmetry mates in 'this' hierarchy
+      nAtoms1 = nMates*nAtoms;        // new number of atoms
+      Atom1   = new PAtom[nAtoms1];  // new array of atoms
+
+      if (nModels>0)  Model1 = new PModel[nModels];  // new array of
+                else  Model1 = NULL;                  // models
+
+      k = 0;  // index of collected atoms
+      for (i=0;i<nModels;i++)
+        if (model[i])  {
+          Model1[i] = newModel();
+          Model1[i]->SetMMDBManager ( PManager(this),i+1 );
+          for (j=0;j<model[i]->nChains;j++)
+            Model1[i]->MoveChain ( model[i]->chain[j],atom,Atom1,k,0 );
+          for (n=0;n<nMates1;n++)
+            for (j=0;j<model[i]->nChains;j++)
+              Model1[i]->MoveChain ( Mate[n]->model[i]->chain[j],
+                                     Mate[n]->atom,Atom1,k,n+1 );
+        } else
+          Model1[i] = NULL;
+
+      if (model) delete[] model;
+      model = Model1;
+
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  delete atom[i];  // should never happen
+      if (atom)  delete[] atom;
+      atom   = Atom1;
+      atmLen = nAtoms1;   // length of Atom array
+      nAtoms = k;
+
+      //  Dispose parallel hierarchies
+      for (i=0;i<nMates1;i++)
+        delete Mate[i];
+      delete[] Mate;
+
+    } else  {
+      //  just apply the only symmetry operation:
+      if (genSym)  ApplySymTransform ( 0,genSym );
+    }
+
+    return GSM_Ok;
+
+  }
+
+  void  CoorManager::ApplyTransform ( mat44 & TMatrix )  {
+  // simply transforms all coordinates by multiplying with matrix TMatrix
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (!atom[i]->Ter)  atom[i]->Transform ( TMatrix );
+      }
+  }
+
+  void  CoorManager::ApplySymTransform ( int SymOpNo, PGenSym genSym ) {
+  //    This procedure applies the symmetry operation number SymOpNo
+  // (starting from 0 on) and renames chains as specified in
+  // GenSym.
+  //    The chains don't have to be renamed. The number of chains
+  // to be renamed is obtained as GenSym->nChains[SymOpNo], their
+  // old names - as GenSym->chID1[SymOpNo][j], and their new names
+  // - as GenSym->chID2[SymOpNo][j],  0<=j<GenSym->nChains[SymOpNo].
+  mat44   tmat;
+  int     i,j,k,nChn;
+  PPChain chain;
+    if (cryst.GetTMatrix(tmat,SymOpNo,0,0,0,PSymOps(genSym))
+         ==SYMOP_Ok)  {
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)  atom[i]->Transform ( tmat );
+        }
+      if (genSym)
+        for (i=0;i<nModels;i++)
+          if (model[i])  {
+            model[i]->GetChainTable ( chain,nChn );
+            for (j=0;j<genSym->nChains[SymOpNo];j++)
+              for (k=0;k<nChn;k++)
+                if (!strcmp(chain[k]->chainID,genSym->chID1[SymOpNo][j]))
+                  chain[k]->SetChainID ( genSym->chID2[SymOpNo][j] );
+          }
+    }
+  }
+
+
+  void  GetEulerRotMatrix ( mat33 & erm,
+                            realtype alpha,
+                            realtype beta,
+                            realtype gamma )  {
+  //  Calculates the Euler rotation matrix for rotation:
+  //                   1) about z-axis by angle alpha (0..2*Pi)
+  //                   2) about new y-axis by angle beta (0..Pi)
+  //                   3) about new z-axis by angle gamma (0..2*Pi)
+  realtype ca,cb,cg, sa,sb,sg;
+
+    ca = cos(alpha);
+    sa = sin(alpha);
+    cb = cos(beta);
+    sb = sin(beta);
+    cg = cos(gamma);
+    sg = sin(gamma);
+
+    erm[0][0] =  ca*cb*cg - sa*sg;
+    erm[0][1] =  cb*cg*sa + ca*sg;
+    erm[0][2] = -cg*sb;
+
+    erm[1][0] = -cg*sa - ca*cb*sg;
+    erm[1][1] =  ca*cg - cb*sa*sg;
+    erm[1][2] =  sb*sg;
+
+    erm[2][0] =  ca*sb;
+    erm[2][1] =  sa*sb;
+    erm[2][2] =  cb;
+
+  }
+
+
+
+  void  GetEulerTMatrix ( mat44 & erm,
+                          realtype alpha,
+                          realtype beta,
+                          realtype gamma,
+                          realtype x0,
+                          realtype y0,
+                          realtype z0 )  {
+  //  Calculates the Euler rotation-translation matrix for rotation:
+  //                   1) about z-axis by angle alpha
+  //                   2) about new y-axis by angle beta
+  //                   3) about new z-axis by angle gamma
+  //  Point (x0,y0,z0) is the center of rotation.
+  mat33 m;
+
+    m[0][0] = 1.0;
+    GetEulerRotMatrix ( m,alpha,beta,gamma );
+
+    erm[0][0] = m[0][0];  erm[0][1] = m[0][1];  erm[0][2] = m[0][2];
+    erm[1][0] = m[1][0];  erm[1][1] = m[1][1];  erm[1][2] = m[1][2];
+    erm[2][0] = m[2][0];  erm[2][1] = m[2][1];  erm[2][2] = m[2][2];
+    erm[3][0] = 0.0;      erm[3][1] = 0.0;      erm[3][2] = 0.0;
+
+    erm[3][3] = 1.0;
+
+    erm[0][3] = x0 - m[0][0]*x0 - m[0][1]*y0 - m[0][2]*z0;
+    erm[1][3] = y0 - m[1][0]*x0 - m[1][1]*y0 - m[1][2]*z0;
+    erm[2][3] = z0 - m[2][0]*x0 - m[2][1]*y0 - m[2][2]*z0;
+
+  }
+
+
+  void  EulerRotation ( PPAtom  A,
+                        int      nA,
+                        realtype alpha,
+                        realtype beta,
+                        realtype gamma,
+                        realtype x0,
+                        realtype y0,
+                        realtype z0 )  {
+  //  Euler rotation:  1) about z-axis by angle alpha
+  //                   2) about new y-axis by angle beta
+  //                   3) about new z-axis by angle gamma
+  //  Point (x0,y0,z0) is the center of rotation.
+  mat33    m;
+  realtype x,y,z;
+  int      i;
+
+    m[0][0] = 1.0;
+    GetEulerRotMatrix ( m,alpha,beta,gamma );
+
+    for (i=0;i<nA;i++)
+      if (A[i])  {
+        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+          x = A[i]->x - x0;
+          y = A[i]->y - y0;
+          z = A[i]->z - z0;
+          A[i]->x = m[0][0]*x + m[0][1]*y + m[0][2]*z + x0;
+          A[i]->y = m[1][0]*x + m[1][1]*y + m[1][2]*z + y0;
+          A[i]->z = m[2][0]*x + m[2][1]*y + m[2][2]*z + z0;
+        }
+      }
+
+  }
+
+
+  void  GetVecRotMatrix ( mat33 & vrm,
+                          realtype alpha,
+                          realtype vx,
+                          realtype vy,
+                          realtype vz )  {
+  //   Calculates the rotation matrix for rotation by angle alpha about
+  // arbitrary vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+  realtype ca,sa, rx,ry,rz, vl;
+
+    ca = cos(alpha);
+    sa = sin(alpha);
+
+    vl = sqrt ( vx*vx + vy*vy + vz*vz );
+    if (vl<=0.0)  return;
+    rx = vx/vl;
+    ry = vy/vl;
+    rz = vz/vl;
+
+    vrm[0][0] = rx*rx*(1.0-ca) + ca;
+    vrm[0][1] = rx*ry*(1.0-ca) - rz*sa;
+    vrm[0][2] = rx*rz*(1.0-ca) + ry*sa;
+
+    vrm[1][0] = ry*rx*(1.0-ca) + rz*sa;
+    vrm[1][1] = ry*ry*(1.0-ca) + ca;
+    vrm[1][2] = ry*rz*(1.0-ca) - rx*sa;
+
+    vrm[2][0] = rz*rx*(1.0-ca) - ry*sa;
+    vrm[2][1] = rz*ry*(1.0-ca) + rx*sa;
+    vrm[2][2] = rz*rz*(1.0-ca) + ca;
+
+  }
+
+
+  void  GetRotParameters ( mat33    & vrm,
+                           realtype & alpha,
+                           realtype & vx,
+                           realtype & vy,
+                           realtype & vz )  {
+  //    Given the rotation matrix vrm, GetRotParameters(..)
+  //  returns the rotation angle alpha and the normalized
+  //  rotation axis vector (vx,vy,vz).
+  //    The rotation angle and vector are determined up to
+  //  their sign (however correlated, so that being substituted
+  //  into GetVecRotMatrix(..) they yield the same rotation
+  //  matrix).
+  //    The function does not check for vrm to be a valid
+  //  rotation matrix.
+  realtype ca,sa,vl;
+    ca = (vrm[0][0]+vrm[1][1]+vrm[2][2]-1.0)/2.0;
+    if (ca<-1.0) ca = -1.0;  // does not work if rotation
+    if (ca>1.0)  ca =  1.0;  //   matrix is correct
+    sa = sqrt(1.0-ca*ca);
+    if (sa>0.0)  {
+      alpha = acos(ca);
+      // coefficient of 2 is corrected by normalization below
+      vx    = (vrm[2][1]-vrm[1][2])/sa;
+      vy    = (vrm[0][2]-vrm[2][0])/sa;
+      vz    = (vrm[1][0]-vrm[0][1])/sa;
+      // the following code is formally redundant if rotation
+      // matrix is correct, however it eliminates the round-offs
+      vl    = sqrt(vx*vx+vy*vy+vz*vz);
+      vx   /= vl;
+      vy   /= vl;
+      vz   /= vl;
+    } else  {
+      // zero rotation, arbitrary axis would do
+      alpha = 0.0;
+      vx    = 1.0;
+      vy    = 0.0;
+      vz    = 0.0;
+    }
+  }
+
+
+  void  GetVecTMatrix ( mat44 & vrm,
+                        realtype alpha,
+                        realtype vx,
+                        realtype vy,
+                        realtype vz,
+                        realtype x0,
+                        realtype y0,
+                        realtype z0 )  {
+  //   Calculates the rotation-translation matrix for rotation by angle
+  // alpha about arbitrary vector directed as (vx,vy,vz) =
+  // (vx2-vx1,vy2-vy1,vz2-vz1). Point (x0,y0,z0) is the center of
+  // rotation -- actually a point belonging to the rotation axis.
+  mat33 m;
+
+    GetVecRotMatrix ( m,alpha,vx,vy,vz );
+
+    vrm[0][0] = m[0][0];  vrm[0][1] = m[0][1];  vrm[0][2] = m[0][2];
+    vrm[1][0] = m[1][0];  vrm[1][1] = m[1][1];  vrm[1][2] = m[1][2];
+    vrm[2][0] = m[2][0];  vrm[2][1] = m[2][1];  vrm[2][2] = m[2][2];
+    vrm[3][0] = 0.0;      vrm[3][1] = 0.0;      vrm[3][2] = 0.0;
+
+    vrm[3][3] = 1.0;
+
+    vrm[0][3] = x0 - m[0][0]*x0 - m[0][1]*y0 - m[0][2]*z0;
+    vrm[1][3] = y0 - m[1][0]*x0 - m[1][1]*y0 - m[1][2]*z0;
+    vrm[2][3] = z0 - m[2][0]*x0 - m[2][1]*y0 - m[2][2]*z0;
+
+  }
+
+
+  void  VectorRotation ( PPAtom  A,
+                         int      nA,
+                         realtype alpha,
+                         realtype vx,
+                         realtype vy,
+                         realtype vz,
+                         realtype x0,
+                         realtype y0,
+                         realtype z0 )  {
+  //   Vector rotation is rotation by angle alpha about arbitrary
+  // vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+  // Point (x0,y0,z0) is the center of rotation -- actually
+  // a point belonging to the rotation axis.
+  mat33    m;
+  realtype x,y,z;
+  int      i;
+
+    GetVecRotMatrix ( m, alpha,vx,vy,vz );
+
+    for (i=0;i<nA;i++)
+      if (A[i])  {
+        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+          x = A[i]->x - x0;
+          y = A[i]->y - y0;
+          z = A[i]->z - z0;
+          A[i]->x = m[0][0]*x + m[0][1]*y + m[0][2]*z + x0;
+          A[i]->y = m[1][0]*x + m[1][1]*y + m[1][2]*z + y0;
+          A[i]->z = m[2][0]*x + m[2][1]*y + m[2][2]*z + z0;
+        }
+      }
+
+  }
+
+
+  void  GetMassCenter ( PPAtom    A,   int        nA,
+                        realtype & xmc, realtype & ymc,
+                        realtype & zmc )  {
+  realtype w,mass;
+  int      i,k;
+
+    xmc  = 0.0;
+    ymc  = 0.0;
+    zmc  = 0.0;
+    mass = 0.0;
+
+    for (i=0;i<nA;i++)
+      if (A[i])  {
+        if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+          k = getElementNo ( A[i]->element );
+          if (k>=0)  w = MolecWeight[k];
+               else  w = 1.0;
+          xmc  += w*A[i]->x;
+          ymc  += w*A[i]->y;
+          zmc  += w*A[i]->z;
+          mass += w;
+        }
+      }
+
+    if (mass>0.0)  {
+      xmc /= mass;
+      ymc /= mass;
+      zmc /= mass;
+    }
+
+  }
+
+  int CoorManager::BringToUnitCell()  {
+  // brings all chains into 0th unit cell
+  PChain    chain;
+  PPAtom    atom;
+  realtype  x0,y0,z0, x,y,z, xf,yf,zf, sx,sy,sz;
+  realtype  dx,dy,dz, d,d0;
+  int       nAtoms;
+  int       i,j,k,n,m,nt, ic,jc,kc, is,js,ks;
+
+    if (!cryst.areMatrices())  return -1;
+
+    is = 0;  // this is only
+    js = 0;  //   to depress
+    ks = 0;  //      "uninitialized" worning
+
+    cryst.Frac2Orth ( 0.5,0.5,0.5, x0,y0,z0 );
+
+    nt = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  {
+        for (j=0;j<model[i]->nChains;j++)  {
+          chain = model[i]->chain[j];
+          if (chain)  {
+
+            x = 0.0;
+            y = 0.0;
+            z = 0.0;
+            m = 0;
+            for (k=0;k<chain->nResidues;k++)
+              if (chain->residue[k])  {
+                chain->residue[k]->GetAtomTable ( atom,nAtoms );
+                for (n=0;n<nAtoms;n++)
+                  if (atom[n])  {
+                    if (!atom[n]->Ter)  {
+                      x += atom[n]->x;
+                      y += atom[n]->y;
+                      z += atom[n]->z;
+                      m++;
+                    }
+                  }
+              }
+            x /= m;
+            y /= m;
+            z /= m;
+
+            cryst.Orth2Frac ( x,y,z, xf,yf,zf );
+            sx = frac ( xf );
+            sy = frac ( yf );
+            sz = frac ( zf );
+            d0 = MaxReal;
+            for (ic=-3;ic<3;ic++)
+              for (jc=-3;jc<3;jc++)
+                for (kc=-3;kc<3;kc++)  {
+                  cryst.Frac2Orth ( sx+ic,sy+jc,sz+kc, dx,dy,dz );
+                  dx -= x0;
+                  dy -= y0;
+                  dz -= z0;
+                  d = dx*dx + dy*dy + dz*dz;
+                  if (d<d0)  {
+                    d0 = d;
+                    is = ic;
+                    js = jc;
+                    ks = kc;
+                  }
+                }
+
+            sx = xf - (sx+is);
+            sy = yf - (sy+js);
+            sz = zf - (sz+ks);
+
+            if ((fabs(sx)>1.0e-10) || (fabs(sy)>1.0e-10)
+                                   || (fabs(sz)>1.0e-10))  {
+              nt++;
+              for (k=0;k<chain->nResidues;k++)
+                if (chain->residue[k])  {
+                  chain->residue[k]->GetAtomTable ( atom,nAtoms );
+                  for (n=0;n<nAtoms;n++)
+                    if (atom[n])  {
+                      if (!atom[n]->Ter)  {
+                        cryst.Orth2Frac ( atom[n]->x,atom[n]->y,
+                                          atom[n]->z,
+                                          xf,yf,zf );
+                        cryst.Frac2Orth ( xf-sx,yf-sy,zf-sz,
+                                          atom[n]->x,atom[n]->y,
+                                          atom[n]->z );
+                      }
+                    }
+                }
+            }
+
+          }
+        }
+      }
+
+    return nt;  // number of converted chains
+
+  }
+
+
+  bool CoorManager::Frac2Orth (
+                realtype   xfrac, realtype   yfrac, realtype   zfrac,
+                realtype & xorth, realtype & yorth, realtype & zorth )  {
+    return cryst.Frac2Orth ( xfrac,yfrac,zfrac, xorth,yorth,zorth );
+  }
+
+  bool CoorManager::Orth2Frac (
+                realtype   xorth, realtype   yorth, realtype   zorth,
+                realtype & xfrac, realtype & yfrac, realtype & zfrac )  {
+    return cryst.Orth2Frac ( xorth,yorth,zorth, xfrac,yfrac,zfrac );
+  }
+
+
+  bool CoorManager::Frac2Orth ( mat44 & F, mat44 & T )  {
+    return cryst.Frac2Orth ( F,T );
+  }
+
+  bool CoorManager::Orth2Frac ( mat44 & T, mat44 & F )  {
+    return cryst.Orth2Frac ( T,F );
+  }
+
+
+
+  //  ------------------------  Contacts  -------------------------------
+
+
+  #define  CA_CA_Dist2  16.0
+
+  void  CoorManager::FindSeqSection ( PAtom atom, int seqDist,
+                                           int  & seq1, int & seq2 )  {
+  PAtom    a;
+  PResidue res;
+  PChain   chain;
+  realtype  x0,y0,z0, x,y,z, dx,dy,dz, d2;
+  int       i1;
+  bool   B0,B;
+
+    x  = 0.0;
+    y  = 0.0;
+    z  = 0.0;
+    x0 = 0.0;
+    y0 = 0.0;
+    z0 = 0.0;
+
+    res = atom->residue;
+    if ((!res) || (seqDist<=0))  {
+      seq1 = MaxInt4;
+      seq2 = MinInt4;
+      return;
+    }
+
+    chain = res->chain;
+    if (!chain)  {
+      seq1 = MaxInt4;
+      seq2 = MinInt4;
+      return;
+    }
+
+    if (seqDist==1)  {
+      seq1 = res->index;
+      seq2 = seq1;
+      return;
+    }
+
+    a = res->GetAtom ( pstr("CA"),pstr("C"),NULL );
+    if (a)  {
+      x0 = a->x;
+      y0 = a->y;
+      z0 = a->z;
+      B0 = true;
+    } else
+      B0 = false;
+    if (B0)  {
+      x = x0;
+      y = y0;
+      z = z0;
+    }
+
+    B    = B0;
+    seq2 = res->index;
+    i1   = IMin(chain->nResidues,seq2+seqDist)-1;
+    while (seq2<i1)  {
+      seq2++;
+      if (chain->residue[seq2])  {
+        a = chain->residue[seq2]->GetAtom ( pstr("CA"),pstr("C"),NULL );
+        if (a && B)  {
+          dx = x-a->x;
+          dy = y-a->y;
+          dz = z-a->z;
+          d2 = dx*dx + dy*dy + dz*dz;
+          if (d2>CA_CA_Dist2)  {
+            seq2--;
+            break;
+          }
+        }
+        if (a)  {
+          x = a->x;
+          y = a->y;
+          z = a->z;
+          B = true;
+        } else
+          B = false;
+      }
+    }
+
+    if (B0)  {
+      x = x0;
+      y = y0;
+      z = z0;
+    }
+    B    = B0;
+    seq1 = res->index;
+    i1   = IMax(0,seq1-seqDist+1);
+    while (seq1>i1)  {
+      seq1--;
+      if (chain->residue[seq1])  {
+        a = chain->residue[seq1]->GetAtom ( pstr("CA"),pstr("C"),NULL );
+        if (a && B)  {
+          dx = x-a->x;
+          dy = y-a->y;
+          dz = z-a->z;
+          d2 = dx*dx + dy*dy + dz*dz;
+          if (d2>CA_CA_Dist2)  {
+            seq1++;
+            break;
+          }
+        }
+        if (a)  {
+          x = a->x;
+          y = a->y;
+          z = a->z;
+          B = true;
+        } else
+          B = false;
+      }
+    }
+
+  }
+
+
+  bool  CoorManager::iContact ( PAtom    a1, PAtom    a2,
+                                         int     seq1, int     seq2,
+                                         realtype  dd, realtype d12,
+                                         realtype d22, realtype & d2 )  {
+  //  seq1..seq2 is forbidden region for residue sequence numbers
+  PResidue  res1,res2;
+  PChain    chain1,chain2;
+  realtype   dx,dy,dz;
+
+    if (a2->Ter)  return false;
+
+    dx = fabs(a2->x-a1->x);
+    if (dx<=dd)  {
+      dy = fabs(a2->y-a1->y);
+      if (dy<=dd)  {
+        dz = fabs(a2->z-a1->z);
+        if (dz<=dd)  {
+          d2 = dx*dx + dy*dy + dz*dz;
+          if ((d12<=d2) && (d2<=d22))  {
+            if (seq1<=seq2)  {
+              res1 = a1->residue;
+              res2 = a2->residue;
+              if (res1 && res2)  {
+                chain1 = res1->chain;
+                chain2 = res2->chain;
+                if (chain1 && chain2)  {
+                  if (!strcmp(chain1->chainID,chain2->chainID))  {
+                    if ((seq1<=res2->index) && (res2->index<=seq2))
+                      return false;
+                  }
+                }
+              }
+            }
+            return true;
+          }
+        }
+      }
+    }
+
+    return false;
+
+  }
+
+  bool  CoorManager::iContact ( realtype   x, realtype   y,
+                                         realtype   z, PAtom    a2,
+                                         realtype  dd, realtype d12,
+                                         realtype d22, realtype & d2 )  {
+  realtype dx,dy,dz;
+
+    if (a2->Ter)  return false;
+
+    dx = fabs(a2->x-x);
+    if (dx<=dd)  {
+      dy = fabs(a2->y-y);
+      if (dy<=dd)  {
+        dz = fabs(a2->z-z);
+        if (dz<=dd)  {
+          d2 = dx*dx + dy*dy + dz*dz;
+          if ((d12<=d2) && (d2<=d22))  return true;
+        }
+      }
+    }
+
+    return false;
+
+  }
+
+
+  void  CoorManager::SeekContacts ( PPAtom    AIndex,
+                                         int        ilen,
+                                         int        atomNum,
+                                         realtype   dist1,
+                                         realtype   dist2,
+                                         int        seqDist,
+                                         RPContact contact,
+                                         int &      ncontacts,
+                                         int        maxlen,
+                                         long       group )  {
+  PContactIndex contactIndex;
+  realtype      d12,d22,d2;
+  int           i,seq1,seq2;
+
+    if (!AIndex)              return;
+    if (dist2<dist1)          return;
+    if (!AIndex[atomNum])     return;
+    if (AIndex[atomNum]->Ter) return;
+
+    contactIndex = new ContactIndex ( contact,maxlen,ncontacts,ilen );
+
+    FindSeqSection ( AIndex[atomNum],seqDist,seq1,seq2 );
+
+    d12 = dist1*dist1;
+    d22 = dist2*dist2;
+
+    for (i=0;i<ilen;i++)
+      if ((i!=atomNum) && AIndex[i])  {
+        if (iContact(AIndex[atomNum],AIndex[i],seq1,seq2,dist2,
+                      d12,d22,d2))
+           contactIndex->AddContact ( atomNum,i,sqrt(d2),group );
+      }
+
+    contactIndex->GetIndex ( contact,ncontacts );
+
+    delete contactIndex;
+
+  }
+
+
+  void  CoorManager::SeekContacts ( PAtom     A,
+                                         PPAtom    AIndex,
+                                         int        ilen,
+                                         realtype   dist1,
+                                         realtype   dist2,
+                                         int        seqDist,
+                                         RPContact contact,
+                                         int &      ncontacts,
+                                         int        maxlen,
+                                         long       group
+                                       )  {
+  PContactIndex contactIndex;
+  realtype      d12,d22,d2;
+  int           i,seq1,seq2;
+
+    if (!AIndex)     return;
+    if (dist2<dist1) return;
+    if (!A)          return;
+    if (A->Ter)      return;
+
+    contactIndex = new ContactIndex ( contact,maxlen,ncontacts,ilen );
+
+    FindSeqSection ( A,seqDist,seq1,seq2 );
+
+    d12 = dist1*dist1;
+    d22 = dist2*dist2;
+
+    for (i=0;i<ilen;i++)
+      if ((AIndex[i]!=A) && AIndex[i])  {
+        if (iContact(A,AIndex[i],seq1,seq2,dist2,d12,d22,d2))
+          contactIndex->AddContact ( -1,i,sqrt(d2),group );
+      }
+
+    contactIndex->GetIndex ( contact,ncontacts );
+
+    delete contactIndex;
+
+  }
+
+
+  void  CoorManager::SeekContacts ( PPAtom    AIndex1,
+                                         int        ilen1,
+                                         PPAtom    AIndex2,
+                                         int        ilen2,
+                                         realtype   dist1,
+                                         realtype   dist2,
+                                         int        seqDist,
+                                         RPContact contact,
+                                         int &      ncontacts,
+                                         int        maxlen,
+                                         mat44 *    TMatrix,
+                                         long       group,
+                                         int        bricking,
+                                         bool    doSqrt
+                                       )  {
+  //  It is Ok to have NULL pointers in AIndex1 and AIndex2
+  PContactIndex contactIndex;
+  PPAtom        A1,A2;
+  rvector       sx0,sy0,sz0;
+  rvector       dx0,dy0,dz0;
+  realtype      d12,d22,d2, eps;
+  int           l1,l2, i,j, nx,ny,nz, dn;
+  int           ix1,ix2, iy1,iy2, iz1,iz2, ix,iy,iz;
+  int           seq1,seq2;
+  PBrick        B;
+  bool          swap,UnitT;
+
+    if ((dist2<dist1) || (!AIndex1) || (!AIndex2))  return;
+
+    contactIndex = new ContactIndex ( contact,maxlen,ncontacts,
+                                      ilen1*ilen2 );
+
+    sx0   = NULL;
+    sy0   = NULL;
+    sz0   = NULL;
+    dx0   = NULL;
+    dy0   = NULL;
+    dz0   = NULL;
+    UnitT = true;
+    if (TMatrix)  {
+      // Transformation matrix is given. Check that that is not
+      // the unit one.
+      eps = 1.0e-6;
+      for (i=0;(i<3) && UnitT;i++)
+        for (j=0;(j<4) && UnitT;j++)
+          if (i==j)  UnitT = fabs(1.0-(*TMatrix)[i][j])<eps;
+               else  UnitT = fabs((*TMatrix)[i][j])<eps;
+      if (!UnitT)  {
+        // A non-unit transformation to AIndex2 is required.
+        // As AIndex1 and AIndex2 may overlap, we have to save
+        // the original AIndex1 coordinates
+        GetVectorMemory ( sx0,ilen1,0 );
+        GetVectorMemory ( sy0,ilen1,0 );
+        GetVectorMemory ( sz0,ilen1,0 );
+        for (i=0;i<ilen1;i++)
+          if (AIndex1[i])  {
+            sx0[i] = AIndex1[i]->x;
+            sy0[i] = AIndex1[i]->y;
+            sz0[i] = AIndex1[i]->z;
+          }
+        // Save original AIndex2 coordinates and modify the index
+        GetVectorMemory ( dx0,ilen2,0 );
+        GetVectorMemory ( dy0,ilen2,0 );
+        GetVectorMemory ( dz0,ilen2,0 );
+        for (i=0;i<ilen2;i++)
+          if (AIndex2[i])  {
+            dx0[i] = AIndex2[i]->x;
+            dy0[i] = AIndex2[i]->y;
+            dz0[i] = AIndex2[i]->z;
+            AIndex2[i]->Transform ( *TMatrix );
+          }
+      }
+    }
+
+    // choose A2 as the largest atom set convenient for
+    // bricking (bricking on larger set is more efficient)
+    if (bricking & BRICK_ON_1)  {
+      A1   = AIndex2;
+      A2   = AIndex1;
+      l1   = ilen2;
+      l2   = ilen1;
+      swap = true;
+    } else if (bricking & BRICK_ON_2)  {
+      A1   = AIndex1;
+      A2   = AIndex2;
+      l1   = ilen1;
+      l2   = ilen2;
+      swap = false;
+    } else if (ilen1<=ilen2)  {
+      A1   = AIndex1;
+      A2   = AIndex2;
+      l1   = ilen1;
+      l2   = ilen2;
+      swap = false;
+    } else  {
+      A1   = AIndex2;
+      A2   = AIndex1;
+      l1   = ilen2;
+      l2   = ilen1;
+      swap = true;
+    }
+
+    d12 = dist1*dist1;
+    d22 = dist2*dist2;
+
+    if (((bricking & BRICK_READY)==0) || (!brick))
+      MakeBricks ( A2,l2,dist2*1.5 );
+
+    dn = mround(dist2/brick_size)+1;
+
+    if (brick)
+      for (i=0;i<l1;i++)
+        if (A1[i])  {
+          if (!A1[i]->Ter)  {
+            if (UnitT)  {
+              // No transformation -- AIndex1 and AIndex2 are unmodified.
+              // Calculate the forbidden sequence region
+              FindSeqSection ( A1[i],seqDist,seq1,seq2 );
+              // And the brick location
+              GetBrickCoor   ( A1[i],nx,ny,nz );
+            } else  {
+              // AIndex2 and AIndex1 are modified, but the sequence
+              // distance does not apply to physically different chains
+              // (meaning that transformation of A2 effectively makes
+              // a different chain). Use unmodified atom coordinates
+              // of 1st set for calculating the brick location.
+              if (swap) GetBrickCoor ( A1[i],nx,ny,nz ); // A1 is AIndex2
+                   else GetBrickCoor ( sx0[i],sy0[i],sz0[i],nx,ny,nz );
+          }
+          if (nx>=0)  {
+            ix1 = IMax ( 0,nx-dn );
+            iy1 = IMax ( 0,ny-dn );
+            iz1 = IMax ( 0,nz-dn );
+            ix2 = IMin ( nbrick_x,nx+dn+1 );
+            iy2 = IMin ( nbrick_y,ny+dn+1 );
+            iz2 = IMin ( nbrick_z,nz+dn+1 );
+            if (UnitT)  {
+              // AIndex1 unmodified, use it
+              for (ix=ix1;ix<ix2;ix++)
+                if (brick[ix])
+                  for (iy=iy1;iy<iy2;iy++)
+                    if (brick[ix][iy])
+                      for (iz=iz1;iz<iz2;iz++)  {
+                        B = brick[ix][iy][iz];
+                        if (B)
+                          for (j=0;j<B->nAtoms;j++)
+                            if (B->atom[j]!=A1[i])  {
+                              if (iContact(A1[i],B->atom[j],seq1,seq2,
+                                            dist2,d12,d22,d2))  {
+                                if (doSqrt)  d2 = sqrt(d2);
+                                if (swap)  contactIndex->AddContact (
+                                             B->id[j],i,d2,group );
+                                     else  contactIndex->AddContact (
+                                             i,B->id[j],d2,group );
+                              }
+                            }
+                      }
+            } else if (swap)  {
+              // A1 stands for AIndex2, it is modified and we need to use
+              // the modified coordinates
+              for (ix=ix1;ix<ix2;ix++)
+                if (brick[ix])
+                  for (iy=iy1;iy<iy2;iy++)
+                    if (brick[ix][iy])
+                      for (iz=iz1;iz<iz2;iz++)  {
+                        B = brick[ix][iy][iz];
+                        if (B)
+                          for (j=0;j<B->nAtoms;j++)
+                            if (iContact(A1[i]->x,A1[i]->y,A1[i]->z,
+                                          B->atom[j], dist2,d12,d22,d2))  {
+                              if (doSqrt)  d2 = sqrt(d2);
+                              contactIndex->AddContact ( B->id[j],i,d2,group );
+                            }
+                      }
+            } else  {
+              // A1 stands for AIndex1, it may be modified (if AIndex1
+              // and AIndex2 overlap) -- use its unmodified coordinates
+              // instead.
+              for (ix=ix1;ix<ix2;ix++)
+                if (brick[ix])
+                  for (iy=iy1;iy<iy2;iy++)
+                    if (brick[ix][iy])
+                      for (iz=iz1;iz<iz2;iz++)  {
+                        B = brick[ix][iy][iz];
+                        if (B)
+                          for (j=0;j<B->nAtoms;j++)
+                            if (iContact(sx0[i],sy0[i],sz0[i],
+                                          B->atom[j],dist2,d12,d22,d2))  {
+                              if (doSqrt)  d2 = sqrt(d2);
+                              contactIndex->AddContact ( i,B->id[j],d2,group );
+                            }
+                      }
+            }
+          }
+        }
+      }
+
+
+    if (!UnitT)  {
+      // restore original coordinates
+      for (i=0;i<ilen1;i++)
+        if (AIndex1[i])  {
+          AIndex1[i]->x = sx0[i];
+          AIndex1[i]->y = sy0[i];
+          AIndex1[i]->z = sz0[i];
+        }
+      for (i=0;i<ilen2;i++)
+        if (AIndex2[i])  {
+          AIndex2[i]->x = dx0[i];
+          AIndex2[i]->y = dy0[i];
+          AIndex2[i]->z = dz0[i];
+        }
+      FreeVectorMemory ( sx0,0 );
+      FreeVectorMemory ( sy0,0 );
+      FreeVectorMemory ( sz0,0 );
+      FreeVectorMemory ( dx0,0 );
+      FreeVectorMemory ( dy0,0 );
+      FreeVectorMemory ( dz0,0 );
+    }
+
+    contactIndex->GetIndex ( contact,ncontacts );
+
+    delete contactIndex;
+
+  }
+
+
+  void  CoorManager::SeekContacts ( PPAtom   AIndex1,
+                                    int      ilen1,
+                                    PPAtom   AIndex2,
+                                    int      ilen2,
+                                    realtype contDist,
+                                    PContact contact,
+                                    int &    ncontacts,
+                                    int      bricking
+                                   )  {
+  //  Simplified optimized for speed version:
+  //    - no NULL pointers and Ters in AIndex1 and AIndex2
+  //    - no checks for identity atoms in AIndex1 and AIndex2
+  //    - contact must be pre-allocated with at least ilen1*ilen2 elements
+  //    - contact returns square distances
+  //    - ncontacts is always reset
+  PPAtom   A1,A2;
+  realtype contDist2, dx,dy,dz, d2;
+  int      l1,l2, i,j, nx,ny,nz, dn;
+  int      ix1,ix2, iy1,iy2, iz1,iz2, ix,iy,iz;
+  PBrick   B;
+  bool     swap;
+
+    // choose A2 as the largest atom set convenient for
+    // bricking (bricking on larger set is more efficient)
+    if (bricking & BRICK_ON_1)  {
+      A1   = AIndex2;
+      A2   = AIndex1;
+      l1   = ilen2;
+      l2   = ilen1;
+      swap = true;
+    } else if (bricking & BRICK_ON_2)  {
+      A1   = AIndex1;
+      A2   = AIndex2;
+      l1   = ilen1;
+      l2   = ilen2;
+      swap = false;
+    } else if (ilen1<=ilen2)  {
+      A1   = AIndex1;
+      A2   = AIndex2;
+      l1   = ilen1;
+      l2   = ilen2;
+      swap = false;
+    } else  {
+      A1   = AIndex2;
+      A2   = AIndex1;
+      l1   = ilen2;
+      l2   = ilen1;
+      swap = true;
+    }
+
+    contDist2 = contDist*contDist;
+
+    if (((bricking & BRICK_READY)==0) || (!brick))
+      MakeBricks ( A2,l2,contDist*1.5 );
+
+    ncontacts = 0;
+
+    if (!brick)  return;
+
+    dn = (int)floor(contDist/brick_size)+1;
+
+    if (swap)  {
+
+      for (i=0;i<l1;i++)
+        if (A1[i])  {
+          // Find brick location
+          GetBrickCoor ( A1[i],nx,ny,nz );
+          if (nx>=0)  {
+            ix1 = IMax ( 0,nx-dn );
+            iy1 = IMax ( 0,ny-dn );
+            iz1 = IMax ( 0,nz-dn );
+            ix2 = IMin ( nbrick_x,nx+dn+1 );
+            iy2 = IMin ( nbrick_y,ny+dn+1 );
+            iz2 = IMin ( nbrick_z,nz+dn+1 );
+            for (ix=ix1;ix<ix2;ix++)
+              if (brick[ix])
+                for (iy=iy1;iy<iy2;iy++)
+                  if (brick[ix][iy])
+                    for (iz=iz1;iz<iz2;iz++)  {
+                      B = brick[ix][iy][iz];
+                      if (B)
+                        for (j=0;j<B->nAtoms;j++)  {
+                          dx = A1[i]->x - B->atom[j]->x;
+                          dy = A1[i]->y - B->atom[j]->y;
+                          dz = A1[i]->z - B->atom[j]->z;
+                          d2 = dx*dx + dy*dy + dz*dz;
+                          if (d2<=contDist2)  {
+                            contact[ncontacts].id1  = B->id[j];
+                            contact[ncontacts].id2  = i;
+                            contact[ncontacts].dist = d2;
+                            ncontacts++;
+                          }
+                        }
+                    }
+          }
+        }
+
+    } else  {
+
+      for (i=0;i<l1;i++)
+        if (A1[i])  {
+          // Find brick location
+          GetBrickCoor ( A1[i],nx,ny,nz );
+          if (nx>=0)  {
+            ix1 = IMax ( 0,nx-dn );
+            iy1 = IMax ( 0,ny-dn );
+            iz1 = IMax ( 0,nz-dn );
+            ix2 = IMin ( nbrick_x,nx+dn+1 );
+            iy2 = IMin ( nbrick_y,ny+dn+1 );
+            iz2 = IMin ( nbrick_z,nz+dn+1 );
+            for (ix=ix1;ix<ix2;ix++)
+              if (brick[ix])
+                for (iy=iy1;iy<iy2;iy++)
+                  if (brick[ix][iy])
+                    for (iz=iz1;iz<iz2;iz++)  {
+                      B = brick[ix][iy][iz];
+                      if (B)
+                        for (j=0;j<B->nAtoms;j++)  {
+                          dx = A1[i]->x - B->atom[j]->x;
+                          dy = A1[i]->y - B->atom[j]->y;
+                          dz = A1[i]->z - B->atom[j]->z;
+                          d2 = dx*dx + dy*dy + dz*dz;
+                          if (d2<=contDist2)  {
+                            contact[ncontacts].id1  = i;
+                            contact[ncontacts].id2  = B->id[j];
+                            contact[ncontacts].dist = d2;
+                            ncontacts++;
+                          }
+                        }
+                    }
+          }
+        }
+
+    }
+
+  }
+
+
+  void  CoorManager::SeekContacts ( PPAtom     AIndex1,
+                                         int         ilen1,
+                                         PPAtom *   AIndex2,
+                                         ivector     ilen2,
+                                         int         nStructures,
+                                         realtype    dist1,
+                                         realtype    dist2,
+                                         PPMContact & contact,
+                                         int         bricking
+                                       )  {
+  //  It is Ok to have NULL pointers in AIndex1 and AIndex2
+  PMBrick B;
+  PAtom   A;
+  realtype d12,d22,d2;
+  int      dn, i,j,k, nx,ny,nz, ix1,iy1,iz1, ix2,iy2,iz2;
+  int      ix,iy,iz;
+
+    if (dist2<dist1)              return;
+    if ((!AIndex1) || (!AIndex2)) return;
+
+    d12 = dist1*dist1;
+    d22 = dist2*dist2;
+
+    if (((bricking & BRICK_READY)==0) || (!mbrick))
+      MakeMBricks ( AIndex2,ilen2,nStructures,dist2*1.5 );
+
+    contact = new PMContact[ilen1];
+
+    dn = mround(dist2/brick_size)+1;
+
+    if (mbrick)
+      for (i=0;i<ilen1;i++)  {
+        A = AIndex1[i];
+        contact[i] = NULL;
+        if (A)  {
+          if (!A->Ter)  {
+            contact[i] = new MContact(nStructures);
+            contact[i]->contactID = i;
+            //  Calculate the brick location
+            GetMBrickCoor ( A,nx,ny,nz );
+            if (nx>=0)  {
+              ix1 = IMax ( 0,nx-dn );
+              iy1 = IMax ( 0,ny-dn );
+              iz1 = IMax ( 0,nz-dn );
+              ix2 = IMin ( nmbrick_x,nx+dn+1 );
+              iy2 = IMin ( nmbrick_y,ny+dn+1 );
+              iz2 = IMin ( nmbrick_z,nz+dn+1 );
+              for (ix=ix1;ix<ix2;ix++)
+                if (mbrick[ix])
+                  for (iy=iy1;iy<iy2;iy++)
+                    if (mbrick[ix][iy])
+                      for (iz=iz1;iz<iz2;iz++)  {
+                        B = mbrick[ix][iy][iz];
+                        if (B)
+                          for (j=0;j<nStructures;j++)
+                            for (k=0;k<B->nAtoms[j];k++)
+                              if (B->atom[j][k]!=A)  {
+                                if (iContact(A,B->atom[j][k],
+                                              MaxInt4,MinInt4,
+                                              dist2,d12,d22,d2))
+                                  contact[i]->AddContact (
+                                         B->atom[j][k],j,B->id[j][k] );
+                              }
+                      }
+            }
+          }
+        }
+      }
+    else
+      for (i=0;i<ilen1;i++)
+        contact[i] = NULL;
+
+  }
+
+
+
+  DefineClass(QSortContacts)
+
+  class QSortContacts : public QuickSort  {
+    public :
+      QSortContacts() : QuickSort() {}
+      int  Compare ( int i, int j );
+      void Swap    ( int i, int j );
+      void Sort    ( PContact contact, int ncontacts, int sortmode );
+    protected :
+      int  mode;
+  };
+
+  int QSortContacts::Compare ( int i, int j )  {
+  bool gt,lt;
+    switch (mode)  {
+      default          :
+      case CNSORT_1INC : gt = (((PContact)data)[i].id1 >
+                               ((PContact)data)[j].id1);
+                         lt = (((PContact)data)[i].id1 <
+                               ((PContact)data)[j].id1);
+                     break;
+      case CNSORT_1DEC : gt = (((PContact)data)[j].id1 >
+                               ((PContact)data)[i].id1);
+                         lt = (((PContact)data)[j].id1 <
+                               ((PContact)data)[i].id1);
+                     break;
+      case CNSORT_2INC : gt = (((PContact)data)[i].id2 >
+                               ((PContact)data)[j].id2);
+                         lt = (((PContact)data)[i].id2 <
+                               ((PContact)data)[j].id2);
+                     break;
+      case CNSORT_2DEC : gt = (((PContact)data)[j].id2 >
+                               ((PContact)data)[i].id2);
+                         lt = (((PContact)data)[j].id2 <
+                               ((PContact)data)[i].id2);
+                     break;
+      case CNSORT_DINC : gt = (((PContact)data)[i].dist >
+                               ((PContact)data)[j].dist);
+                         lt = (((PContact)data)[i].dist <
+                               ((PContact)data)[j].dist);
+                     break;
+      case CNSORT_DDEC : gt = (((PContact)data)[j].dist >
+                               ((PContact)data)[i].dist);
+                         lt = (((PContact)data)[j].dist <
+                               ((PContact)data)[i].dist);
+                     break;
+    }
+    if (gt)  return  1;
+    if (lt)  return -1;
+    return 0;
+  }
+
+  void QSortContacts::Swap ( int i, int j )  {
+    ((PContact)data)[i].Swap ( ((PContact)data)[j] );
+  }
+
+
+  void QSortContacts::Sort ( PContact contact, int ncontacts,
+                             int sortmode )  {
+    mode = sortmode;
+    if (mode!=CNSORT_OFF)
+      QuickSort::Sort ( &(contact[0]),ncontacts );
+  }
+
+
+  void  SortContacts ( PContact contact, int ncontacts,
+                       CNSORT_DIR sortmode )  {
+  QSortContacts SC;
+    if (sortmode!=CNSORT_OFF)
+      SC.Sort ( contact,ncontacts,sortmode );
+  }
+
+
+  //  -------------------  Stream functions  ----------------------
+
+  void  CoorManager::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version    );
+    Root::write ( f );
+    f.WriteInt  ( &CoorIDCode );
+    f.WriteReal ( &brick_size );
+    f.WriteReal ( &xbrick_0   );
+    f.WriteReal ( &ybrick_0   );
+    f.WriteReal ( &zbrick_0   );
+    f.WriteInt  ( &nbrick_x   );
+    f.WriteInt  ( &nbrick_y   );
+    f.WriteInt  ( &nbrick_z   );
+  }
+
+  void  CoorManager::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version    );
+    Root::read ( f );
+    f.ReadInt  ( &CoorIDCode );
+    f.ReadReal ( &brick_size );
+    f.ReadReal ( &xbrick_0   );
+    f.ReadReal ( &ybrick_0   );
+    f.ReadReal ( &zbrick_0   );
+    f.ReadInt  ( &nbrick_x   );
+    f.ReadInt  ( &nbrick_y   );
+    f.ReadInt  ( &nbrick_z   );
+  }
+
+
+  MakeStreamFunctions(CoorManager);
+
+
+
+
+  // ===================================================================
+
+  int  SuperposeAtoms ( mat44 & T, PPAtom A1, int nA, PPAtom A2,
+                        ivector C )  {
+  realtype xc1,yc1,zc1, xc2,yc2,zc2, det,B;
+  rmatrix  A,U,V;
+  rvector  W,RV1;
+  vect3    vc1,vc2;
+  int      i,j,k,i1,i2,nat;
+
+
+    //  1. Set unit matrix as "default" return
+
+    for (i=0;i<4;i++)  {
+      for (j=0;j<4;j++)
+        T[i][j] = 0.0;
+      T[i][i] = 1.0;
+    }
+
+
+    //  2. Calculate mass centers
+
+    xc1 = 0.0;
+    yc1 = 0.0;
+    zc1 = 0.0;
+    xc2 = 0.0;
+    yc2 = 0.0;
+    zc2 = 0.0;
+
+    nat = 0;
+    if (C)  {
+
+      for (i1=0;i1<nA;i1++)
+        if (!A1[i1]->Ter)  {
+          i2 = C[i1];
+          if (i2>=0)  {
+            xc1 += A1[i1]->x;
+            yc1 += A1[i1]->y;
+            zc1 += A1[i1]->z;
+            xc2 += A2[i2]->x;
+            yc2 += A2[i2]->y;
+            zc2 += A2[i2]->z;
+            nat++;
+          }
+        }
+
+    } else  {
+
+      for (i=0;i<nA;i++)
+        if ((!A1[i]->Ter) && (!A2[i]->Ter))  {
+          xc1 += A1[i]->x;
+          yc1 += A1[i]->y;
+          zc1 += A1[i]->z;
+          xc2 += A2[i]->x;
+          yc2 += A2[i]->y;
+          zc2 += A2[i]->z;
+          nat++;
+        }
+
+    }
+
+    if (nat>1)  {
+      xc1 /= nat;
+      yc1 /= nat;
+      zc1 /= nat;
+      xc2 /= nat;
+      yc2 /= nat;
+      zc2 /= nat;
+    } else if (nat>0)  {
+      T[0][3] = xc2 - xc1;
+      T[1][3] = yc2 - yc1;
+      T[2][3] = zc2 - zc1;
+      return SPOSEAT_Ok;
+    } else
+      return SPOSEAT_NoAtoms;
+
+
+    //  3.  Calculate the correlation matrix
+
+    GetMatrixMemory ( A,3,3,1,1 );
+
+    for (i=1;i<=3;i++)
+      for (j=1;j<=3;j++)
+        A[i][j] = 0.0;
+
+    if (C)  {
+
+      for (i1=0;i1<nA;i1++)
+        if (!A1[i1]->Ter)  {
+          i2 = C[i1];
+          if (i2>=0)  {
+            vc1[0] = A1[i1]->x - xc1;
+            vc1[1] = A1[i1]->y - yc1;
+            vc1[2] = A1[i1]->z - zc1;
+            vc2[0] = A2[i2]->x - xc2;
+            vc2[1] = A2[i2]->y - yc2;
+            vc2[2] = A2[i2]->z - zc2;
+            for (i=1;i<=3;i++)
+              for (j=1;j<=3;j++)
+                A[i][j] += vc1[j-1]*vc2[i-1];
+          }
+        }
+
+    } else  {
+
+      for (k=0;k<nA;k++)
+        if ((!A1[k]->Ter) && (!A2[k]->Ter))  {
+          vc1[0] = A1[k]->x - xc1;
+          vc1[1] = A1[k]->y - yc1;
+          vc1[2] = A1[k]->z - zc1;
+          vc2[0] = A2[k]->x - xc2;
+          vc2[1] = A2[k]->y - yc2;
+          vc2[2] = A2[k]->z - zc2;
+          for (i=1;i<=3;i++)
+            for (j=1;j<=3;j++)
+              A[i][j] += vc1[j-1]*vc2[i-1];
+        }
+
+    }
+
+
+    //  4. Calculate transformation matrix (to be applied to A1)
+
+    det = A[1][1]*A[2][2]*A[3][3] +
+          A[1][2]*A[2][3]*A[3][1] +
+          A[2][1]*A[3][2]*A[1][3] -
+          A[1][3]*A[2][2]*A[3][1] -
+          A[1][1]*A[2][3]*A[3][2] -
+          A[3][3]*A[1][2]*A[2][1];
+
+    //  4.1 SV-decompose the correlation matrix
+
+    GetMatrixMemory ( U  ,3,3,1,1 );
+    GetMatrixMemory ( V  ,3,3,1,1 );
+    GetVectorMemory ( W  ,3,1 );
+    GetVectorMemory ( RV1,3,1 );
+
+    math::SVD ( 3,3,3,A,U,V,W,RV1,true,true,i );
+
+    if (i!=0)  {
+      FreeVectorMemory ( RV1,1 );
+      FreeVectorMemory ( W  ,1 );
+      FreeMatrixMemory ( V  ,3,1,1 );
+      FreeMatrixMemory ( U  ,3,1,1 );
+      FreeMatrixMemory ( A  ,3,1,1 );
+      return SPOSEAT_SVD_Fail;
+    }
+
+    //  4.2 Check for parasite inversion and fix it if found
+
+    if (det<=0.0)  {
+      k = 0;
+      B = MaxReal;
+      for (j=1;j<=3;j++)
+        if (W[j]<B)  {
+          B = W[j];
+          k = j;
+        }
+      for (j=1;j<=3;j++)
+        V[j][k] = -V[j][k];
+    }
+
+    //  4.3 Calculate rotational part of T
+
+    for (j=1;j<=3;j++)
+      for (k=1;k<=3;k++)  {
+        B = 0.0;
+        for (i=1;i<=3;i++)
+          B += U[j][i]*V[k][i];
+        T[j-1][k-1] = B;
+      }
+
+
+    //  4.4 Add translational part to T
+
+    T[0][3] = xc2 - T[0][0]*xc1 - T[0][1]*yc1 - T[0][2]*zc1;
+    T[1][3] = yc2 - T[1][0]*xc1 - T[1][1]*yc1 - T[1][2]*zc1;
+    T[2][3] = zc2 - T[2][0]*xc1 - T[2][1]*yc1 - T[2][2]*zc1;
+
+
+    //  5. Release memory and quit
+
+    FreeVectorMemory ( RV1,1 );
+    FreeVectorMemory ( W  ,1 );
+    FreeMatrixMemory ( V  ,3,1,1 );
+    FreeMatrixMemory ( U  ,3,1,1 );
+    FreeMatrixMemory ( A  ,3,1,1 );
+
+    return SPOSEAT_Ok;
+
+  }
+
+  realtype getPhi ( PPAtom A )  {
+  //
+  //   A0    A1    A2    A3
+  //   o-----o-----o-----o
+  //            |
+  //           Phi
+  //
+  //  -Pi <= Phi <= +Pi
+  //
+  vect3    U,W,V, a,b,c;
+  realtype Wmag,S,T;
+
+    U[0] = A[0]->x - A[1]->x;
+    U[1] = A[0]->y - A[1]->y;
+    U[2] = A[0]->z - A[1]->z;
+
+    W[0] = A[2]->x - A[1]->x;
+    W[1] = A[2]->y - A[1]->y;
+    W[2] = A[2]->z - A[1]->z;
+
+    V[0] = A[3]->x - A[2]->x;
+    V[1] = A[3]->y - A[2]->y;
+    V[2] = A[3]->z - A[2]->z;
+
+    a[0] = U[1]*W[2] - W[1]*U[2];
+    a[1] = U[2]*W[0] - W[2]*U[0];
+    a[2] = U[0]*W[1] - W[0]*U[1];
+
+    b[0] = V[1]*W[2] - W[1]*V[2];
+    b[1] = V[2]*W[0] - W[2]*V[0];
+    b[2] = V[0]*W[1] - W[0]*V[1];
+
+    c[0] = a[1]*b[2] - b[1]*a[2];
+    c[1] = a[2]*b[0] - b[2]*a[0];
+    c[2] = a[0]*b[1] - b[0]*a[1];
+
+    Wmag = sqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]);
+
+    S    = c[0]*W[0] + c[1]*W[1] + c[2]*W[2];
+    T    = a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
+    T   *= Wmag;
+
+    if ((S==0.0) && (T==0.0))  return NO_TORSION;
+                         else  return atan2(S,T);
+
+  }
+
+  realtype getPsi ( PPAtom A )  {
+  vect3    v1,v2;
+  realtype l1,l2;
+
+    v1[0] = A[0]->x - A[1]->x;
+    v1[1] = A[0]->y - A[1]->y;
+    v1[2] = A[0]->z - A[1]->z;
+
+    v2[0] = A[2]->x - A[1]->x;
+    v2[1] = A[2]->y - A[1]->y;
+    v2[2] = A[2]->z - A[1]->z;
+
+    l1 = v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2];
+    if (l1==0.0)  l1 = 1.0;
+    l2 = v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2];
+    if (l2==0.0)  l2 = 1.0;
+
+    return  acos((v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])/sqrt(l1*l2));
+
+  }
+
+  const realtype NO_TORSION = -MaxReal;
+
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_coormngr.h b/mmdb2/mmdb_coormngr.h
new file mode 100644
index 0000000..c493169
--- /dev/null
+++ b/mmdb2/mmdb_coormngr.h
@@ -0,0 +1,959 @@
+//  $Id: mmdb_coormngr.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    14.07.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_coormngr <interface>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Brick       ( space brick                  )
+//       ~~~~~~~~~  mmdb::CoorManager ( MMDB atom coordinate manager )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_CoorMngr__
+#define __MMDB_CoorMngr__
+
+#include "mmdb_root.h"
+
+namespace mmdb  {
+
+  // ===========================  Brick  ==============================
+
+  //  bricking control
+  enum BRICK_STATE  {
+    BRICK_ON_1  = 0x00000001,
+    BRICK_ON_2  = 0x00000002,
+    BRICK_READY = 0x00000004
+  };
+
+  DefineClass(Brick);
+  typedef  PPBrick * PPPBrick;
+
+  class Brick  {
+
+    public :
+      int     nAtoms;  // number of atoms hit into brick
+      PPAtom  atom;  // pointers to atoms
+      ivector id;  // atom ids (in present realization, these are
+                       // indices of atoms from the bricked array)
+
+      Brick ();
+      ~Brick();
+
+      void  Clear   ();
+      void  AddAtom ( PAtom A, int atomid );
+
+    protected :
+      int  nAllocAtoms;
+      void InitBrick();
+
+  };
+
+
+  // ===========================  MBrick  =============================
+
+  //  Bricking multiple structures
+
+  DefineClass(MBrick);
+  typedef  PPMBrick * PPPMBrick;
+
+  class MBrick  {
+
+    public :
+      ivector  nAtoms;  // number of atoms in the brick
+      PPAtom  *atom;    // pointers to atoms
+      imatrix    id;    // atom ids (in present realization, these are
+                        // indices of atoms from the bricked array)
+
+      MBrick ( int nStructures );
+      ~MBrick();
+
+      void  Clear   ();
+      void  AddAtom ( PAtom A, int structNo, int atomid );
+
+    protected :
+      ivector  nAlloAtoms;
+      int      nStruct;
+      void InitMBrick ( int nStructures );
+
+  };
+
+
+
+  //  ====================  GenSym  ========================
+
+  DefineClass(GenSym);
+  DefineStreamFunctions(GenSym);
+
+  class GenSym : public SymOps  {
+
+    friend class CoorManager;
+
+    public :
+
+      GenSym ();
+      GenSym ( io::RPStream Object );
+      ~GenSym();
+
+      void FreeMemory();
+
+      int  AddSymOp    ( cpstr XYZOperation );
+      //  the number of just added operation may be obtained as
+      //  Nop = GenSym::GetNofSymOps()-1 .
+
+      int  AddRenChain ( int Nop, const ChainID ch1, const ChainID ch2 );
+
+      void Copy  ( PSymOps genSym );
+
+      void write ( io::RFile f );
+      void read  ( io::RFile f );
+
+    protected :
+
+      PChainID * chID1;   // pairs of chains to rename from chID1[n][i]
+      PChainID * chID2;   // to chID2[n][i] for each operation n<Nops
+      ivector    nChains; // number of chains to rename for each oper-n
+
+      void InitGenSym();
+
+    private :
+      int        nOpAlloc;  // number of allocated operations
+
+  };
+
+
+  // =========================  Contact  =============================
+
+  DefineStructure(Contact);
+
+  struct Contact  {
+    int      id1,id2;
+    long     group;
+    realtype dist;
+    void Copy ( RContact c );
+    void Swap ( RContact c );
+  };
+
+
+  // ========================  MContact  =============================
+
+  DefineClass(MContact);
+
+  class MContact : public io::Stream  {
+
+    public :
+      int       nStruct,contactID;
+      ivector   nAtoms;
+      PPAtom *  atom;
+      imatrix   id;
+
+      MContact ( int nStructures  );
+      ~MContact();
+
+      void    AddContact ( PAtom A, int structNo, int atomid );
+
+    protected:
+      ivector nAlloc;
+
+  };
+
+  extern void DeleteMContacts ( PPMContact & mcontact, int nContacts );
+
+
+  // ======================  CoorManager  =========================
+
+  DefineClass(CoorManager);
+  DefineStreamFunctions(CoorManager);
+
+  //  ----  Atom extraction return
+  enum CID_RC  {
+    CID_Ok        = 0,
+    CID_NoModel   = 1,
+    CID_NoChain   = 2,
+    CID_NoResidue = 3,
+    CID_NoAtom    = 4,
+    CID_WrongPath = 5
+  };
+
+  //  ----  generate symmetry mates return codes
+  enum GSM_RC  {
+    GSM_Ok               = 0,
+    GSM_NoSymOps         = 1,
+    GSM_NoTransfMatrices = 2,
+    GSM_NoCell           = 3
+  };
+
+  class CoorManager : public Root  {
+
+    public :
+
+      int CoorIDCode; // last return from atom extraction procedure
+
+      CoorManager ();
+      CoorManager ( io::RPStream Object );
+      ~CoorManager();
+
+
+      //  ----------------------------------------------------------
+
+      int  SetDefaultCoorID ( cpstr CID );
+
+
+      //  ----------------  Bricking  ------------------------------
+
+      void  RemoveBricks ();
+      bool  areBricks  () { return (brick!=NULL); }
+      void  MakeBricks   ( PPAtom atmvec, int avlen,
+                           realtype Margin, realtype BrickSize=6.0 );
+      void  GetBrickDimension (
+                           int & nxmax, int & nymax, int & nzmax );
+      void  GetBrickCoor ( PAtom A, int & nx, int & ny, int & nz );
+      void  GetBrickCoor ( realtype x, realtype y, realtype z,
+                           int & nx, int & ny, int & nz );
+      PBrick GetBrick   ( int   nx, int   ny, int   nz );
+
+      void  RemoveMBricks ();
+      bool  areMBricks  () { return (mbrick!=NULL); }
+      void  MakeMBricks   ( PPAtom * atmvec, ivector avlen,
+                            int nStructures, realtype Margin,
+                            realtype BrickSize=6.0 );
+      void  GetMBrickDimension (
+                           int & nxmax, int & nymax, int & nzmax );
+      void  GetMBrickCoor ( PAtom A, int & nx, int & ny, int & nz );
+      void  GetMBrickCoor ( realtype x, realtype y, realtype z,
+                            int & nx, int & ny, int & nz );
+      PMBrick GetMBrick  ( int   nx, int   ny, int   nz );
+
+      //  ----------------  Extracting models  ---------------------
+
+      int    GetNumberOfModels ()  { return nModels; }
+      int    GetFirstModelNum ();
+      PModel GetFirstDefinedModel();
+      PModel GetModel ( int   modelNo  );  // 1<=modelNo<=nModels
+      PModel GetModel ( cpstr CID );
+      void   GetModelTable ( PPModel & modTable,
+                              int & NumberOfModels );
+
+      //  ----------------  Deleting models  -----------------------
+
+      int  DeleteModel ( cpstr CID );
+      int  DeleteModel ( int modelNo );  // 1<=modelNo<=nOfModels
+
+      //  ----------------  Adding/Inserting models  ---------------
+
+      int  AddModel     ( PModel mdl );
+      int  InsModel     ( PModel mdl, int modelNo );
+      void RotateModels ( int  modelNo1, int modelNo2, int rotdir );
+      void SwapModels   ( int  modelNo1, int modelNo2 );
+
+      //  ----------------  Extracting chains  ---------------------
+
+      int     GetNumberOfChains ( int   modelNo  );
+      int     GetNumberOfChains ( cpstr CID );
+      PChain  GetChain ( int modelNo, const ChainID chainID );
+      PChain  GetChain ( int modelNo, int   chainNo );
+      PChain  GetChain ( cpstr CID );
+      void    GetChainTable ( int modelNo, PPChain & chainTable,
+                              int & NumberOfChains );
+      void    GetChainTable ( cpstr CID, PPChain & chainTable,
+                              int & NumberOfChains );
+
+      //  -----------------  Deleting chains  ----------------------
+
+      int  DeleteChain     ( int modelNo, const ChainID chID );
+      int  DeleteChain     ( int modelNo, int chainNo  );
+      int  DeleteAllChains ( int modelNo );
+      int  DeleteAllChains ();
+
+      //  ------------------  Adding chains  -----------------------
+
+      int  AddChain ( int modelNo, PChain chain );
+
+      //  ----------------  Extracting residues  -------------------
+
+      int GetNumberOfResidues ( int modelNo, const ChainID chainID );
+      int GetNumberOfResidues ( int modelNo, int   chainNo );
+      int GetNumberOfResidues ( cpstr CID );
+      PResidue GetResidue   ( int modelNo, const ChainID chainID,
+                              int seqNo,   const InsCode insCode );
+      PResidue GetResidue   ( int modelNo, int   chainNo,
+                              int seqNo,   const InsCode insCode );
+      PResidue GetResidue   ( int modelNo, const ChainID chainID,
+                                                          int resNo );
+      PResidue GetResidue   ( int modelNo, int   chainNo, int resNo );
+      PResidue GetResidue   ( cpstr CID );
+      int      GetResidueNo ( int modelNo, const ChainID chainID,
+                              int seqNo,   const InsCode insCode );
+      int      GetResidueNo ( int modelNo, int   chainNo,
+                              int seqNo,   const InsCode insCode );
+      void    GetResidueTable ( PPResidue & resTable,
+                                int & NumberOfResidues );
+      void    GetResidueTable ( int modelNo, const ChainID chainID,
+                                PPResidue & resTable,
+                                int & NumberOfResidues );
+      void    GetResidueTable ( int modelNo, int chainNo,
+                                PPResidue & resTable,
+                                int & NumberOfResidues );
+      void    GetResidueTable ( cpstr CID, PPResidue & resTable,
+                                int & NumberOfResidues );
+
+
+      //  -----------------  Deleting residues  -----------------------
+
+      int DeleteResidue     ( int modelNo, const ChainID chainID,
+                              int seqNo,   const InsCode insCode );
+      int DeleteResidue     ( int modelNo, const ChainID chainID,
+                                                     int resNo );
+      int DeleteResidue     ( int modelNo, int   chainNo,
+                              int seqNo,   const InsCode insCode );
+      int DeleteResidue     ( int modelNo, int   chainNo, int resNo );
+      int DeleteAllResidues ( int modelNo, const ChainID chainID );
+      int DeleteAllResidues ( int modelNo, int   chainNo );
+      int DeleteAllResidues ( int modelNo );
+      int DeleteAllResidues ();
+      int DeleteSolvent     ();
+
+      //  -------------------  Adding residues  -----------------------
+
+      int AddResidue ( int modelNo, const ChainID chainID,
+                                                   PResidue res );
+      int AddResidue ( int modelNo, int   chainNo, PResidue res );
+
+      // --------------------  Extracting atoms  ----------------------
+
+      int   GetNumberOfAtoms ()  { return nAtoms;  }
+      int   GetNumberOfAtoms ( int modelNo, const ChainID chainID,
+                               int seqNo,   const InsCode insCode );
+      int   GetNumberOfAtoms ( int modelNo, int   chainNo,
+                               int seqNo,   const InsCode insCode );
+      int   GetNumberOfAtoms ( int modelNo, const ChainID chainID,
+                                                      int resNo );
+      int   GetNumberOfAtoms ( int modelNo, int   chainNo, int resNo );
+      int   GetNumberOfAtoms ( cpstr CID );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                const ChainID  chID,    // chain ID
+                int            seqNo,   // residue sequence number
+                const InsCode  insCode, // residue insertion code
+                const AtomName aname,   // atom name
+                const Element  elmnt,   // chemical element code or '*'
+                const AltLoc   aloc     // alternate location indicator
+                     );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                const ChainID  chID,    // chain ID
+                int            seqNo,   // residue sequence number
+                const InsCode  insCode, // residue insertion code
+                int            atomNo   // atom number 0..
+                     );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                const ChainID  chID,    // chain ID
+                int            resNo,   // residue number 0..
+                const AtomName aname,   // atom name
+                const Element  elmnt,   // chemical element code or '*'
+                const AltLoc   aloc     // alternate location indicator
+                     );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                const ChainID  chID,    // chain ID
+                int            resNo,   // residue number 0..
+                int            atomNo   // atom number 0..
+                     );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                int            chNo,    // chain number 0..
+                int            seqNo,   // residue sequence number
+                const InsCode  insCode, // residue insertion code
+                const AtomName aname,   // atom name
+                const Element  elmnt,   // chemical element code or '*'
+                const AltLoc   aloc     // alternate location indicator
+                     );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                int            chNo,    // chain number 0...
+                int            seqNo,   // residue sequence number
+                const InsCode  insCode, // residue insertion code
+                int            atomNo   // atom number 0...
+                     );
+
+      PAtom GetAtom (
+                int            modelNo, // model serial number 1...
+                int            chNo,    // chain number 0...
+                int            resNo,   // residue number 0...
+                const AtomName aname,   // atom name
+                const Element  elmnt,   // chemical element code or '*'
+                const AltLoc   aloc     // alternate location indicator
+                     );
+
+      PAtom GetAtom (
+                int      modelNo, // model serial number 1...
+                int      chNo,    // chain number 0...
+                int      resNo,   // residue number 0...
+                int      atomNo   // atom number 0...
+                     );
+
+
+      //   GetAtom(CID) returns atom answering to the following
+      // CID pattern:
+      //   /mdl/chn/seq(res).i/atm[elm]:a
+      // where
+      //   mdl   - model number (mandatory); at least model #1 is always
+      //           present
+      //   chn   - chain identifier ( mandatory)
+      //   seq   - residue sequence number (mandatory)
+      //   (res) - residue name in round brackets (may be omitted)
+      //   .i    - insert code after a dot; if '.i' or 'i' is missing
+      //           then residue without an insertion code is looked
+      //           for
+      //   atm   - atom name (mandatory)
+      //   [elm] - chemical element code in square brackets; it may
+      //           be omitted but could be helpful for e.g.
+      //           distinguishing C_alpha and CA
+      //   :a    - alternate location indicator after colon; if
+      //           ':a' or 'a' is missing then an atom without
+      //           alternate location indicator is looked for.
+      // All spaces are ignored, all identifiers should be in capital
+      // letters (comparisons are case-sensitive).
+      PAtom GetAtom ( cpstr CID );
+
+
+      void GetAtomTable ( PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int modelNo, const ChainID chainID,
+                          int seqNo,   const InsCode insCode,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int modelNo, int   chainNo,
+                          int seqNo,   const InsCode insCode,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int modelNo, const ChainID chainID, int resNo,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int modelNo, int     chainNo, int resNo,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( cpstr CID, PPAtom & atomTable,
+                          int & NumberOfAtoms );
+
+
+      //   GetAtomTable1(..) returns atom table without TER atoms and
+      // without NULL atom pointers. NumberOfAtoms returns the actual
+      // number of atom pointers in atomTable.
+      //   atomTable is allocated within the function. If it was
+      // not set to NULL before calling the function, the function will
+      // attempt to deallocate it first.
+      //   The application is responsible for deleting atomTable,
+      // however it must not touch atom pointers, i.e. use simply
+      // "delete atomTable;". Never pass atomTable from GetAtomTable(..)
+      // into this function, unless you set it to NULL before doing that.
+      void GetAtomTable1 ( PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int modelNo, const ChainID chainID,
+                           int seqNo,   const InsCode insCode,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int modelNo, int   chainNo,
+                           int seqNo,   const InsCode insCode,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int modelNo, const ChainID chainID, int resNo,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int modelNo, int     chainNo, int resNo,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( cpstr CID, PPAtom & atomTable,
+                           int & NumberOfAtoms );
+
+
+      //  --------------------  Deleting atoms  -----------------------
+
+      int DeleteAtom ( int            modelNo,
+                       const ChainID  chID,
+                       int            seqNo,
+                       const InsCode  insCode,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int           modelNo,
+                       const ChainID chID,
+                       int           seqNo,
+                       const InsCode insCode,
+                       int           atomNo );
+      int DeleteAtom ( int            modelNo,
+                       const ChainID  chID,
+                       int            resNo,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int modelNo, const ChainID chID,
+                       int resNo, int atomNo );
+      int DeleteAtom ( int modelNo, int chNo, int seqNo,
+                       const InsCode  insCode,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int modelNo, int chNo, int seqNo,
+                       const InsCode insCode, int atomNo );
+      int DeleteAtom ( int modelNo, int chNo, int resNo,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int modelNo, int chNo, int resNo, int atomNo );
+
+      int DeleteAllAtoms ( int modelNo, const ChainID chID,
+                           int seqNo,   const InsCode insCode );
+      int DeleteAllAtoms ( int modelNo, const ChainID chID, int resNo );
+      int DeleteAllAtoms ( int modelNo, const ChainID chID );
+      int DeleteAllAtoms ( int modelNo, int chNo, int seqNo,
+                           const InsCode insCode );
+      int DeleteAllAtoms ( int modelNo, int chNo, int resNo );
+      int DeleteAllAtoms ( int modelNo, int chNo );
+      int DeleteAllAtoms ( int modelNo );
+      int DeleteAllAtoms ();
+
+      //  This function leaves only alternative location with maximal
+      // occupancy, if those are equal or unspecified, the one with
+      // "least" alternative location indicator.
+      //  The function returns the number of deleted atoms and optimizes
+      // the atom index.
+      int DeleteAltLocs  ();
+
+
+      //  ---------------------  Adding atoms  ------------------------
+
+      int AddAtom ( int modelNo, const ChainID chID,
+                    int seqNo,   const InsCode insCode, PAtom atom );
+      int AddAtom ( int modelNo, const ChainID chID, int resNo,
+                                                        PAtom atom );
+      int AddAtom ( int modelNo, int chNo, int seqNo,
+                                 const InsCode insCode, PAtom atom );
+      int AddAtom ( int modelNo, int chNo, int resNo, PAtom  atom );
+
+
+      // --------------------  Transformations  -----------------------
+
+      int  GenerateSymMates ( PGenSym genSym=NULL );
+                               // 1: no Sym operations,
+                               // 2: no fract/orth matrices
+                               // 3: no cell parameters
+                               // 0: Ok
+
+      void ApplyTransform   ( mat44 & TMatrix ); // simply transforms all
+                                            // coordinates by multiplying
+                                            // with matrix TMatrix
+
+      int  BringToUnitCell();  // brings all chains into 0th unit cell
+
+      //   Frac2Orth(..) and Orth2Frac(..) transform between fractional
+      // and orthogonal coordinates, if areMatrices() returns true.
+      // If the transformation matrices were not set, the functions just
+      // copy the coordinates.  Returns true if the transformation was
+      // done; False return means that transformation matrices were not
+      // calculated
+      bool Frac2Orth (
+                realtype   xfrac, realtype   yfrac, realtype   zfrac,
+                realtype & xorth, realtype & yorth, realtype & zorth );
+      bool Orth2Frac (
+                realtype   xorth, realtype   yorth, realtype   zorth,
+                realtype & xfrac, realtype & yfrac, realtype & zfrac );
+
+
+      //   Below, F and T are transformation matrices in fractional and
+      // orthogonal coordinates, respectively.
+      bool Frac2Orth ( mat44 & F, mat44 & T );
+      bool Orth2Frac ( mat44 & T, mat44 & F );
+
+      // ====================  Seeking contacts  ======================
+
+      void  SeekContacts (
+               PPAtom    AIndex,    // index of atoms [0..ilen-1]
+               int        ilen,      // length of index
+               int        atomNum,   // number of 1st contact atom
+                                     // in the index. All other atoms
+                                     // are checked for contact with
+                                     // 1st atom
+               realtype   dist1,     // minimal contact distance
+               realtype   dist2,     // maximal contact distance
+               int        seqDist,   // the sequence distance to neglect.
+                                     // If seqDist==0, all atoms are
+                                     // checked for contact. If
+                                     // seqDist==1, the atoms belonging
+                                     // to the same residue as atom
+                                     // AIndex[atomNum], are neglected.
+                                     // If seqDist>1, all atoms belonging
+                                     // to residues closer than
+                                     // +/-(seqDist-1) around that of
+                                     // atom AIndex[atomNum], are
+                                     // neglected. If chain is broken
+                                     // (has a gap) on section
+                                     // [-(seqDist-1)..seqDist-1], the
+                                     // section of neglection is
+                                     // shortened to that gap.
+               RPContact contact,   // indices of contacting atoms
+                                     // [0..ncontacts-1]. contact[i].id1
+                                     // is set to atomNum and
+                                     // contact[i].id2 is set to the
+                                     // index of 2nd contacting atom
+                                     // in vector AIndex
+               int &      ncontacts, // number of contacts found. If
+                                     // ncontacts>0 on input, it is
+                                     // assumed that new contacts that
+                                     // newly found contacts should be
+                                     // appended to those already
+                                     // existing
+               int        maxlen=0,  // if <=0, then vector contact is
+                                     // allocated dynamically. If
+                                     // contact!=NULL, then it is
+                                     // appended with new contacts.
+                                     // The application is responsible
+                                     // for deallocation of contact
+                                     // after use.
+                                     //   If maxlen>0 then vector contact
+                                     // is prohibited of dynamical
+                                     // allocation/deallocation. In this
+                                     // case, not more than maxlen
+                                     // contacts will be returned.
+               long       group=0    // a contact group ID, which will be
+                                     // simply stored in contact[i].group
+                                     // fields. This ID may be useful
+                                     // if contacts are obtained in
+                                     // multiple calls of the function
+                         );
+
+      void  SeekContacts (
+               PAtom     A,         // 1st atom in contact
+               PPAtom    AIndex,    // index of atoms [0..ilen-1] to
+                                     // check for contact with 1st atom
+               int        ilen,      // length of index
+               realtype   dist1,     // minimal contact distance
+               realtype   dist2,     // maximal contact distance
+               int        seqDist,   // the sequence distance to neglect.
+                                     // If seqDist==0, all atoms are
+                                     // checked for contact. If
+                                     // seqDist==1, the atoms belonging
+                                     // to the same residue as atom
+                                     // A, are neglected. If seqDist>1,
+                                     // all atoms belonging to residues
+                                     // closer than +/-(seqDist-1) around
+                                     // that of atom A, are neglected. If
+                                     // chain is broken (has a gap) on
+                                     // section
+                                     // [-(seqDist-1)..seqDist-1], the
+                                     // section of neglection is
+                                     // shortened to that gap.
+               RPContact contact,   // indices of contacting atoms
+                                     // [0..ncontacts-1]. contact[i].id1
+                                     // is set to -1, and contact[i].id2
+                                     // is set to the index of 2nd
+                                     // contacting atom in vector AIndex
+               int &      ncontacts, // number of contacts found. If
+                                     // ncontacts>0 on input, it is
+                                     // assumed that new contacts that
+                                     // newly found contacts should be
+                                     // appended those already existing
+               int        maxlen=0,  // if <=0, then vector contact is
+                                     // allocated dynamically. If
+                                     // contact!=NULL, then it is
+                                     // appended with new contacts.
+                                     // The application is responsible
+                                     // for deallocation of contact
+                                     // after use.
+                                     //   If maxlen>0 then vector contact
+                                     // is prohibited of dynamical
+                                     // allocation/deallocation. In this
+                                     // case, not more than maxlen
+                                     // contacts will be returned.
+               long       group=0    // a contact group ID, which will be
+                                     // simply stored in contact[i].group
+                                     // fields. This ID may be useful
+                                     // if contacts are obtained in
+                                     // multiple calls of the function
+                         );
+
+      void  SeekContacts (
+               PPAtom    AIndex1,   //  1st atom index [0..ilen1-1]
+               int        ilen1,     //  length of 1st index
+               PPAtom    AIndex2,   //  2nd atom index [0..ilen2-1] to
+                                     // check for contact with 1st index
+               int        ilen2,     //  length of 2nd index
+               realtype   dist1,     //  minimal contact distance
+               realtype   dist2,     //  maximal contact distance
+               int        seqDist,   //  the sequence distance to
+                                     // neglect.
+                                     //  If seqDist==0, all atoms are
+                                     // checked for contact.
+                                     //  If seqDist==1, the atoms
+                                     // belonging to the same residue
+                                     // are neglected.
+                                     //  If seqDist>1, all atoms
+                                     // belonging to residues closer than
+                                     // +/-(seqDist-1) to each other,
+                                     // are neglected. If chain is broken
+                                     // (has a gap) on section
+                                     // [-(seqDist-1)..seqDist-1], the
+                                     // section of neglection is
+                                     // shortened to that gap.
+               RPContact contact,   //  indices of contacting atoms
+                                     // [0..ncontacts-1]. contact[i].id1
+                                     // contains number of atom from 1st
+                                     // index, and contact[i].id2
+                                     // contains number of atom from 2nd
+                                     // index, contacting with the former
+                                     // one
+               int &      ncontacts, //  number of contacts found. If
+                                     // ncontacts>0 on input, it is
+                                     // assumed that newly found
+                                     // contacts should be appended to
+                                     // those already existing
+               int        maxlen=0,  //  if <=0, then vector contact is
+                                     // allocated dynamically. If
+                                     // contact!=NULL, then it is
+                                     // appended with new contacts.
+                                     // The application is responsible
+                                     // for deallocation of contact
+                                     // after use.
+                                     //   If maxlen>0 then vector contact
+                                     // is prohibited of dynamical
+                                     // allocation/deallocation. In this
+                                     // case, not more than maxlen
+                                     // contacts will be returned.
+               mat44 * TMatrix=NULL, //  transformation matrix for 2nd
+                                     // set of atoms (AIndex2)
+               long       group=0,   //  a contact group ID, which will
+                                     // be stored in contact[i].group
+                                     // fields. This ID may be useful
+                                     // if contacts are obtained in
+                                     // multiple calls of the function
+               int     bricking=0,   //  bricking control; may be a
+                                     // combination of BRICK_ON_1 or
+                                     // BRICK_ON_2 with BRICK_READY
+               bool    doSqrt=true   // if False, then Contact contains
+                                     // square distances
+                         );
+
+      //  Simplified optimized for speed version:
+      //    - no NULL pointers and Ters in AIndex1 and AIndex2
+      //    - no checks for identity atoms in AIndex1 and AIndex2
+      //    - contact must be pre-allocated with at least ilen1*ilen2
+      //      elements
+      //    - contact returns square distances
+      //    - ncontacts is always reset
+      void  SeekContacts (
+               PPAtom    AIndex1,   //  1st atom index [0..ilen1-1]
+               int        ilen1,     //  length of 1st index
+               PPAtom    AIndex2,   //  2nd atom index [0..ilen2-1] to
+                                     // check for contact with 1st index
+               int        ilen2,     //  length of 2nd index
+               realtype   contDist,  //  maximal contact distance
+               PContact  contact,   //  indices of contacting atoms
+                                     // [0..ncontacts-1]. contact[i].id1
+                                     // contains number of atom from 1st
+                                     // index, and contact[i].id2
+                                     // contains number of atom from 2nd
+                                     // index, contacting with the former
+                                     // one. Must be pre-allocated
+               int &      ncontacts, //  number of contacts found
+               int       bricking=0  //  bricking control; may be a
+                                     // combination of BRICK_ON_1 or
+                                     // BRICK_ON_2 with BRICK_READY
+                         );
+
+      void  SeekContacts (
+             PPAtom       AIndex1,  //  1st atom index [0..ilen1-1]
+             int           ilen1,    //  length of 1st index
+             PPAtom *     AIndex2,  //  indexes of atoms to be checked
+                                     // for contact with each atom from
+                                     // Aindex1; dimension
+                                     // [0..nStructures-1][0..ilen2[i]-1]
+             ivector       ilen2,    //  lengths of indexes AIndex2
+             int           nStructures, //  number of indexes AIndex2
+             realtype      dist1,    //  minimal contact distance
+             realtype      dist2,    //  maximal contact distance
+             PPMContact & contact,  // resulting contacts, one structure
+                                     // per each position in AIndex1. If
+                                     // AIndex1[i] is NULL, contact[i] is
+                                     // also NULL. "contact" is always
+                                     // allocated, no re-use or
+                                     // re-allocation is attempted.
+             int            bricking=0  //  bricking control; may be
+                                     // BRICK_READY if AIndex2 does not
+                                    // change
+                         );
+
+    protected :
+
+      //  bricks
+      realtype    brick_size, xbrick_0,ybrick_0,zbrick_0;
+      int         nbrick_x,nbrick_y,nbrick_z;
+      PPPBrick  * brick;
+
+      realtype    mbrick_size, xmbrick_0,ymbrick_0,zmbrick_0;
+      int         nmbrick_x,nmbrick_y,nmbrick_z;
+      PPPMBrick * mbrick;
+
+      //  ---------------  Stream I/O  -----------------------------
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+      void  InitMMDBCoorManager();
+
+      void  ApplySymTransform ( int SymMatrixNo, PGenSym genSym=NULL );
+
+      void  ResetManager ();
+
+      void  FindSeqSection ( PAtom  atom, int  seqDist,
+                             int  &  seq1, int  &  seq2 );
+      bool  iContact  ( PAtom    a1, PAtom    a2,
+                        int     seq1, int     seq2,
+                        realtype  dd, realtype d12,
+                        realtype d22, realtype & d2 );
+      bool  iContact  ( realtype   x, realtype   y,
+                        realtype   z, PAtom    a2,
+                        realtype  dd, realtype d12,
+                        realtype d22, realtype & d2 );
+
+  };
+
+
+
+  //  ===================================================================
+
+
+
+  //   GetEulerRotMatrix(..) calculates the Euler rotation matrix
+  // for rotation:
+  //                   1) about z-axis by angle alpha
+  //                   2) about new y-axis by angle beta
+  //                   3) about new z-axis by angle gamma
+  extern void  GetEulerRotMatrix ( mat33 & erm,   realtype alpha,
+                                   realtype beta, realtype gamma );
+
+  //  GetEulerTMatrix(..) calculates the Euler rotation-translation
+  // matrix for rotation:
+  //                   1) about z-axis by angle alpha
+  //                   2) about new y-axis by angle beta
+  //                   3) about new z-axis by angle gamma
+  //  Point (x0,y0,z0) is the center of rotation.
+  extern void  GetEulerTMatrix ( mat44 & erm,   realtype alpha,
+                            realtype beta, realtype gamma,
+                            realtype x0,   realtype y0,  realtype z0 );
+
+  //  Euler rotation:  1) about z-axis by angle alpha
+  //                   2) about new y-axis by angle beta
+  //                   3) about new z-axis by angle gamma
+  //  Point (x0,y0,z0) is the center of rotation.
+  extern void EulerRotation ( PPAtom A, int nA,
+                           realtype alpha, realtype beta, realtype gamma,
+                           realtype x0,    realtype y0,   realtype z0 );
+
+  //   GetVecRotMatrix(..) calculates the rotation matrix for
+  // rotation by angle alpha about arbitrary vector directed
+  // as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+  extern void GetVecRotMatrix ( mat33 & vrm,  realtype alpha,
+                             realtype vx,  realtype vy, realtype vz );
+
+
+  //    Given the rotation matrix vrm, GetRotParameters(..)
+  //  returns the rotation angle alpha and the normalized
+  //  rotation axis vector (vx,vy,vz).
+  //    The rotation angle and vector are determined up to
+  //  their sign (however correlated, so that being substituted
+  //  into GetVecRotMatrix(..) they yield the same rotation
+  //  matrix).
+  //    The function does not check for vrm to be a valid
+  //  rotation matrix.
+  extern void GetRotParameters ( mat33 & vrm, realtype & alpha,
+                         realtype & vx, realtype & vy, realtype & vz );
+
+
+  //   GetVecTMatrix(..) calculates the rotation-translation matrix
+  // for rotation by angle alpha about arbitrary vector directed as
+  // (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1). Point (x0,y0,z0) is
+  // the center of rotation -- actually a point belonging to the
+  // rotation axis.
+  extern void GetVecTMatrix  ( mat44 & vrm, realtype alpha,
+                               realtype vx, realtype vy, realtype vz,
+                               realtype x0, realtype y0, realtype z0 );
+
+  //   Vector rotation is rotation by angle alpha about arbitrary
+  // vector directed as (vx,vy,vz) = (vx2-vx1,vy2-vy1,vz2-vz1).
+  // Point (x0,y0,z0) is the center of rotation -- actually
+  // a point belonging to the rotation axis.
+  extern void VectorRotation ( PPAtom A, int nA,  realtype alpha,
+                               realtype vx, realtype vy, realtype vz,
+                               realtype x0, realtype y0, realtype z0 );
+
+  extern void GetMassCenter  ( PPAtom A, int nA,
+                        realtype & xmc, realtype & ymc, realtype & zmc );
+
+
+  enum SPOSEAT_RC  {
+    SPOSEAT_Ok       = 0,
+    SPOSEAT_NoAtoms  = 1,
+    SPOSEAT_SVD_Fail = 2
+  };
+
+  //   Given two sets of atoms, A1 and A2, SuperposeAtoms(...) calculates
+  // the rotational-translational matrix T such that |T*A1 - A2| is
+  // minimal in least-square terms.
+  //   If vector C is not given (default), all nA atoms of set A1 are
+  // considered as corresponding to nA first atoms of set A2,
+  // A1[i] <-> A2[i], 0<=i<nA .
+  //   If vector C is given, then the correspondence of atoms is
+  // established as A1[i] <-> A2[C[i]] only for those i that C[i]>=0.
+  // The default option (C==NULL) is thus identical to C[i]==i, 0<=i<nA.
+  //   Upon normal completion, the procedure returns SPOSEAT_Ok.
+
+  extern int SuperposeAtoms ( mat44 & T, PPAtom A1, int nA, PPAtom A2,
+                              ivector C=NULL );
+
+  enum CNSORT_DIR  {
+    CNSORT_OFF  = 0,
+    CNSORT_1INC = 1,
+    CNSORT_1DEC = 2,
+    CNSORT_2INC = 3,
+    CNSORT_2DEC = 4,
+    CNSORT_DINC = 5,
+    CNSORT_DDEC = 6
+  };
+
+  extern void  SortContacts ( PContact contact, int ncontacts,
+                              CNSORT_DIR sortmode );
+
+
+  extern const realtype NO_TORSION;
+
+  extern realtype getPhi ( PPAtom A );  // A[0] - A[3] used
+  extern realtype getPsi ( PPAtom A );  // A[0] - A[2] used
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_cryst.cpp b/mmdb2/mmdb_cryst.cpp
new file mode 100644
index 0000000..5ad924c
--- /dev/null
+++ b/mmdb2/mmdb_cryst.cpp
@@ -0,0 +1,2312 @@
+//  $Id: mmdb_cryst.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    21.11.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Cryst <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::CrystContainer ( container for cryst. data )
+//       ~~~~~~~~~  mmdb::NCSMatrix  ( non-cryst. symm. matrix class )
+//                  mmdb::TVect      ( translation vector class      )
+//                  mmdb::Cryst      ( MMDB cryst. section class     )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_cryst.h"
+#include "mmdb_defs.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb  {
+
+  //  ==============  CrystContainer  ====================
+
+  PContainerClass CrystContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template  :
+                    return  ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_NCSMatrix : return new NCSMatrix();
+      case ClassID_TVect     : return new TVect    ();
+    }
+  }
+
+  ERROR_CODE CrystContainer::AddMTRIXLine ( cpstr S )  {
+  int        i;
+  ERROR_CODE RC;
+    RC = Error_NCSM_WrongSerial;
+    for (i=0;i<length;i++)  {
+      RC = PNCSMatrix(Container[i])->ConvertPDBASCII(S);
+      if (RC==0)  break;
+      if (RC!=Error_NCSM_WrongSerial) break;
+    }
+    return RC;
+  }
+
+  MakeStreamFunctions(CrystContainer)
+
+
+  //  ================  NCSMatrix  ===================
+
+  NCSMatrix::NCSMatrix() : ContainerClass()  {
+    Init();
+  }
+
+  NCSMatrix::NCSMatrix ( cpstr S ) : ContainerClass()  {
+    Init();
+    ConvertPDBASCII ( S );
+  }
+
+  NCSMatrix::NCSMatrix ( io::RPStream Object )
+            : ContainerClass(Object)  {
+    Init();
+  }
+
+  NCSMatrix::~NCSMatrix() {}
+
+  void  NCSMatrix::Init()  {
+  int i,j;
+    serNum = -1;
+    iGiven = -1;
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        m[i][j] = 0.0;
+      m[i][i] = 1.0;
+      v[i] = 0.0;
+    }
+    WhatIsSet = 0;  // nothing is set
+  }
+
+  bool  NCSMatrix::PDBASCIIDump1 ( io::RFile f )  {
+  //  makes the ASCII PDB MATRIXn lines if all
+  //  of them were set.
+  char S[100];
+  int  i,j;
+
+    if ((WhatIsSet & NCSMSET_All)==NCSMSET_All)
+      for (i=0;i<3;i++)  {
+        sprintf   ( S,"MTRIX%1i %3i",i+1,serNum );
+        PadSpaces ( S,80 );
+        for (j=0;j<3;j++)
+          PutRealF ( &(S[10+j*10]),m[i][j],10,6 );
+        PutRealF ( &(S[45]),v[i],10,5 );
+        if (iGiven)  S[59] = '1';
+        f.WriteLine ( S );
+      }
+
+    return true;  // container should use this virtual
+
+  }
+
+  ERROR_CODE NCSMatrix::ConvertPDBASCII ( cpstr S )  {
+  realtype m0,m1,m2,v0;
+  int      sN,iG;
+
+    if (!(GetInteger(sN,&(S[7]) ,3 ) &&
+          GetReal   (m0,&(S[10]),10) &&
+          GetReal   (m1,&(S[20]),10) &&
+          GetReal   (m2,&(S[30]),10) &&
+          GetReal   (v0,&(S[45]),10)))
+      return Error_NCSM_Unrecognized;
+
+    if (S[59]=='1')  iG = 1;
+               else  iG = 0;
+
+    if (WhatIsSet & NCSMSET_All)  {
+      if (sN!=serNum)  return Error_NCSM_WrongSerial;
+      if (iG!=iGiven)  return Error_NCSM_UnmatchIG;
+    }
+
+    if (!strncmp(S,"MTRIX1",6))  {
+
+      if (WhatIsSet & NCSMSET_Matrix1)  return Error_NCSM_AlreadySet;
+      serNum  = sN;
+      iGiven  = iG;
+      m[0][0] = m0;
+      m[0][1] = m1;
+      m[0][2] = m2;
+      v[0]    = v0;
+      WhatIsSet |= NCSMSET_Matrix1;
+
+    } else if (!strncmp(S,"MTRIX2",6))  {
+
+      if (WhatIsSet & NCSMSET_Matrix2)  return Error_NCSM_AlreadySet;
+      serNum  = sN;
+      iGiven  = iG;
+      m[1][0] = m0;
+      m[1][1] = m1;
+      m[1][2] = m2;
+      v[1]    = v0;
+      WhatIsSet |= NCSMSET_Matrix2;
+
+    } else if (!strncmp(S,"MTRIX3",6))  {
+
+      if (WhatIsSet & NCSMSET_Matrix3)  return Error_NCSM_AlreadySet;
+      serNum  = sN;
+      iGiven  = iG;
+      m[2][0] = m0;
+      m[2][1] = m1;
+      m[2][2] = m2;
+      v[2]    = v0;
+      WhatIsSet |= NCSMSET_Matrix3;
+
+    } else
+      return Error_WrongSection;
+
+    return Error_NoError;
+
+  }
+
+  void  NCSMatrix::MakeCIF ( mmcif::PData CIF, int N )  {
+  mmcif::PLoop Loop;
+  int          RC;
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_NCS_OPER,Loop );
+    if ((RC!=mmcif::CIFRC_Ok) || (N==0))  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_ID       );
+      Loop->AddLoopTag ( CIFTAG_MATRIX11 );
+      Loop->AddLoopTag ( CIFTAG_MATRIX12 );
+      Loop->AddLoopTag ( CIFTAG_MATRIX13 );
+      Loop->AddLoopTag ( CIFTAG_VECTOR1  );
+      Loop->AddLoopTag ( CIFTAG_MATRIX21 );
+      Loop->AddLoopTag ( CIFTAG_MATRIX22 );
+      Loop->AddLoopTag ( CIFTAG_MATRIX23 );
+      Loop->AddLoopTag ( CIFTAG_VECTOR2  );
+      Loop->AddLoopTag ( CIFTAG_MATRIX31 );
+      Loop->AddLoopTag ( CIFTAG_MATRIX32 );
+      Loop->AddLoopTag ( CIFTAG_MATRIX33 );
+      Loop->AddLoopTag ( CIFTAG_VECTOR3  );
+      Loop->AddLoopTag ( CIFTAG_CODE     );
+    }
+    Loop->AddInteger ( serNum  );
+    if (WhatIsSet & NCSMSET_Matrix1) {
+      Loop->AddReal ( m[0][0] );
+      Loop->AddReal ( m[0][1] );
+      Loop->AddReal ( m[0][2] );
+      Loop->AddReal ( v[0]    );
+    } else  {
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+    }
+    if (WhatIsSet & NCSMSET_Matrix2) {
+      Loop->AddReal ( m[1][0] );
+      Loop->AddReal ( m[1][1] );
+      Loop->AddReal ( m[1][2] );
+      Loop->AddReal ( v[1]    );
+    } else  {
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+    }
+    if (WhatIsSet & NCSMSET_Matrix3) {
+      Loop->AddReal ( m[2][0] );
+      Loop->AddReal ( m[2][1] );
+      Loop->AddReal ( m[2][2] );
+      Loop->AddReal ( v[2]    );
+    } else  {
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+      Loop->AddString ( NULL );
+    }
+    if (iGiven==1)  Loop->AddString ( pstr("generated") );
+              else  Loop->AddNoData ( mmcif::CIF_NODATA_DOT    );
+  }
+
+  ERROR_CODE  NCSMatrix::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  char         Code[100];
+  ERROR_CODE   rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_NCS_OPER );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+
+    if (n>=Loop->GetLoopLength())  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    WhatIsSet = 0;
+    rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
+    if (rc!=Error_NoError)  return rc;
+    if (CIFGetString(Code,Loop,CIFTAG_CODE,n,sizeof(Code),
+        pstr("")))
+      iGiven = MinInt4;
+    else if (!strcasecmp(Code,"generated"))
+      iGiven = 1;
+    else
+      iGiven = MinInt4;
+
+
+    rc = CIFGetReal ( m[0][0],Loop,CIFTAG_MATRIX11,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( m[0][1],Loop,CIFTAG_MATRIX12,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( m[0][2],Loop,CIFTAG_MATRIX13,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( v[0]   ,Loop,CIFTAG_VECTOR1 ,n );
+    if (rc!=Error_NoError)  return rc;
+    WhatIsSet |= NCSMSET_Matrix1;
+
+    rc = CIFGetReal ( m[1][0],Loop,CIFTAG_MATRIX21,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( m[1][1],Loop,CIFTAG_MATRIX22,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( m[1][2],Loop,CIFTAG_MATRIX23,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( v[1]   ,Loop,CIFTAG_VECTOR2 ,n );
+    if (rc!=Error_NoError)  return rc;
+    WhatIsSet |= NCSMSET_Matrix2;
+
+    rc = CIFGetReal ( m[2][0],Loop,CIFTAG_MATRIX31,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( m[2][1],Loop,CIFTAG_MATRIX32,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( m[2][2],Loop,CIFTAG_MATRIX33,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal ( v[2]   ,Loop,CIFTAG_VECTOR3 ,n );
+    if (rc!=Error_NoError)  return rc;
+    WhatIsSet |= NCSMSET_Matrix3;
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  NCSMatrix::SetNCSMatrix ( int serialNum,
+                                   mat33 & ncs_m, vect3 & ncs_v,
+                                   int i_Given )  {
+  int i,j;
+    serNum = serialNum;
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        m[i][j] = ncs_m[i][j];
+      v[i] = ncs_v[i];
+    }
+    iGiven     = i_Given;
+    WhatIsSet |= NCSMSET_All;
+  }
+
+  void  NCSMatrix::Copy ( PContainerClass NCSMatrix )  {
+  int i,j;
+
+    serNum = PNCSMatrix(NCSMatrix)->serNum;
+    iGiven = PNCSMatrix(NCSMatrix)->iGiven;
+
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        m[i][j] = PNCSMatrix(NCSMatrix)->m[i][j];
+      v[i] = PNCSMatrix(NCSMatrix)->v[i];
+    }
+
+    WhatIsSet = PNCSMatrix(NCSMatrix)->WhatIsSet;
+
+  }
+
+  void  NCSMatrix::write ( io::RFile f )  {
+  int  i,j;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    f.WriteInt  ( &serNum  );
+    f.WriteInt  ( &iGiven  );
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        f.WriteReal ( &(m[i][j]) );
+      f.WriteReal ( &(v[i]) );
+    }
+    f.WriteWord ( &WhatIsSet );
+  }
+
+  void  NCSMatrix::read ( io::RFile f ) {
+  int  i,j;
+  byte Version;
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &serNum  );
+    f.ReadInt  ( &iGiven  );
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        f.ReadReal ( &(m[i][j]) );
+      f.ReadReal ( &(v[i]) );
+    }
+    f.ReadWord ( &WhatIsSet );
+  }
+
+  MakeStreamFunctions(NCSMatrix)
+
+
+
+  //  ================  TVect  ===================
+
+  TVect::TVect() : ContainerClass()  {
+    Init();
+  }
+
+  TVect::TVect ( cpstr S ) : ContainerClass()  {
+    Init();
+    ConvertPDBASCII ( S );
+  }
+
+  TVect::TVect ( io::RPStream Object ) : ContainerClass(Object)  {
+    Init();
+  }
+
+  TVect::~TVect()  {
+    if (comment)  delete[] comment;
+  }
+
+  void TVect::Init()  {
+    serNum  = -1;
+    t[0]    = 0.0;
+    t[1]    = 0.0;
+    t[2]    = 0.0;
+    comment = NULL;
+  }
+
+  void TVect::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB TVECT line number N
+    sprintf   ( S,"TVECT  %3i",serNum );
+    PadSpaces ( S,80 );
+    PutRealF  ( &(S[10]),t[0],10,5 );
+    PutRealF  ( &(S[20]),t[1],10,5 );
+    PutRealF  ( &(S[30]),t[2],10,5 );
+    if (comment)
+      strncpy ( &(S[40]),comment,IMin(30,strlen(comment)) );
+  }
+
+  ERROR_CODE TVect::ConvertPDBASCII ( cpstr S )  {
+    GetInteger ( serNum ,&(S[7]) ,3  );
+    GetReal    ( t[0]   ,&(S[10]),10 );
+    GetReal    ( t[1]   ,&(S[20]),10 );
+    GetReal    ( t[2]   ,&(S[30]),10 );
+    CreateCopy ( comment,&(S[40])    );
+    return Error_NoError;
+
+  }
+
+  void TVect::MakeCIF ( mmcif::PData CIF, int N )  {
+  mmcif::PLoop Loop;
+  int         RC;
+    RC = CIF->AddLoop ( CIFCAT_DATABASE_PDB_TVECT,Loop );
+    if ((RC!=mmcif::CIFRC_Ok) || (N==0))  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_ID      );
+      Loop->AddLoopTag ( CIFTAG_VECTOR1 );
+      Loop->AddLoopTag ( CIFTAG_VECTOR2 );
+      Loop->AddLoopTag ( CIFTAG_VECTOR3 );
+      Loop->AddLoopTag ( CIFTAG_DETAILS );
+    }
+    Loop->AddInteger ( serNum  );
+    Loop->AddReal    ( t[0]    );
+    Loop->AddReal    ( t[1]    );
+    Loop->AddReal    ( t[2]    );
+    Loop->AddString  ( comment );
+  }
+
+  ERROR_CODE TVect::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  ERROR_CODE   rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_DATABASE_PDB_TVECT );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+
+    if (n>=Loop->GetLoopLength())  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    rc = CIFGetInteger(serNum,Loop,CIFTAG_ID,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal(t[0],Loop,CIFTAG_VECTOR1,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal(t[1],Loop,CIFTAG_VECTOR2,n );
+    if (rc!=Error_NoError)  return rc;
+    rc = CIFGetReal(t[2],Loop,CIFTAG_VECTOR3,n );
+    if (rc!=Error_NoError)  return rc;
+    Loop->GetString ( comment,CIFTAG_DETAILS,n,true );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+
+  void  TVect::Copy ( PContainerClass TVect )  {
+  int i;
+    serNum = PTVect(TVect)->serNum;
+    for (i=0;i<3;i++)
+      t[i] = PTVect(TVect)->t[i];
+    CreateCopy ( comment,PTVect(TVect)->comment );
+  }
+
+  void  TVect::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    f.WriteInt  ( &serNum  );
+    for (i=0;i<3;i++)
+      f.WriteReal ( &(t[i]) );
+    f.CreateWrite ( comment );
+  }
+
+  void  TVect::read ( io::RFile f ) {
+  int  i;
+  byte Version;
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &serNum  );
+    for (i=0;i<3;i++)
+      f.ReadReal ( &(t[i]) );
+    f.CreateRead ( comment );
+  }
+
+  MakeStreamFunctions(TVect)
+
+
+
+  //  =====================   Cryst   =======================
+
+  Cryst::Cryst() : io::Stream() {
+    Init ( true );
+  }
+
+  Cryst::Cryst ( io::RPStream Object ) : io::Stream(Object)  {
+    Init ( true );
+  }
+
+  void  Cryst::Init ( bool fullInit )  {
+  int i,j,k;
+
+    WhatIsSet = 0;  // nothing is set
+    a         = 1.0;
+    b         = 1.0;
+    c         = 1.0;
+    alpha     = 90.0;
+    beta      = 90.0;
+    gamma     = 90.0;
+    strcpy ( spaceGroup   ,"" );
+    strcpy ( spaceGroupFix,"" );
+    Z         = 1;
+    CellCheck = CCHK_NoCell;
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)  {
+        o[i][j] = 0.0;
+        s[i][j] = 0.0;
+        for (k=0;k<6;k++)
+          RR[k][i][j] = 0.0;
+      }
+      o[i][i] = 1.0;
+      s[i][i] = 1.0;
+      t[i]    = 0.0;
+      u[i]    = 0.0;
+      for (k=0;k<6;k++)
+        RR[k][i][i] = 1.0;
+    }
+    for (i=0;i<4;i++)  {
+      for (j=0;j<4;j++)  {
+        RO [i][j] = 0.0;
+        RF [i][j] = 0.0;
+        ROU[i][j] = 0.0;
+        RFU[i][j] = 0.0;
+      }
+      RO [i][i] = 1.0;
+      RF [i][i] = 1.0;
+      ROU[i][i] = 1.0;
+      RFU[i][i] = 1.0;
+    }
+    Vol    = 0.0;
+    VolChk = 0.0;
+    VolErr = 0.0;
+    as     = 1.0;
+    bs     = 1.0;
+    cs     = 1.0;
+    alphas = 90.0;
+    betas  = 90.0;
+    gammas = 90.0;
+
+    for (k=0;k<6;k++)
+      AC[k] = 0.0;
+
+    NCode  = 0;
+
+    if (fullInit)  {
+      syminfo_lib   = NULL;
+      ignoreScalei  = false;  // flag to ignore SCALEi cards
+      processSG     = true;   // flag to process space group at file read
+      fixSpaceGroup = true;   // flag to fix space group at file read
+    }
+
+  }
+
+  Cryst::~Cryst() {
+    FreeMemory();
+    if (syminfo_lib)  delete[] syminfo_lib;
+  }
+
+  void  Cryst::FreeMemory()  {
+    ncsMatrix.FreeContainer();
+    tVect    .FreeContainer();
+    symOps   .FreeMemory   ();
+  }
+
+  void  Cryst::Reset()  {
+    FreeMemory();
+    Init ( false );
+  }
+
+  cpstr rhombohedral[] = {
+    cpstr("R 3"  ),
+    cpstr("R 3"  ),
+    cpstr("R 3 2"),
+    cpstr("R 3 2")
+  };
+
+  cpstr short_mono[] = {
+    cpstr("P 2" ),
+    cpstr("P 21"),
+    cpstr("C 2" ),
+    cpstr("A 2" ),
+    cpstr("B 2" ),
+    cpstr("I 2" )
+  };
+
+  cpstr special[] = {
+    cpstr("A1"     ),
+              cpstr("Hall:  P 1 (-x,-1/2*y+1/2*z,1/2*y+1/2*z)"  ),
+    cpstr("C1211"  ),
+              cpstr("Hall:  C 2y (x+1/4,y+1/4,z)"               ),
+    cpstr("C21"    ),
+              cpstr("Hall:  C 2y (x+1/4,y+1/4,z)"               ),
+    cpstr("I1211"  ),
+              cpstr("Hall:  C 2y (x+1/4,y+1/4,-x+z-1/4)"        ),
+    cpstr("I21"    ),
+              cpstr("Hall:  C 2y (x+1/4,y+1/4,-x+z-1/4)"        ),
+    cpstr("P21212A"),
+              cpstr("Hall:  P 2 2ab (x+1/4,y+1/4,z)"            ),
+    cpstr("F422"   ),
+              cpstr("Hall:  I 4 2 (1/2*x+1/2*y,-1/2*x+1/2*y,z)" ),
+    cpstr("C4212"  ),
+              cpstr("Hall:  P 4 2 (1/2*x+1/2*y-1/4,-1/2*x+1/2*y-1/4,z)")
+  };
+
+
+
+  int  Cryst::FixSpaceGroup()  {
+  //  This function attempts to clean up the Brookhaven mess in space
+  // group naming, by checking the space group symbol with cell
+  // parameters.  Returns:
+  //
+  //     0    - space group symbol is correct, spaceGroupFix receives
+  //            a copy of spaceGroup
+  //     1    - space group symbol does not agree with cell parameters,
+  //            and fixed successfully. spaceGroupFix receives
+  //            the appropriate space group symbol
+  //    -1    - space group symbol does not agree with cell parameters,
+  //            however fix is not possible.  spaceGroupFix receives
+  //            a copy of spaceGroup
+  //    -2    - any checks are not possible because cell parameters
+  //            are not found, spaceGroupFix receives a copy of
+  //            spaceGroup
+  //
+  realtype eps,m1,m2;
+  SymGroup s;
+  int      i,k;
+  char     c;
+
+    strcpy ( spaceGroupFix,spaceGroup );
+
+    if ((WhatIsSet & CSET_CellParams)!=CSET_CellParams)  return -2;
+
+    eps = 0.01;
+
+    k = -1;
+    for (i=0;(i<4) && (k<0);i++)
+      if (!strcmp(spaceGroup,rhombohedral[i]))  k = i;
+
+    if (k>=0)  {
+      c = 'N';
+      if ((fabs(a-b)<=eps) && (fabs(alpha-90.0)<=eps) &&
+          (fabs(beta-90.0)<=eps) && (fabs(gamma-120.0)<=eps))
+        c = 'H';
+      else {
+        m1 = (a+b+c)/3.0;
+        m2 = (alpha+beta+gamma)/3.0;
+        if ((fabs(a-m1)<=eps) && (fabs(b-m1)<=eps) &&
+            (fabs(c-m1)<=eps) &&
+            (fabs(alpha-m2)<=eps) && (fabs(beta-m2)<=eps) &&
+            (fabs(gamma-m2)<=eps))
+          c = 'R';
+      }
+      if (c!=spaceGroup[0])  {
+        if (c!='N')  {
+          spaceGroupFix[0] = c;
+          return 1;
+        }
+        return -1;
+      }
+      return 0;
+    }
+
+    for (i=0;(i<6) && (k<0);i++)
+      if (!strcmp(spaceGroup,short_mono[i]))  k = i;
+
+    if (k>=0)  {
+      if ((fabs(alpha-90.0)<=eps) && (fabs(gamma-90.0)<=eps))  {
+        if (spaceGroup[0]=='B')  return -1;
+        sprintf ( spaceGroupFix,"%c 1 %s 1",spaceGroup[0],
+                  &(spaceGroup[2]) );
+        return 1;
+      }
+      if ((fabs(alpha-90.0)<=eps) && (fabs(beta-90.0)<=eps))  {
+        if (spaceGroup[0]=='C')  return -1;
+        sprintf ( spaceGroupFix,"%c 1 1 %s",spaceGroup[0],
+                  &(spaceGroup[2]) );
+        return 1;
+      }
+      return -1;
+    }
+
+    i = 0;
+    k = 0;
+    while (spaceGroup[i])  {
+      if (spaceGroup[i]!=' ')  s[k++] = spaceGroup[i];
+      i++;
+    }
+    s[k] = char(0);
+
+    k = -1;
+    for (i=0;(i<16) && (k<0);i+=2)
+      if (!strcmp(s,special[i]))  k = i;
+
+    if (k>=0)  {
+      strcpy ( spaceGroupFix,special[k+1] );
+      return 1;
+    }
+
+    return 0;
+
+  }
+
+  ERROR_CODE Cryst::ConvertPDBString ( pstr PDBString )  {
+  // Interprets the ASCII PDB line and fills the corresponding fields.
+  //   Returns zero if the line was converted, otherwise returns a
+  // non-negative value of Error_XXXX.
+  //   PDBString must be not shorter than 81 characters.
+  PNCSMatrix ncsMtx;
+  PTVect     tV;
+  ERROR_CODE RC;
+
+    //  pad input line with spaces, if necessary
+    PadSpaces ( PDBString,80 );
+
+    if (!strncmp(PDBString,"CRYST",5))  {
+      // Here we check for "CRYST" and not for "CRYST1" keyword.
+      // As seems, people tend to not differentiating them.
+      if (GetReal(a,&(PDBString[6]) ,9) &&
+          GetReal(b,&(PDBString[15]),9) &&
+          GetReal(c,&(PDBString[24]),9))
+        WhatIsSet |= CSET_CellParams1;
+
+      if (GetReal(alpha,&(PDBString[33]),7) &&
+          GetReal(beta ,&(PDBString[40]),7) &&
+          GetReal(gamma,&(PDBString[47]),7))
+        WhatIsSet |= CSET_CellParams2;
+
+      GetString ( spaceGroup,&(PDBString[55]),11 );
+      CutSpaces ( spaceGroup,SCUTKEY_BEGEND );
+      if (fixSpaceGroup)  FixSpaceGroup();
+                    else  strcpy ( spaceGroupFix,spaceGroup );
+      if (spaceGroupFix[0] && processSG)  {
+        if (symOps.SetGroup(spaceGroupFix,syminfo_lib)==SYMOP_Ok)
+          WhatIsSet |= CSET_SpaceGroup;
+      }
+
+      if (GetInteger(Z,&(PDBString[66]),4))
+        WhatIsSet |= CSET_ZValue;
+
+      WhatIsSet &= 0xFBFF;
+
+      if ((a*b*c*alpha*beta*gamma==0.0) ||
+          ((a==1.0)      && (b==1.0)     && (c==1.0)      &&
+           (alpha==90.0) && (beta==90.0) && (gamma==90.0) &&
+           (!strcmp(spaceGroup,"P 1"))))  {
+        WhatIsSet &= ~(CSET_CellParams1 | CSET_CellParams2 |
+                       CSET_SpaceGroup);
+        WhatIsSet |= CSET_DummyCell;
+      }
+
+    } else if (!strncmp(PDBString,"ORIGX1",6))  {
+
+      if (GetReal(o[0][0],&(PDBString[10]),10) &&
+          GetReal(o[0][1],&(PDBString[20]),10) &&
+          GetReal(o[0][2],&(PDBString[30]),10) &&
+          GetReal(t[0]   ,&(PDBString[45]),10))
+        WhatIsSet |= CSET_OrigMatrix1;
+
+    } else if (!strncmp(PDBString,"ORIGX2",6))  {
+
+      if (GetReal(o[1][0],&(PDBString[10]),10) &&
+          GetReal(o[1][1],&(PDBString[20]),10) &&
+          GetReal(o[1][2],&(PDBString[30]),10) &&
+          GetReal(t[1]   ,&(PDBString[45]),10))
+        WhatIsSet |= CSET_OrigMatrix2;
+
+    } else if (!strncmp(PDBString,"ORIGX3",6))  {
+
+      if (GetReal(o[2][0],&(PDBString[10]),10) &&
+          GetReal(o[2][1],&(PDBString[20]),10) &&
+          GetReal(o[2][2],&(PDBString[30]),10) &&
+          GetReal(t[2]   ,&(PDBString[45]),10))
+        WhatIsSet |= CSET_OrigMatrix3;
+
+    } else if (!strncmp(PDBString,"SCALE1",6))  {
+
+      if (GetReal(s[0][0],&(PDBString[10]),10) &&
+          GetReal(s[0][1],&(PDBString[20]),10) &&
+          GetReal(s[0][2],&(PDBString[30]),10) &&
+          GetReal(u[0]   ,&(PDBString[45]),10))
+        WhatIsSet |= CSET_ScaleMatrix1;
+      WhatIsSet &= 0xFBFF;
+      CellCheck |= CCHK_Unchecked;
+
+    } else if (!strncmp(PDBString,"SCALE2",6))  {
+
+      if (GetReal(s[1][0],&(PDBString[10]),10) &&
+          GetReal(s[1][1],&(PDBString[20]),10) &&
+          GetReal(s[1][2],&(PDBString[30]),10) &&
+          GetReal(u[1]   ,&(PDBString[45]),10))
+        WhatIsSet |= CSET_ScaleMatrix2;
+      WhatIsSet &= 0xFBFF;
+      CellCheck |= CCHK_Unchecked;
+
+    } else if (!strncmp(PDBString,"SCALE3",6))  {
+
+      if (GetReal(s[2][0],&(PDBString[10]),10) &&
+          GetReal(s[2][1],&(PDBString[20]),10) &&
+          GetReal(s[2][2],&(PDBString[30]),10) &&
+          GetReal(u[2]   ,&(PDBString[45]),10))
+        WhatIsSet |= CSET_ScaleMatrix3;
+      WhatIsSet &= 0xFBFF;
+      CellCheck |= CCHK_Unchecked;
+
+    } else if (!strncmp(PDBString,"MTRIX",5))  {
+
+      RC = ncsMatrix.AddMTRIXLine ( PDBString );
+      if (RC==Error_NCSM_WrongSerial)  {
+        ncsMtx = new NCSMatrix();
+        RC = ncsMtx->ConvertPDBASCII ( PDBString );
+        if (RC==0)  ncsMatrix.AddData ( ncsMtx );
+              else  delete ncsMtx;
+      }
+      return RC;
+
+    } else if (!strncmp(PDBString,"TVECT ",6))  {
+
+      tV = new TVect();
+      RC = tV->ConvertPDBASCII(PDBString);
+      if (RC==0)  tVect.AddData ( tV );
+            else  delete tV;
+      return RC;
+
+    } else
+      return Error_WrongSection;
+
+    return Error_NoError;
+
+  }
+
+  void  Cryst::PDBASCIIDump ( io::RFile f )  {
+  int  i,j;
+  char S[100];
+
+    if (WhatIsSet & (CSET_CrystCard | CSET_DummyCell))  {
+      strcpy    ( S,"CRYST1" );
+      PadSpaces ( S,80 );
+      if (WhatIsSet & CSET_CellParams1)  {
+        PutRealF ( &(S[6 ]),a,9,3 );
+        PutRealF ( &(S[15]),b,9,3 );
+        PutRealF ( &(S[24]),c,9,3 );
+      }
+      if (WhatIsSet & CSET_CellParams2)  {
+        PutRealF ( &(S[33]),alpha,7,2 );
+        PutRealF ( &(S[40]),beta ,7,2 );
+        PutRealF ( &(S[47]),gamma,7,2 );
+      }
+      if ((WhatIsSet & CSET_SpaceGroup) || (spaceGroup[0]))
+        strncpy ( &(S[55]),spaceGroup,IMin(11,strlen(spaceGroup)) );
+      if (WhatIsSet & CSET_ZValue)
+        PutInteger ( &(S[66]),Z,4 );
+      f.WriteLine ( S );
+    }
+
+    if ((WhatIsSet & CSET_OrigMatrix)==CSET_OrigMatrix)
+      for (i=0;i<3;i++)  {
+        sprintf   ( S,"ORIGX%1i",i+1);
+        PadSpaces ( S,80 );
+        for (j=0;j<3;j++)
+          PutRealF ( &(S[10+j*10]),o[i][j],10,6 );
+        PutRealF ( &(S[45]),t[i],10,5 );
+        f.WriteLine ( S );
+      }
+
+    if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)
+      for (i=0;i<3;i++)  {
+        sprintf   ( S,"SCALE%1i",i+1);
+        PadSpaces ( S,80 );
+        for (j=0;j<3;j++)
+          PutRealF ( &(S[10+j*10]),s[i][j],10,6 );
+        PutRealF ( &(S[45]),u[i],10,5 );
+        f.WriteLine ( S );
+      }
+
+    ncsMatrix.PDBASCIIDump ( f );
+    tVect    .PDBASCIIDump ( f );
+
+  }
+
+
+  ERROR_CODE Cryst::GetCIF ( mmcif::PData CIF ) {
+  mmcif::PStruct cifStruct;
+  ERROR_CODE     RC;
+
+    WhatIsSet = 0;
+
+    cifStruct = CIF->GetStructure ( CIFCAT_CELL );
+
+    if (cifStruct)  {
+
+      RC = CIFGetReal ( a,cifStruct,CIFTAG_LENGTH_A );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( b,cifStruct,CIFTAG_LENGTH_B );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( c,cifStruct,CIFTAG_LENGTH_C );
+      if (RC==Error_UnrecognizedReal)  return RC;
+      if (RC==Error_NoError)  WhatIsSet |= CSET_CellParams1;
+
+      RC = CIFGetReal ( alpha,cifStruct,CIFTAG_ANGLE_ALPHA );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( beta,cifStruct,CIFTAG_ANGLE_BETA );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( gamma,cifStruct,CIFTAG_ANGLE_GAMMA );
+      if (RC==Error_UnrecognizedReal)  return RC;
+      if (RC==Error_NoError)  WhatIsSet |= CSET_CellParams2;
+
+      RC = CIFGetInteger ( Z,cifStruct,CIFTAG_Z_PDB );
+      if (RC==Error_UnrecognizedReal)  return RC;
+      if (RC==Error_NoError) WhatIsSet |= CSET_ZValue;
+
+    }
+
+    cifStruct = CIF->GetStructure ( CIFCAT_SYMMETRY );
+    if (cifStruct)  {
+      CIFGetString ( spaceGroup,cifStruct,CIFTAG_SPACE_GROUP_NAME_H_M,
+                     sizeof(spaceGroup),pstr("") );
+      CutSpaces ( spaceGroup,SCUTKEY_BEGEND );
+      if (fixSpaceGroup)  FixSpaceGroup();
+                    else  strcpy ( spaceGroupFix,spaceGroup );
+      /*
+      if (fixSpaceGroup)  {
+        if (!strcasecmp(spaceGroup,"P 21"))
+          strcpy ( spaceGroup,"P 1 21 1" );
+        else if (!strcasecmp(spaceGroup,"C 2"))
+          strcpy ( spaceGroup,"C 1 2 1" );
+      }
+      */
+      if (spaceGroupFix[0] && processSG)  {
+        if (symOps.SetGroup(spaceGroupFix,syminfo_lib)==SYMOP_Ok)
+          WhatIsSet |= CSET_SpaceGroup;
+      }
+    }
+
+    if ((a*b*c*alpha*beta*gamma==0.0) ||
+        ((a==1.0)      && (b==1.0)     && (c==1.0)      &&
+         (alpha==90.0) && (beta==90.0) && (gamma==90.0) &&
+         (!strcmp(spaceGroup,"P 1"))))  {
+      WhatIsSet &= ~(CSET_CellParams1 | CSET_CellParams2 |
+                     CSET_SpaceGroup);
+      WhatIsSet |= CSET_DummyCell;
+    }
+
+    cifStruct = CIF->GetStructure ( CIFCAT_DATABASE_PDB_MATRIX );
+    if (cifStruct)  {
+      RC = CIFGetReal ( o[0][0],cifStruct,CIFTAG_ORIGX11 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[0][1],cifStruct,CIFTAG_ORIGX12 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[0][2],cifStruct,CIFTAG_ORIGX13 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[1][0],cifStruct,CIFTAG_ORIGX21 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[1][1],cifStruct,CIFTAG_ORIGX22 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[1][2],cifStruct,CIFTAG_ORIGX23 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[2][0],cifStruct,CIFTAG_ORIGX31 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[2][1],cifStruct,CIFTAG_ORIGX32 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( o[2][2],cifStruct,CIFTAG_ORIGX33 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( t[0],cifStruct,CIFTAG_ORIGX_VECTOR1 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( t[1],cifStruct,CIFTAG_ORIGX_VECTOR2 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal ( t[2],cifStruct,CIFTAG_ORIGX_VECTOR3 );
+      if (RC!=Error_NoError)  return RC;
+      WhatIsSet |= CSET_OrigMatrix;
+    }
+
+    cifStruct = CIF->GetStructure ( CIFCAT_ATOM_SITES );
+    if (cifStruct)  {
+      RC = CIFGetReal ( s[0][0],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX11 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[0][1],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX12);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[0][2],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX13);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[1][0],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX21);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[1][1],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX22);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[1][2],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX23);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[2][0],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX31);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[2][1],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX32);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(s[2][2],cifStruct,CIFTAG_FRACT_TRANSF_MATRIX33);
+      if (RC==Error_NoError)
+        RC = CIFGetReal(u[0]   ,cifStruct,CIFTAG_FRACT_TRANSF_VECTOR1 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal(u[1]   ,cifStruct,CIFTAG_FRACT_TRANSF_VECTOR2 );
+      if (RC==Error_NoError)
+        RC = CIFGetReal(u[2]   ,cifStruct,CIFTAG_FRACT_TRANSF_VECTOR3 );
+      if (RC!=Error_NoError)  return RC;
+      WhatIsSet |= CSET_ScaleMatrix;
+    }
+
+    RC = ncsMatrix.GetCIF(CIF,ClassID_NCSMatrix);
+    if (RC!=Error_NoError) return RC;
+
+    RC = tVect.GetCIF(CIF,ClassID_TVect);
+    return RC;
+
+  }
+
+  void Cryst::MakeCIF ( mmcif::PData CIF )  {
+  mmcif::PStruct cifStruct;
+  char           S[200];
+
+    if (WhatIsSet & (CSET_CellParams1 | CSET_DummyCell))  {
+      CIF->AddStructure ( CIFCAT_CELL,cifStruct );
+      cifStruct->PutReal ( a,CIFTAG_LENGTH_A,8 );
+      cifStruct->PutReal ( b,CIFTAG_LENGTH_B,8 );
+      cifStruct->PutReal ( c,CIFTAG_LENGTH_C,8 );
+    }
+
+    if (WhatIsSet & (CSET_CellParams2 | CSET_DummyCell))  {
+      CIF->AddStructure ( CIFCAT_CELL,cifStruct );
+      cifStruct->PutReal ( alpha,CIFTAG_ANGLE_ALPHA,8 );
+      cifStruct->PutReal ( beta ,CIFTAG_ANGLE_BETA, 8 );
+      cifStruct->PutReal ( gamma,CIFTAG_ANGLE_GAMMA,8 );
+    }
+
+    if ((WhatIsSet & (CSET_SpaceGroup | CSET_DummyCell)) ||
+        (spaceGroup[0]))
+      CIF->PutString ( strcpy_cs(S,spaceGroup),CIFCAT_SYMMETRY,
+                       CIFTAG_SPACE_GROUP_NAME_H_M );
+
+    if (WhatIsSet & (CSET_ZValue | CSET_DummyCell))
+      CIF->PutInteger ( Z,CIFCAT_CELL,CIFTAG_Z_PDB );
+
+
+    if ((WhatIsSet & CSET_OrigMatrix)==CSET_OrigMatrix)  {
+      CIF->AddStructure ( CIFCAT_DATABASE_PDB_MATRIX,cifStruct );
+      cifStruct->PutReal ( o[0][0],CIFTAG_ORIGX11      ,8 );
+      cifStruct->PutReal ( o[0][1],CIFTAG_ORIGX12      ,8 );
+      cifStruct->PutReal ( o[0][2],CIFTAG_ORIGX13      ,8 );
+      cifStruct->PutReal ( o[1][0],CIFTAG_ORIGX21      ,8 );
+      cifStruct->PutReal ( o[1][1],CIFTAG_ORIGX22      ,8 );
+      cifStruct->PutReal ( o[1][2],CIFTAG_ORIGX23      ,8 );
+      cifStruct->PutReal ( o[2][0],CIFTAG_ORIGX31      ,8 );
+      cifStruct->PutReal ( o[2][1],CIFTAG_ORIGX32      ,8 );
+      cifStruct->PutReal ( o[2][2],CIFTAG_ORIGX33      ,8 );
+      cifStruct->PutReal ( t[0]   ,CIFTAG_ORIGX_VECTOR1,8 );
+      cifStruct->PutReal ( t[1]   ,CIFTAG_ORIGX_VECTOR2,8 );
+      cifStruct->PutReal ( t[2]   ,CIFTAG_ORIGX_VECTOR3,8 );
+    }
+
+    if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)  {
+      CIF->AddStructure ( CIFCAT_ATOM_SITES,cifStruct );
+      cifStruct->PutReal ( s[0][0],CIFTAG_FRACT_TRANSF_MATRIX11,8 );
+      cifStruct->PutReal ( s[0][1],CIFTAG_FRACT_TRANSF_MATRIX12,8 );
+      cifStruct->PutReal ( s[0][2],CIFTAG_FRACT_TRANSF_MATRIX13,8 );
+      cifStruct->PutReal ( s[1][0],CIFTAG_FRACT_TRANSF_MATRIX21,8 );
+      cifStruct->PutReal ( s[1][1],CIFTAG_FRACT_TRANSF_MATRIX22,8 );
+      cifStruct->PutReal ( s[1][2],CIFTAG_FRACT_TRANSF_MATRIX23,8 );
+      cifStruct->PutReal ( s[2][0],CIFTAG_FRACT_TRANSF_MATRIX31,8 );
+      cifStruct->PutReal ( s[2][1],CIFTAG_FRACT_TRANSF_MATRIX32,8 );
+      cifStruct->PutReal ( s[2][2],CIFTAG_FRACT_TRANSF_MATRIX33,8 );
+      cifStruct->PutReal ( u[0]   ,CIFTAG_FRACT_TRANSF_VECTOR1 ,8 );
+      cifStruct->PutReal ( u[1]   ,CIFTAG_FRACT_TRANSF_VECTOR2 ,8 );
+      cifStruct->PutReal ( u[2]   ,CIFTAG_FRACT_TRANSF_VECTOR3 ,8 );
+    }
+
+    ncsMatrix.MakeCIF ( CIF );
+    tVect    .MakeCIF ( CIF );
+
+  }
+
+
+
+  cpstr OrthCode[6] = {
+    cpstr("A/X0, C*/Z0"), // (standard brookhaven)
+    cpstr("B/X0, A*/Z0"),
+    cpstr("C/X0, B*/Z0"),
+    cpstr("HEX A+B/X0, C*/Z0"),
+    cpstr("A*/X0, C/Z0 (rollett)"),
+    cpstr("A/X0, B*/Y0")
+  };
+
+  cpstr getOrthCodeName ( int NCode )  {
+    if ((NCode>0) && (NCode<=6))  return OrthCode[NCode-1];
+    return cpstr("CUSTOM");
+  }
+
+  void  Cryst::CalcCoordTransforms()  {
+  realtype rChk1,rChk2,Fac;
+  int      i,j,k;
+
+    WhatIsSet &= ~CSET_Transforms;  // clear the flag
+
+    if ((WhatIsSet & CSET_CellParams)==CSET_CellParams)  {
+      //   The 'cryst1' card was supplied. Calculate
+      // standard orthogonalizations.
+
+      CalcOrthMatrices();
+      if (NCode<0)  NCode = 0;
+
+      for (i=0;i<3;i++)  {
+        for (j=0;j<3;j++)
+          RO[i][j] = RR[NCode][i][j];
+        RO[i][3] = 0.0;
+        RO[3][i] = 0.0;
+      }
+      RO[3][3] = 1.0;
+      Mat4Inverse ( RO,RF );
+
+      WhatIsSet |= CSET_Transforms;
+
+      if (ignoreScalei)
+        CellCheck = CCHK_Ok;
+      else if ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix)  {
+        //   All 'scalei' cards were supplied. Calculate
+        // rotation and translation matrices and check
+        // if they are in consistence with the cell.
+
+        for (i=0;i<3;i++)  {
+          for (j=0;j<3;j++)
+            RF[i][j] = s[i][j];
+          RF[i][3] = u[i];
+          RF[3][i] = 0.0;
+        }
+        RF[3][3] = 1.0;
+        Mat4Inverse ( RF,RO );
+
+        // Find orthogonalisation type
+        VolChk = RO[0][0]*(RO[1][1]*RO[2][2] - RO[1][2]*RO[2][1]) +
+                 RO[0][1]*(RO[1][2]*RO[2][0] - RO[1][0]*RO[2][2]) +
+                 RO[0][2]*(RO[1][0]*RO[2][1] - RO[1][1]*RO[2][0]);
+
+        CellCheck = CCHK_Ok;
+        if (Vol>0.0)  {
+          VolErr = fabs(VolChk-Vol)/Vol;
+          if (VolErr>0.02)     CellCheck |= CCHK_Error;
+          else if (VolErr>0.1) CellCheck |= CCHK_Disagreement;
+        } else
+          CellCheck |= CCHK_NoCell;
+
+        //  try to find NCode
+        NCode = -1;
+        for (k=0;(k<6) && (NCode<0);k++)  {
+          NCode = k;
+          for (i=0;i<3;i++)
+            for (j=0;j<3;j++)  {
+              rChk1 = RO[i][j] + RR[k][i][j];
+              rChk2 = RO[i][j] - RR[k][i][j];
+              if (fabs(rChk1)>=0.1)  {
+                if (fabs(rChk2/rChk1)>0.01)
+                  NCode = -1;
+              }
+            }
+        }
+
+        //   Correct inaccuracy of SCALEi input due to FORMAT,
+        // replace RF,RO with RR[NCode][][] if possible.
+
+        if (NCode>=0)  {
+          for (i=0;i<3;i++)
+            for (j=0;j<3;j++)
+              RO[i][j] = RR[NCode][i][j];
+          Mat4Inverse ( RO,RF );
+        } else
+          CellCheck |= CCHK_NoOrthCode;
+
+        if ((u[0]!=0.0) || (u[1]!=0.0) || (u[2]!=0.0))
+          CellCheck |= CCHK_Translations;
+
+      }
+
+      //  Generate ROU and RFU for AnisoU stuff
+      RFU[3][3] = 1.0;
+      for (i=0;i<3;i++)  {
+        Fac = sqrt(RF[i][0]*RF[i][0] + RF[i][1]*RF[i][1] +
+                   RF[i][2]*RF[i][2]);
+        RFU[i][0] = RF[i][0]/Fac;
+        RFU[i][1] = RF[i][1]/Fac;
+        RFU[i][2] = RF[i][2]/Fac;
+        RFU[i][3] = 0.0;
+        RFU[3][i] = 0.0;
+      }
+      RFU[3][3] = 1.0;
+      Mat4Inverse ( RFU,ROU );
+
+    } else
+      CellCheck |= CCHK_NoCell;
+
+  }
+
+
+  void  Cryst::RWBROOKReadPrintout()  {
+  int i,j;
+
+    if ((WhatIsSet & CSET_CellParams)==CSET_CellParams)  {
+      printf ( "  MATRICES DERIVED FROM CRYST1"
+               " CARD IN COORDINATE FILE\n\n\n"
+               "             RF                 "
+               "                 RO\n\n" );
+      for (i=0;i<4;i++)  {
+        printf ( " " );
+        for (j=0;j<4;j++)
+          printf ( "%8.3f",RF[i][j] );
+        printf ( "     " );
+        for (j=0;j<4;j++)
+          printf ( "%8.3f",RO[i][j] );
+        printf ( "\n" );
+      }
+      printf ( "\n" );
+    } else
+      printf ( "\n  $WARNING: NO CRYST CARDS READ$\n" );
+
+    if ((WhatIsSet & CSET_ScaleMatrix)!=CSET_ScaleMatrix)
+      printf ( "\n  $WARNING: NO SCALE CARDS READ$\n" );
+
+  }
+
+
+  void  Cryst::CalcOrthMatrices()  {
+  //  Calculates matrices for standard orthogonalizations
+  // and the cell volume.
+  //  The matrices are stored in array RR
+  realtype Conv,Alph,Bet,Gamm,Sum,V;
+  realtype sinA,cosA,sinB,cosB,sinG,cosG;
+  realtype sinAS,cosAS,sinBS,cosBS,sinGS,cosGS;
+  int      i,j,k;
+
+    if ((WhatIsSet & CSET_CellParams)!=CSET_CellParams)  return;
+
+    Conv = Pi/180.0;
+
+    Alph = alpha*Conv;
+    Bet  = beta *Conv;
+    Gamm = gamma*Conv;
+
+    Sum  = (Alph+Bet+Gamm)*0.5;
+
+    V    = sqrt(sin(Sum-Alph)*sin(Sum-Bet)*sin(Sum-Gamm)*sin(Sum));
+
+    Vol  = 2.0*a*b*c*V;
+
+    //  Precaution measure for erratic use of the library
+    if ((fabs(Alph)<1.0e-6) || (fabs(Bet)<1.0e-6) ||
+                               (fabs(Gamm)<1.0e-6))  {
+      as     = 0.0;
+      bs     = 0.0;
+      cs     = 0.0;
+      alphas = 0.0;
+      betas  = 0.0;
+      gammas = 0.0;
+      for (k=0;k<6;k++)  {
+        AC[k] = 0.0;
+        for (i=0;i<3;i++)  {
+          for (j=0;j<3;j++)
+            RR[k][i][j] = 0.0;
+          RR[k][i][i] = 1.0;
+        }
+      }
+      return;
+    }
+
+    sinA   = sin(Alph);
+    cosA   = cos(Alph);
+    sinB   = sin(Bet);
+    cosB   = cos(Bet);
+    sinG   = sin(Gamm);
+    cosG   = cos(Gamm);
+
+    cosAS  = (cosG*cosB-cosA) / (sinB*sinG);
+    sinAS  = sqrt(1.0-cosAS*cosAS);
+    cosBS  = (cosA*cosG-cosB) / (sinA*sinG);
+    sinBS  = sqrt(1.0-cosBS*cosBS);
+    cosGS  = (cosA*cosB-cosG) / (sinA*sinB);
+    sinGS  = sqrt(1.0-cosGS*cosGS);
+
+    as     = b*c*sinA/Vol;
+    bs     = c*a*sinB/Vol;
+    cs     = a*b*sinG/Vol;
+    alphas = atan2(sinAS,cosAS)/Conv;
+    betas  = atan2(sinBS,cosBS)/Conv;
+    gammas = atan2(sinGS,cosGS)/Conv;
+
+  // ---- Set useful things for calculating dstar
+
+    AC[0]  = as*as;
+    AC[1]  = bs*bs;
+    AC[2]  = cs*cs;
+    AC[3]  = 2.0*bs*cs*cosAS;
+    AC[4]  = 2.0*cs*as*cosBS;
+    AC[5]  = 2.0*as*bs*cosGS;
+
+  // ---- Zero matrices
+
+    for (k=0;k<6;k++)
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)
+          RR[k][i][j] = 0.0;
+
+  // ---- Calculate matrices
+
+  // ---- XO along a  Zo along c*
+
+    RR[0][0][0] =  a;
+    RR[0][0][1] =  b*cosG;
+    RR[0][0][2] =  c*cosB;
+    RR[0][1][1] =  b*sinG;
+    RR[0][1][2] = -c*sinB*cosAS;
+    RR[0][2][2] =  c*sinB*sinAS;
+
+   // ---- XO along b  Zo along a*
+
+    RR[1][0][0] =  a*cosG;
+    RR[1][0][1] =  b;
+    RR[1][0][2] =  c*cosA;
+    RR[1][1][0] = -a*sinG*cosBS;
+    RR[1][1][2] =  c*sinA;
+    RR[1][2][0] =  a*sinG*sinBS;
+
+  // ---- XO along c  Zo along b*
+
+    RR[2][0][0] =  a*cosB;
+    RR[2][0][1] =  b*cosA;
+    RR[2][0][2] =  c;
+    RR[2][1][0] =  a*sinB;
+    RR[2][1][1] = -b*sinA*cosGS;
+    RR[2][2][1] =  b*sinA*sinGS;
+
+  // ---- trigonal only - XO along a+b  YO alon a-b  Zo along c*
+
+    RR[3][0][0] =  a/2.0;
+    RR[3][0][1] =  a/2.0;
+    RR[3][1][0] = -a*sinG;
+    RR[3][1][1] =  a*sinG;
+    RR[3][2][2] =  c;
+
+  // ---- XO along a*, ZO along c
+
+    RR[4][0][0] =  a*sinB*sinGS;
+    RR[4][1][0] = -a*sinB*cosGS;
+    RR[4][1][1] =  b*sinA;
+    RR[4][2][0] =  a*cosB;
+    RR[4][2][1] =  b*cosA;
+    RR[4][2][2] =  c;
+
+  // ---- Grr*! to  Gerard Bricogne - his setting for P1 in SKEW.
+  //      XO along a, Y0 along b*
+
+    RR[5][0][0] =  a;
+    RR[5][0][1] =  b*cosG;
+    RR[5][0][2] =  c*cosB;
+    RR[5][1][1] =  b*sinG*sinAS;
+    RR[5][2][1] = -b*sinG*cosAS;
+    RR[5][2][2] =  c*sinB;
+
+  }
+
+
+  bool Cryst::areMatrices()  {
+  // returns true if the orthogonal-to-fractional and
+  // fractional-to-orthogonal matrices are defined
+    return (WhatIsSet & CSET_Transforms)!=0x0000;
+  }
+
+
+  bool Cryst::Frac2Orth (
+                realtype x,    realtype y,    realtype z,
+                realtype & xx, realtype & yy, realtype & zz ) {
+    if (areMatrices())  {
+      xx = RO[0][0]*x + RO[0][1]*y + RO[0][2]*z + RO[0][3];
+      yy = RO[1][0]*x + RO[1][1]*y + RO[1][2]*z + RO[1][3];
+      zz = RO[2][0]*x + RO[2][1]*y + RO[2][2]*z + RO[2][3];
+      return true;
+    } else  {
+      xx = x;
+      yy = y;
+      zz = z;
+      return false;
+    }
+  }
+
+  bool Cryst::Orth2Frac (
+                realtype x,    realtype y,    realtype z,
+                realtype & xx, realtype & yy, realtype & zz ) {
+    if (areMatrices())  {
+      xx = RF[0][0]*x + RF[0][1]*y + RF[0][2]*z + RF[0][3];
+      yy = RF[1][0]*x + RF[1][1]*y + RF[1][2]*z + RF[1][3];
+      zz = RF[2][0]*x + RF[2][1]*y + RF[2][2]*z + RF[2][3];
+      return true;
+    } else  {
+      xx = x;
+      yy = y;
+      zz = z;
+      return false;
+    }
+  }
+
+
+  bool Cryst::Frac2Orth ( mat44 & F, mat44 & T )  {
+  mat44 A;
+    if (areMatrices())  {
+      Mat4Mult ( A,F,RF );
+      Mat4Mult ( T,RO,A );
+      return true;
+    } else  {
+      Mat4Init ( T );
+      return false;
+    }
+  }
+
+
+  bool Cryst::Orth2Frac ( mat44 & T, mat44 & F )  {
+  mat44 A;
+    if (areMatrices())  {
+      Mat4Mult ( A,T,RO );
+      Mat4Mult ( F,RF,A );
+      return true;
+    } else  {
+      Mat4Init ( F );
+      return false;
+    }
+  }
+
+
+  int  Cryst::GetNumberOfSymOps()  {
+    return symOps.GetNofSymOps();
+  }
+
+  pstr Cryst::GetSymOp ( int Nop )  {
+    return symOps.GetSymOp ( Nop );
+  }
+
+
+  int  Cryst::GetTMatrix ( mat44 & TMatrix, int Nop,
+                           int cellshift_a, int cellshift_b,
+                           int cellshift_c, PSymOps symOpers )  {
+  //
+  //  GetTMatrix(..) calculates and returns the coordinate transformation
+  //  matrix, which converts orthogonal coordinates according to the
+  //  symmetry operation Nop and places them into unit cell shifted by
+  //  cellshift_a a's, cellshift_b b's and cellshift_c c's.
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+  //
+  mat44 fm;
+  int   i,j,k;
+
+    if (cellshift_a<=-MaxInt4) {
+      k = GetFractMatrix ( fm,Nop,0,0,0,symOpers );
+      fm[0][3] = frac(fm[0][3]);
+      fm[1][3] = frac(fm[1][3]);
+      fm[2][3] = frac(fm[2][3]);
+    } else
+      k = GetFractMatrix ( fm,Nop,cellshift_a,cellshift_b,cellshift_c,
+                           symOpers );
+
+    if (k)  {
+      Mat4Init ( TMatrix );
+      return k;
+    }
+
+    // transformation back to orthogonal coordinates
+    for (i=0;i<3;i++)  {
+      for (j=0;j<4;j++)  {
+        TMatrix[i][j] = 0.0;
+        for (k=0;k<3;k++)
+          TMatrix[i][j] += RO[i][k]*fm[k][j];
+      }
+      TMatrix[i][3] += RO[i][3];
+    }
+
+    TMatrix[3][0] = 0.0;
+    TMatrix[3][1] = 0.0;
+    TMatrix[3][2] = 0.0;
+    TMatrix[3][3] = 1.0;
+
+    return 0;
+
+  }
+
+
+  int  Cryst::GetUCTMatrix ( mat44 & TMatrix, int Nop,
+                                  realtype x, realtype y, realtype z,
+                                  int cellshift_a, int cellshift_b,
+                                  int cellshift_c, PSymOps symOpers )  {
+  //
+  //  GetUCTMatrix(..) calculates and returns the coordinate
+  //  transformation matrix, which converts orthogonal coordinates
+  //  according to the symmetry operation Nop. Translation part of
+  //  the matrix is being chosen such that point (x,y,z) has least
+  //  distance to the center of primary (333) unit cell, and then
+  //  it is shifted by cellshift_a a's, cellshift_b b's and
+  //  cellshift_c c's.
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+  //
+  mat44    fm,tm;
+  vect3    ft;
+  realtype x0,y0,z0, dx,dy,dz, d,d0;
+  int      i,j,k, ic,jc,kc;
+
+    k = GetFractMatrix ( fm,Nop,0,0,0,symOpers );
+    if (k) {
+      Mat4Init ( TMatrix );
+      return k;
+    }
+
+    fm[0][3] = frac(fm[0][3]) + cellshift_a;
+    fm[1][3] = frac(fm[1][3]) + cellshift_b;
+    fm[2][3] = frac(fm[2][3]) + cellshift_c;
+
+    Frac2Orth ( cellshift_a+0.5,cellshift_b+0.5,cellshift_c+0.5,
+                x0,y0,z0 );
+
+    // transformation back to orthogonal coordinates
+
+    for (i=0;i<3;i++)
+      for (j=0;j<3;j++)  {
+        tm[i][j] = 0.0;
+        for (k=0;k<3;k++)
+          tm[i][j] += RO[i][k]*fm[k][j];
+      }
+    tm[3][0] = 0.0;
+    tm[3][1] = 0.0;
+    tm[3][2] = 0.0;
+    tm[3][3] = 1.0;
+
+    d0 = MaxReal;
+    for (ic=-3;ic<3;ic++)
+      for (jc=-3;jc<3;jc++)
+        for (kc=-3;kc<3;kc++)  {
+          ft[0] = fm[0][3] + ic;
+          ft[1] = fm[1][3] + jc;
+          ft[2] = fm[2][3] + kc;
+          for (i=0;i<3;i++)  {
+            tm[i][3] = 0.0;
+            for (k=0;k<3;k++)
+              tm[i][3] += RO[i][k]*ft[k];
+            tm[i][3] += RO[i][3];
+          }
+          dx = tm[0][0]*x + tm[0][1]*y + tm[0][2]*z + tm[0][3] - x0;
+          dy = tm[1][0]*x + tm[1][1]*y + tm[1][2]*z + tm[1][3] - y0;
+          dz = tm[2][0]*x + tm[2][1]*y + tm[2][2]*z + tm[2][3] - z0;
+          d = dx*dx + dy*dy + dz*dz;
+          if (d<d0)  {
+            d0 = d;
+            Mat4Copy ( tm,TMatrix );
+          }
+        }
+
+    return 0;
+
+  }
+
+
+  int  Cryst::GetFractMatrix ( mat44 & TMatrix, int Nop,
+                               int cellshift_a, int cellshift_b,
+                               int cellshift_c,
+                               PSymOps symOpers )  {
+  //
+  //  GetFractMatrix(..) calculates and returns the coordinate
+  //  transformation matrix, which converts fractional coordinates
+  //  according to the symmetry operation Nop and places them into
+  //  unit cell shifted by cellshift_a a's, cellshift_b b's and
+  //  cellshift_c c's.
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+  //
+  mat44 tm;
+  int   i,j,k;
+
+    k = 0;
+    if (symOpers)  k = symOpers->GetTMatrix ( tm,Nop );
+             else  k = symOps.GetTMatrix    ( tm,Nop );
+    if (!k)  {
+      if (!areMatrices())      k = 2;
+      if (!isCellParameters()) k = 3;
+    } else
+      k = 1;
+
+    if (k)  {
+      Mat4Init ( TMatrix );
+      return k;
+    }
+
+    //  transformation to fractional coordinates + symmetry operation
+    for (i=0;i<3;i++)  {
+      for (j=0;j<4;j++)  {
+        TMatrix[i][j] = 0.0;
+        for (k=0;k<3;k++)
+          TMatrix[i][j] += tm[i][k]*RF[k][j];
+      }
+      TMatrix[i][3] += tm[i][3];  // symmetry operation shift
+    }
+
+    // cell shift
+    TMatrix[0][3] += cellshift_a;
+    TMatrix[1][3] += cellshift_b;
+    TMatrix[2][3] += cellshift_c;
+
+    TMatrix[3][0] = 0.0;
+    TMatrix[3][1] = 0.0;
+    TMatrix[3][2] = 0.0;
+    TMatrix[3][3] = 1.0;
+
+    return 0;
+
+  }
+
+  int  Cryst::GetSymOpMatrix ( mat44 & TMatrix, int Nop )  {
+  //
+  //  GetSymOpMatrix(..) returns the transformation matrix for
+  //  Nop-th symmetry operator in the space group
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+  //
+    return symOps.GetTMatrix ( TMatrix,Nop );
+  }
+
+
+  bool Cryst::Cryst2Orth ( rvector U )  {
+  mat33    A,AT,Tmp,TmpMat;
+  realtype BB;
+  int      i,j,k;
+
+    if (areMatrices())  {
+
+      Tmp[0][0] = U[0];
+      Tmp[1][1] = U[1];
+      Tmp[2][2] = U[2];
+      Tmp[0][1] = U[3];
+      Tmp[1][0] = U[3];
+      Tmp[0][2] = U[4];
+      Tmp[2][0] = U[4];
+      Tmp[1][2] = U[5];
+      Tmp[2][1] = U[5];
+
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)  {
+          A [j][i] = ROU[j][i];
+          AT[i][j] = ROU[j][i];
+        }
+
+      //  TmpMat = Tmp*AT
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)  {
+          BB = 0.0;
+          for (k=0;k<3;k++)
+            BB += Tmp[i][k]*AT[k][j];
+          TmpMat[i][j] = BB;
+        }
+
+      //  Tmp = A*TmpMat
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)  {
+          BB = 0.0;
+          for (k=0;k<3;k++)
+            BB += A[i][k]*TmpMat[k][j];
+          Tmp[i][j] = BB;
+        }
+
+      U[0] = Tmp[0][0];
+      U[1] = Tmp[1][1];
+      U[2] = Tmp[2][2];
+      U[3] = Tmp[0][1];
+      U[4] = Tmp[0][2];
+      U[5] = Tmp[1][2];
+
+      return true;
+
+    }
+
+    return false;
+
+  }
+
+
+  bool  Cryst::Orth2Cryst ( rvector U )  {
+  mat33    A,AT,Tmp,TmpMat;
+  realtype BB;
+  int      i,j,k;
+
+    if (areMatrices())  {
+
+      Tmp[0][0] = U[0];
+      Tmp[1][1] = U[1];
+      Tmp[2][2] = U[2];
+      Tmp[0][1] = U[3];
+      Tmp[1][0] = U[3];
+      Tmp[0][2] = U[4];
+      Tmp[2][0] = U[4];
+      Tmp[1][2] = U[5];
+      Tmp[2][1] = U[5];
+
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)  {
+          A [j][i] = RFU[j][i];
+          AT[i][j] = RFU[j][i];
+        }
+
+      //  TmpMat = Tmp*AT
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)  {
+          BB = 0.0;
+          for (k=0;k<3;k++)
+            BB += Tmp[i][k]*AT[k][j];
+          TmpMat[i][j] = BB;
+        }
+
+      //  Tmp = A*TmpMat
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)  {
+          BB = 0.0;
+          for (k=0;k<3;k++)
+            BB += A[i][k]*TmpMat[k][j];
+          Tmp[i][j] = BB;
+        }
+
+      U[0] = Tmp[0][0];
+      U[1] = Tmp[1][1];
+      U[2] = Tmp[2][2];
+      U[3] = Tmp[0][1];
+      U[4] = Tmp[0][2];
+      U[5] = Tmp[1][2];
+
+      return true;
+
+    }
+
+    return false;
+
+  }
+
+
+  void  Cryst::SetCell ( realtype cell_a,
+                              realtype cell_b,
+                              realtype cell_c,
+                              realtype cell_alpha,
+                              realtype cell_beta,
+                              realtype cell_gamma,
+                              int      OrthCode )  {
+  //  this function should be used for changing the cell parameters
+  int  i,j;
+
+    if ((cell_a>0.0)      && (cell_b>0.0)     && (cell_c>0.0) &&
+        (cell_alpha!=0.0) && (cell_beta!=0.0) && (cell_gamma!=0.0))  {
+
+      if (OrthCode>0)  NCode = OrthCode-1;
+                 else  NCode = 0;
+
+      a     = cell_a;
+      b     = cell_b;
+      c     = cell_c;
+      alpha = cell_alpha;
+      beta  = cell_beta;
+      gamma = cell_gamma;
+
+      WhatIsSet |= CSET_CellParams;
+
+      // calculate matrices
+
+      for (i=0;i<4;i++)  {
+        for (j=0;j<4;j++)  {
+          RO [i][j] = 0.0;
+          RF [i][j] = 0.0;
+          ROU[i][j] = 0.0;
+          RFU[i][j] = 0.0;
+        }
+        RO [i][i] = 1.0;
+        RF [i][i] = 1.0;
+        ROU[i][i] = 1.0;
+        RFU[i][i] = 1.0;
+      }
+
+      CalcCoordTransforms();
+
+      if (!(CellCheck & CCHK_NoOrthCode))  {
+        for (i=0;i<3;i++)  {
+          for (j=0;j<3;j++)
+            RO[i][j] = RR[NCode][i][j];
+          RO[i][3] = 0.0;
+          RO[3][i] = 0.0;
+        }
+        RO[3][3] = 1.0;
+        Mat4Inverse ( RO,RF );
+      }
+
+      WhatIsSet |= CSET_Transforms;
+
+    } else
+
+      WhatIsSet &= ~(CSET_CellParams | CSET_Transforms);
+
+  }
+
+  void Cryst::SetSyminfoLib ( cpstr syminfoLib )  {
+    CreateCopy ( syminfo_lib,syminfoLib );
+  }
+
+  pstr Cryst::GetSyminfoLib()  {
+    return syminfo_lib;
+  }
+
+  int Cryst::SetSpaceGroup ( cpstr spGroup )  {
+  //  This function does not attempt to fix the space group
+  int RC,l;
+    RC = SYMOP_UnknownSpaceGroup;
+    WhatIsSet &= ~CSET_SpaceGroup;
+    if (spGroup)  {
+      if (spGroup[0])  {
+        l = IMin ( strlen(spGroup),sizeof(spaceGroup)-1 );
+        strcpy_ncss ( spaceGroup,spGroup,l );
+        strcpy ( spaceGroupFix,spaceGroup );
+        if (spaceGroup[0])  {
+          RC = symOps.SetGroup ( spaceGroup,syminfo_lib );
+      //        RC = SymOps.SetGroup ( spGroup,syminfo_lib );
+          //      strncpy ( spaceGroup,spGroup,l );
+          //      spaceGroup[l] = char(0);
+          if (RC==SYMOP_Ok)  WhatIsSet |= CSET_SpaceGroup;
+        }
+      }
+    }
+    return RC;
+  }
+
+
+  void  Cryst::PutCell ( realtype cell_a,
+                              realtype cell_b,
+                              realtype cell_c,
+                              realtype cell_alpha,
+                              realtype cell_beta,
+                              realtype cell_gamma,
+                              int      OrthCode ) {
+  //  this function should be used for setting the cell parameters
+  int i,j;
+
+    if ((cell_a!=0.0) || (OrthCode>0))  {
+      a     = cell_a;
+      b     = cell_b;
+      c     = cell_c;
+      alpha = cell_alpha;
+      beta  = cell_beta;
+      gamma = cell_gamma;
+      WhatIsSet |= CSET_CellParams;
+    }
+
+    if (OrthCode>0)  {
+
+      // calculate matrices
+
+      NCode = OrthCode-1;
+      CalcOrthMatrices();
+
+      for (i=0;i<3;i++)  {
+        for (j=0;j<3;j++)
+          RO[i][j] = RR[NCode][i][j];
+        RO[i][3] = 0.0;
+        RO[3][i] = 0.0;
+      }
+      RO[3][3] = 1.0;
+
+      Mat4Inverse ( RO,RF );
+
+      WhatIsSet |= CSET_Transforms;
+
+    } else
+      WhatIsSet &= ~CSET_Transforms;
+
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        s[i][j] = RF[i][j];
+      u[i] = RF[i][3];
+    }
+
+    WhatIsSet |= CSET_ScaleMatrix;
+
+  }
+
+
+  bool Cryst::isScaleMatrix()  {
+    return  ((WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix);
+  }
+
+  bool Cryst::isCellParameters()  {
+    return  ((WhatIsSet & CSET_CellParams)==CSET_CellParams);
+  }
+
+  bool Cryst::isNCSMatrix()  {
+    return  (ncsMatrix.Length()>0);
+  }
+
+  int  Cryst::GetNumberOfNCSMatrices()  {
+    return  ncsMatrix.Length();
+  }
+
+  int  Cryst::GetNumberOfNCSMates()  {
+  // Returns the number of NCS mates not given in the file (iGiven==0)
+  int        i,l,iG;
+  PNCSMatrix NCSM;
+    iG = 0;
+    l  = ncsMatrix.Length();
+    for (i=0;i<l;i++)  {
+      NCSM = PNCSMatrix(ncsMatrix.GetContainerClass(i));
+      if (NCSM)  {
+        if (!NCSM->iGiven)  iG++;
+      }
+    }
+    return iG;
+  }
+
+  bool Cryst::GetNCSMatrix ( int NCSMatrixNo,
+                                     mat33 & ncs_m, vect3 & ncs_v )  {
+  int        i,j;
+  PNCSMatrix NCSM;
+    NCSM = PNCSMatrix(ncsMatrix.GetContainerClass(NCSMatrixNo));
+    if (NCSM)  {
+      for (i=0;i<3;i++) {
+        for (j=0;j<3;j++)
+          ncs_m[i][j] = NCSM->m[i][j];
+        ncs_v[i] = NCSM->v[i];
+      }
+      return true;
+    }
+    return false;
+  }
+
+  bool Cryst::GetNCSMatrix ( int NCSMatrixNo,
+                             mat44 & ncs_m, int & iGiven )  {
+  int         i,j;
+  PNCSMatrix NCSM;
+    NCSM = PNCSMatrix(ncsMatrix.GetContainerClass(NCSMatrixNo));
+    if (NCSM)  {
+      for (i=0;i<3;i++) {
+        for (j=0;j<3;j++)
+          ncs_m[i][j] = NCSM->m[i][j];
+        ncs_m[i][3] = NCSM->v[i];
+      }
+      ncs_m[3][0] = 0.0;
+      ncs_m[3][1] = 0.0;
+      ncs_m[3][2] = 0.0;
+      ncs_m[3][3] = 1.0;
+      iGiven = NCSM->iGiven;
+      return true;
+    } else  {
+      for (i=0;i<4;i++) {
+        for (j=0;j<4;j++)
+          ncs_m[i][j] = 0.0;
+        ncs_m[i][i] = 1.0;
+      }
+      return false;
+    }
+  }
+
+  int  Cryst::AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v,
+                             int iGiven )  {
+  PNCSMatrix ncsMtx;
+    ncsMtx = new NCSMatrix();
+    ncsMtx->SetNCSMatrix ( ncsMatrix.Length()+1,ncs_m,ncs_v,iGiven );
+    ncsMatrix.AddData ( ncsMtx );
+    return ncsMtx->serNum;
+  }
+
+  void  Cryst::GetRCell ( realtype & cell_as,
+                          realtype & cell_bs,
+                          realtype & cell_cs,
+                          realtype & cell_alphas,
+                          realtype & cell_betas,
+                          realtype & cell_gammas,
+                          realtype & vols )  {
+    cell_as     = as;
+    cell_bs     = bs;
+    cell_cs     = cs;
+    cell_alphas = alphas;
+    cell_betas  = betas;
+    cell_gammas = gammas;
+    if (Vol!=0.0)  vols = 1.0/Vol;
+             else  vols = 0.0;
+  }
+
+  void  Cryst::GetCell ( realtype & cell_a,
+                              realtype & cell_b,
+                              realtype & cell_c,
+                              realtype & cell_alpha,
+                              realtype & cell_beta,
+                              realtype & cell_gamma,
+                              realtype & vol )  {
+    if (WhatIsSet & CSET_CellParams)  {
+      cell_a     = a;
+      cell_b     = b;
+      cell_c     = c;
+      cell_alpha = alpha;
+      cell_beta  = beta;
+      cell_gamma = gamma;
+      vol        = Vol;
+    } else  {
+      cell_a     = 0.0;
+      cell_b     = 0.0;
+      cell_c     = 0.0;
+      cell_alpha = 0.0;
+      cell_beta  = 0.0;
+      cell_gamma = 0.0;
+      vol        = 0.0;
+    }
+  }
+
+  pstr Cryst::GetSpaceGroup()  {
+    if (WhatIsSet & CSET_SpaceGroup)  return spaceGroup;
+                                else  return NULL;
+  }
+
+  pstr Cryst::GetSpaceGroupFix()  {
+    if (WhatIsSet & CSET_SpaceGroup)  return spaceGroupFix;
+                                else  return NULL;
+  }
+
+
+  void  Cryst::Copy ( PCryst Cryst )  {
+  int i,j,k;
+
+    if (Cryst)  {
+
+      a     = Cryst->a;
+      b     = Cryst->b;
+      c     = Cryst->c;
+      alpha = Cryst->alpha;
+      beta  = Cryst->beta;
+      gamma = Cryst->gamma;
+
+      for (i=0;i<4;i++)
+        for (j=0;j<4;j++)  {
+          RO [i][j] = Cryst->RO [i][j];
+          RF [i][j] = Cryst->RF [i][j];
+          ROU[i][j] = Cryst->ROU[i][j];
+          RFU[i][j] = Cryst->RFU[i][j];
+        }
+
+      for (i=0;i<3;i++) {
+        for (j=0;j<3;j++)  {
+          o[i][j] = Cryst->o[i][j];
+          s[i][j] = Cryst->s[i][j];
+          for (k=0;k<6;k++)
+            RR[k][i][j] = Cryst->RR[k][i][j];
+        }
+        t[i] = Cryst->t[i];
+        u[i] = Cryst->u[i];
+      }
+
+      Vol       = Cryst->Vol;
+      NCode     = Cryst->NCode;
+      Z         = Cryst->Z;
+      CellCheck = Cryst->CellCheck;
+      WhatIsSet = Cryst->WhatIsSet;
+      strcpy ( spaceGroup   ,Cryst->spaceGroup    );
+      strcpy ( spaceGroupFix,Cryst->spaceGroupFix );
+
+      ncsMatrix.Copy ( &(Cryst->ncsMatrix) );
+      tVect    .Copy ( &(Cryst->tVect)     );
+      symOps   .Copy ( &(Cryst->symOps)    );
+
+      as     = Cryst->as;
+      bs     = Cryst->bs;
+      cs     = Cryst->cs;
+      alphas = Cryst->alphas;
+      betas  = Cryst->betas;
+      gammas = Cryst->betas;
+      VolChk = Cryst->VolChk;
+      VolErr = Cryst->VolErr;
+
+      for (k=0;k<6;k++)
+        AC[k] = Cryst->AC[k];
+
+    } else  {
+
+      ncsMatrix.FreeContainer();
+      tVect    .FreeContainer();
+      WhatIsSet = 0;
+
+    }
+
+  }
+
+
+  void  Cryst::write ( io::RFile f )  {
+  int  i,j,k;
+  byte Version=3;
+
+    f.WriteByte ( &Version   );
+    f.WriteWord ( &WhatIsSet );
+    f.WriteReal ( &a         );
+    f.WriteReal ( &b         );
+    f.WriteReal ( &c         );
+    f.WriteReal ( &alpha     );
+    f.WriteReal ( &beta      );
+    f.WriteReal ( &gamma     );
+    f.WriteWord ( &CellCheck );
+    f.WriteBool ( &ignoreScalei );
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)  {
+        f.WriteReal ( &(RO [i][j]) );
+        f.WriteReal ( &(RF [i][j]) );
+        f.WriteReal ( &(ROU[i][j]) );
+        f.WriteReal ( &(RFU[i][j]) );
+      }
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)  {
+        f.WriteReal ( &(o[i][j]) );
+        f.WriteReal ( &(s[i][j]) );
+        for (k=0;k<6;k++)
+          f.WriteReal ( &(RR[k][i][j]) );
+      }
+      f.WriteReal ( &(t[i]) );
+      f.WriteReal ( &(u[i]) );
+    }
+    f.WriteReal ( &Vol    );
+    f.WriteReal ( &VolChk );
+    f.WriteReal ( &VolErr );
+    f.WriteInt  ( &NCode  );
+    f.WriteInt  ( &Z      );
+    f.WriteTerLine ( spaceGroup   ,false );
+    f.WriteTerLine ( spaceGroupFix,false );
+
+    for (i=0;i<6;i++)
+      f.WriteReal ( &(AC[6]) );
+    f.WriteReal ( &as     );
+    f.WriteReal ( &bs     );
+    f.WriteReal ( &cs     );
+    f.WriteReal ( &alphas );
+    f.WriteReal ( &betas  );
+    f.WriteReal ( &gammas );
+
+    ncsMatrix.write ( f );
+    tVect    .write ( f );
+    symOps   .write ( f );
+
+  }
+
+  void  Cryst::read ( io::RFile f )  {
+  int  i,j,k;
+  byte Version;
+
+    f.ReadByte ( &Version   );
+    f.ReadWord ( &WhatIsSet );
+    f.ReadReal ( &a         );
+    f.ReadReal ( &b         );
+    f.ReadReal ( &c         );
+    f.ReadReal ( &alpha     );
+    f.ReadReal ( &beta      );
+    f.ReadReal ( &gamma     );
+    f.ReadWord ( &CellCheck );
+    if (Version>2)
+      f.ReadBool ( &ignoreScalei );
+    else  ignoreScalei = false;
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)  {
+        f.ReadReal ( &(RO [i][j]) );
+        f.ReadReal ( &(RF [i][j]) );
+        f.ReadReal ( &(ROU[i][j]) );
+        f.ReadReal ( &(RFU[i][j]) );
+      }
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)  {
+        f.ReadReal ( &(o[i][j]) );
+        f.ReadReal ( &(s[i][j]) );
+        for (k=0;k<6;k++)
+          f.ReadReal ( &(RR[k][i][j]) );
+      }
+      f.ReadReal ( &(t[i]) );
+      f.ReadReal ( &(u[i]) );
+    }
+    f.ReadReal ( &Vol    );
+    f.ReadReal ( &VolChk );
+    f.ReadReal ( &VolErr );
+    f.ReadInt  ( &NCode  );
+    f.ReadInt  ( &Z      );
+    f.ReadTerLine ( spaceGroup,false );
+    if (Version>1)
+          f.ReadTerLine ( spaceGroupFix,false );
+    else  strcpy ( spaceGroupFix,spaceGroup );
+
+    for (i=0;i<6;i++)
+      f.ReadReal ( &(AC[6]) );
+    f.ReadReal ( &as     );
+    f.ReadReal ( &bs     );
+    f.ReadReal ( &cs     );
+    f.ReadReal ( &alphas );
+    f.ReadReal ( &betas  );
+    f.ReadReal ( &gammas );
+
+    ncsMatrix.read ( f );
+    tVect    .read ( f );
+    symOps   .read ( f );
+
+  }
+
+  MakeStreamFunctions(Cryst)
+
+
+  // ===================================================================
+
+
+  void  TestCryst() {
+  //  reads from 'in.cryst', writes into
+  //  'out.cryst' and 'abin.cryst'
+  io::File   f;
+  char       S[81];
+  PCryst     cryst;
+
+    cryst = new Cryst();
+
+    f.assign ( pstr("in.cryst"),true );
+    if (f.reset()) {
+      while (!f.FileEnd()) {
+        f.ReadLine ( S,sizeof(S) );
+        cryst->ConvertPDBString ( S );
+      }
+      f.shut();
+    } else {
+      printf ( " Can't open input file 'in.chain' \n" );
+      delete cryst;
+      return;
+    }
+
+    f.assign ( pstr("out.cryst"),true );
+    if (f.rewrite()) {
+      cryst->PDBASCIIDump ( f );
+      f.shut();
+    } else {
+      printf ( " Can't open output file 'out.cryst' \n" );
+      delete cryst;
+      return;
+    }
+
+
+    f.assign ( pstr("mmdb.cryst.bin"),false );
+    if (f.rewrite()) {
+      cryst->write ( f );
+      f.shut();
+    } else {
+      printf ( "  Can't open binary cryst file for writing.\n" );
+      delete cryst;
+      return;
+    }
+
+    delete cryst;
+    printf ( "   Cryst deleted.\n" );
+
+    cryst = new Cryst();
+    if (f.reset()) {
+      cryst->read ( f );
+      f.shut();
+    } else {
+      printf ( "  Can't open binary cryst file for reading.\n" );
+      delete cryst;
+      return;
+    }
+
+    f.assign ( pstr("abin.cryst"),true );
+    if (f.rewrite()) {
+      cryst->PDBASCIIDump ( f );
+      f.shut();
+    } else
+      printf ( " Can't open output file 'abin.cryst' \n" );
+
+    delete cryst;
+
+  }
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_cryst.h b/mmdb2/mmdb_cryst.h
new file mode 100644
index 0000000..4ca4150
--- /dev/null
+++ b/mmdb2/mmdb_cryst.h
@@ -0,0 +1,458 @@
+//  $Id: mmdb_cryst.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Cryst <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::CrystContainer ( container for cryst. data )
+//       ~~~~~~~~~  mmdb::NCSMatrix  ( non-cryst. symm. matrix class )
+//                  mmdb::TVect      ( translation vector class      )
+//                  mmdb::Cryst      ( MMDB cryst. section class     )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Cryst__
+#define __MMDB_Cryst__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_symop.h"
+#include "mmdb_defs.h"
+#include "mmdb_utils.h"
+
+namespace mmdb  {
+
+  //  ====================  CrystContainer  ======================
+
+  DefineClass(CrystContainer);
+  DefineStreamFunctions(CrystContainer);
+
+  class CrystContainer : public ClassContainer  {
+
+    public :
+
+      CrystContainer () : ClassContainer() {}
+      CrystContainer ( io::RPStream Object )
+                        : ClassContainer ( Object ) {}
+      ~CrystContainer() {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+      ERROR_CODE AddMTRIXLine ( cpstr S );
+
+  };
+
+
+  //  ==================  NCSMatrix  ========================
+
+  enum NCSM_SET  {
+    NCSMSET_Matrix1 = 0x00000001,
+    NCSMSET_Matrix2 = 0x00000002,
+    NCSMSET_Matrix3 = 0x00000004,
+    NCSMSET_All     = 0x00000007
+  };
+
+  DefineClass(NCSMatrix);
+  DefineStreamFunctions(NCSMatrix);
+
+  class NCSMatrix : public ContainerClass  {
+
+    friend class Cryst;
+
+    public :
+
+      int   serNum;   // serial number
+      mat33 m;        // non-crystallographic symmetry matrix
+      vect3 v;        // translational part of ncs matrix
+      int   iGiven;   // iGiven flag (see PDB format)
+
+      NCSMatrix ();
+      NCSMatrix ( cpstr S );
+      NCSMatrix ( io::RPStream Object );
+      ~NCSMatrix();
+
+      bool       PDBASCIIDump1   ( io::RFile f );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_NCSMatrix; }
+
+      void  SetNCSMatrix    ( int serialNum,
+                              mat33 & ncs_m, vect3 & ncs_v,
+                              int i_Given );
+
+      void  Copy  ( PContainerClass NCSMatrix );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      word  WhatIsSet;  //    mask       field
+                        //   0x0001    MTRIX1 was converted
+                        //   0x0002    MTRIX2 was converted
+                        //   0x0004    MTRIX3 was converted
+
+      void  Init();
+
+  };
+
+
+  //  ==================  TVect  ========================
+
+  DefineClass(TVect);
+  DefineStreamFunctions(TVect);
+
+  class TVect : public ContainerClass  {
+
+    public :
+
+      int   serNum;   // serial number
+      vect3 t;        // translation vector
+      pstr  comment;  // comment
+
+      TVect ();
+      TVect ( cpstr S );
+      TVect ( io::RPStream Object );
+      ~TVect();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_TVect; }
+
+      void  Copy  ( PContainerClass TVect );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void  Init();
+
+  };
+
+
+  //  =================  Cryst  =======================
+
+  DefineClass(Cryst);
+  DefineStreamFunctions(Cryst);
+
+  // constants for the CellCheck field
+  enum CELL_CHECK  {
+    CCHK_Ok           = 0x00000000,
+    CCHK_NoCell       = 0x00000001,
+    CCHK_Error        = 0x00000002,
+    CCHK_Disagreement = 0x00000004,
+    CCHK_NoOrthCode   = 0x00000008,
+    CCHK_Translations = 0x00000010,
+    CCHK_Unchecked    = 0x00001000
+  };
+
+  // constants for the WhatIsSet field
+  enum CELL_SET  {
+    CSET_CellParams1  = 0x00000001,
+    CSET_CellParams2  = 0x00000002,
+    CSET_CellParams   = 0x00000003,
+    CSET_SpaceGroup   = 0x00000004,
+    CSET_ZValue       = 0x00000008,
+    CSET_CrystCard    = 0x0000000F,
+    CSET_OrigMatrix1  = 0x00000010,
+    CSET_OrigMatrix2  = 0x00000020,
+    CSET_OrigMatrix3  = 0x00000040,
+    CSET_OrigMatrix   = 0x00000070,
+    CSET_ScaleMatrix1 = 0x00000080,
+    CSET_ScaleMatrix2 = 0x00000100,
+    CSET_ScaleMatrix3 = 0x00000200,
+    CSET_ScaleMatrix  = 0x00000380,
+    CSET_Transforms   = 0x00000400,
+    CSET_DummyCell    = 0x00001000
+  };
+
+  extern cpstr OrthCode[6];
+
+  class Cryst : public io::Stream  {
+
+    friend class Channel;
+
+    public :
+      realtype  a,b,c;            // cell parameters
+      realtype  alpha,beta,gamma; // cell parameters
+      mat44     RO,RF;            // orthogonal-fractional recalculation
+                                  //   matrices
+      mat44     ROU,RFU;          // ort-frac recalc matrices for
+                                  //   anisotr. t-fac
+      mat633    RR;               // standard orthogonalizations
+      realtype  Vol;              // cell volume
+      int       NCode;            // code of orthogonalization matrix
+      SymGroup  spaceGroup;       // group of space symmetry as read
+                                  //    from file
+      SymGroup  spaceGroupFix;    // actually used space group
+      int       Z;                // Z-value
+
+      mat33     o;                // orthogonal transformation matrix
+      vect3     t;                // translation orthogonal vector
+      mat33     s;                // scale matrix
+      vect3     u;                // translation part of the scale matrix
+
+      word      CellCheck;        // 0x0000 - Ok
+                                  // 0x0001 - no cell stored
+                                  // 0x0002 - some error in cell volume
+                                  // 0x0004 - disagreement between
+                                  //           cell and PDB
+                                  // 0x0008 - no orth code derived
+                                  // 0x0010 - translations also specified
+                                  // 0x1000 - the check was not done
+      word   WhatIsSet;           // indicator of the fields set
+      bool   ignoreScalei;        // flag to ignore SCALEi cards
+      bool   processSG;           // flag to process space group at file
+                                  // read
+      bool   fixSpaceGroup;       // flag to fix space group at file read
+
+      Cryst ();
+      Cryst ( io::RPStream Object );
+      ~Cryst();
+
+      void  FreeMemory();
+      void  Reset     ();
+
+      //   ConvertPDBString(..) interprets an ASCII PDB line and fills
+      // the corresponding data fields. It returns zero if the line was
+      // successfully converted, otherwise returns a non-negative value
+      // of Error_XXXX.
+      //   PDBString must be not shorter than 81 characters.
+      ERROR_CODE ConvertPDBString ( pstr PDBString );
+
+      //   RWBROOKReadPrintout() may be invoked after reading PDB file
+      // for simulating the old RWBROOK messages and warnings
+      void  RWBROOKReadPrintout();
+
+      void  SetCell ( realtype cell_a,
+                      realtype cell_b,
+                      realtype cell_c,
+                      realtype cell_alpha,
+                      realtype cell_beta,
+                      realtype cell_gamma,
+                      int      OrthCode );
+      void  PutCell ( realtype cell_a,
+                      realtype cell_b,
+                      realtype cell_c,
+                      realtype cell_alpha,
+                      realtype cell_beta,
+                      realtype cell_gamma,
+                      int      OrthCode );
+
+      void  GetCell ( realtype & cell_a,
+                      realtype & cell_b,
+                      realtype & cell_c,
+                      realtype & cell_alpha,
+                      realtype & cell_beta,
+                      realtype & cell_gamma,
+                      realtype & vol );
+
+      void  GetRCell ( realtype & cell_as,
+                       realtype & cell_bs,
+                       realtype & cell_cs,
+                       realtype & cell_alphas,
+                       realtype & cell_betas,
+                       realtype & cell_gammas,
+                       realtype & vols );
+
+      void  SetSyminfoLib ( cpstr syminfoLib );
+      pstr  GetSyminfoLib ();
+
+      int   SetSpaceGroup ( cpstr spGroup );
+      pstr  GetSpaceGroup ();
+      pstr  GetSpaceGroupFix();
+
+      //   CalcCoordTransforms() should be called once after all data
+      // relevant to the crystallographic information, are read and
+      // converted. Field CellCheck will then have bits set if there
+      // are errors, e.g. bit CCHK_NoCell means that the coordinate
+      // transformations cannot be performed.
+      void  CalcCoordTransforms();
+
+      // A PDB ASCII dump
+      void  PDBASCIIDump ( io::RFile f );
+
+      ERROR_CODE GetCIF  ( mmcif::PData CIF );
+      void  MakeCIF ( mmcif::PData CIF );
+
+      bool areMatrices();  // returns True if the orthogonal-to-
+                              // fractional and fractional-to-orthogonal
+                              // matrices are defined
+
+      //   Frac2Orth(..) and Orth2Frac(..) transform between fractional
+      // and orthogonal coordinates, if areMatrices() returns True.
+      // If the transformation matrices were not set, the functions just
+      // copy the coordinates.  Returns True if the transformation was
+      // done; False return means that transformation matrices were not
+      // calculated
+      bool Frac2Orth (
+                realtype x,    realtype y,    realtype z,
+                realtype & xx, realtype & yy, realtype & zz );
+      bool Orth2Frac (
+                realtype x,    realtype y,    realtype z,
+                realtype & xx, realtype & yy, realtype & zz );
+
+      //   Below, F and T are transformation matrices in fractional and
+      // orthogonal coordinates, respectively.
+      bool Frac2Orth ( mat44 & F, mat44 & T );
+      bool Orth2Frac ( mat44 & T, mat44 & F );
+
+
+      //   Cryst2Orth(..) and Orth2Cryst(..) transform between fractional
+      // and orthogonal anisotropic temperature factors, if areMatrices()
+      // returns True. If the transformation matrices were not set, the
+      // functions leave the factors unchanged.
+      //   Vector U is composed as follows:
+      //      U[0]=u11   U[1]=u22   U[2]=u33
+      //      U[3]=u12   U[4]=u13   U[5]=u23
+      // Returns True if the transformation was done; False retuen
+      // means that transformation matrices were not calculated
+      bool  Cryst2Orth ( rvector U );
+      bool  Orth2Cryst ( rvector U );
+
+      void  CalcOrthMatrices();  // calculates RR, AC, cella's and Vol
+
+      bool  isNCSMatrix     ();
+      bool  isScaleMatrix   ();
+      bool  isCellParameters();
+
+      int   GetNumberOfSymOps();
+      pstr  GetSymOp ( int Nop );
+
+      int   GetNumberOfNCSMatrices();
+      int   GetNumberOfNCSMates   ();  // Returns the number of
+                                       // NCS mates not given in
+                                       // the file (iGiven==0)
+
+      bool  GetNCSMatrix ( int NCSMatrixNo, mat33 & ncs_m,
+                           vect3 & ncs_v );
+      bool  GetNCSMatrix ( int NCSMatrixNo, mat44 & ncs_m,
+                           int & iGiven ); // no=0..N-1
+      int   AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v, int iGiven );
+
+      //  GetTMatrix(..) calculates and returns the coordinate
+      //  transformation matrix, which converts orthogonal coordinates
+      //  according to the symmetry operation number Nop and places
+      //  them into unit cell shifted by cellshift_a a's, cellshift_b
+      //  b's and cellshift_c c's.
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      int   GetTMatrix ( mat44 & TMatrix, int Nop,
+                         int cellshift_a, int cellshift_b,
+                         int cellshift_c, PSymOps symOpers=NULL );
+
+      //  GetUCTMatrix(..) calculates and returns the coordinate
+      //  transformation matrix, which converts orthogonal coordinates
+      //  according to the symmetry operation Nop. Translation part
+      //  of the matrix is  being chosen such that point (x,y,z) has
+      //  least distance to the center of primary (333) unit cell,
+      //  and then it is shifted by cellshift_a a's, cellshift_b b's
+      //  and cellshift_c c's.
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      //
+      int   GetUCTMatrix ( mat44 & TMatrix, int Nop,
+                           realtype x, realtype y, realtype z,
+                           int cellshift_a, int cellshift_b,
+                           int cellshift_c, PSymOps symOpers=NULL );
+
+      //  GetFractMatrix(..) calculates and returns the coordinate
+      //  transformation matrix, which converts fractional coordinates
+      //  according to the symmetry operation number Nop and places them
+      //  into unit cell shifted by cellshift_a a's, cellshift_b b's and
+      //  cellshift_c c's.
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      int   GetFractMatrix ( mat44 & TMatrix, int Nop,
+                             int cellshift_a, int cellshift_b,
+                             int cellshift_c, PSymOps symOpers=NULL );
+
+      //  GetSymOpMatrix(..) returns the transformation matrix for
+      //  Nop-th symmetry operator in the space group
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      //
+      int   GetSymOpMatrix ( mat44 & TMatrix, int Nop );
+
+      void  Copy  ( PCryst Cryst );
+
+      void  write ( io::RFile f );    // writes header to PDB binary file
+      void  read  ( io::RFile f );    // reads header from PDB binary file
+
+    protected :
+
+      CrystContainer ncsMatrix;      // non-cryst. symm. matrices
+      CrystContainer tVect;          // translation vectors
+
+      realtype  as,bs,cs;             // calculated 'cell parameters'
+      realtype  alphas,betas,gammas;  // calculated 'cell parameters'
+      realtype  AC[6];
+      realtype  VolChk,VolErr;
+
+      pstr      syminfo_lib;          // path to syminfo.lib
+      SymOps    symOps;               // symmetry operations
+
+      void  Init ( bool fullInit );
+      int   FixSpaceGroup();
+
+  };
+
+  extern cpstr getOrthCodeName ( int NCode );
+
+}  // namespace mmdb
+
+/*
+extern void  TestCryst();  //  reads from 'in.cryst', writes into
+                           //  'out.cryst' and 'abin.cryst'
+*/
+
+
+#endif
+
diff --git a/mmdb2/mmdb_defs.h b/mmdb2/mmdb_defs.h
new file mode 100644
index 0000000..da06dac
--- /dev/null
+++ b/mmdb2/mmdb_defs.h
@@ -0,0 +1,271 @@
+//  $Id: mmdb_defs.h,v 1.27 2012/01/26 17:52:20 ekr Exp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    10.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_Defs <interface>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//      Definition of types, constants and important classes.
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Defs__
+#define __MMDB_Defs__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  enum  MMDB_VERSION  {
+    MAJOR_VERSION = 2,  //!< MMDB major version
+    MINOR_VERSION = 0,  //!< MMDB minor version
+    MICRO_VERSION = 1   //!< MMDB micro version
+  };
+
+  //  =======================  types  =================================
+
+  typedef  char         IDCode  [16];   //!< ID code of PDB entry
+  typedef  IDCode *     PIDCode;        //!< pointer to ID code
+  typedef  PIDCode &    RPIDCode;       //!< ref. to pointer to ID code
+  typedef  char         Date    [12];   //!< date DD-MMM-YYYY
+  typedef  char         RecName [7];    //!< name of PDB record
+
+  typedef  char         ChainID [10];   //!< chain ID
+  typedef  ChainID *    PChainID;       //!< pointer to chain ID
+  typedef  char         InsCode [10];   //!< insertion code
+  typedef  char         DBName  [10];   //!< sequence database name
+  typedef  char         DBAcCode[20];   //!< seq. database accession code
+  typedef  DBAcCode *   PDBAcCode;      //!< pointer to seq. db acc code
+  typedef  char         DBIdCode[20];   //!< seq. database ident-n code
+  typedef  DBIdCode *   PDBIdCode;      //!< pointer to DBIdCode
+  typedef  char         ResName [20];   //!< residue name
+  typedef  ResName  *   PResName;       //!< pointer to residue name
+  typedef  PResName *   PPResName;      //!< ptr to vector of residue names
+  typedef  char         HelixID [20];   //!< helix ID
+  typedef  char         StrandID[20];   //!< strand ID
+  typedef  char         SheetID [20];   //!< sheet ID
+  typedef  char         TurnID  [20];   //!< turn ID
+  typedef  char         LinkRID [20];   //!< Refmac link ID
+
+  typedef  char         SymGroup[100];  //!< group of space symmetry
+  typedef  realtype     vect3   [3];    //!< vector of 3 real numbers
+  typedef  vect3    *   pvect3;         //!< ptr to vector 3
+  typedef  pvect3   &   rpvect3;        //!< ref to ptr to vector 3
+  typedef  realtype     vect4   [4];    //!< vector of 4 real numbers
+  typedef  vect3        mat33   [3];    //!< matrix 3x3 of real numbers
+
+  typedef  vect4        mat44   [4];    //!< matrix 4x4 of real numbers
+  typedef  mat44    *   pmat44;         //!< ptr to matrix 4x4
+  typedef  mat44    &   rmat44;         //!< ref to matrix 4x4
+  typedef  pmat44   *   ppmat44;        //!< ptr to ptr to matrix 4x4
+  typedef  pmat44   &   rpmat44;        //!< ref to ptr to matrix 4x4
+  typedef  mat33        mat633  [6];    //!< matrix 6x3x3 of real numbers
+
+  typedef  char         AtomName[20];   //!< name of the atom
+  typedef  AtomName *   PAtomName;      //!< pointer to atom name
+  typedef  char         AltLoc  [20];   //!< alternate location indicator
+  typedef  AltLoc   *   PAltLoc;        //!< pointer to alt loc indicator
+  typedef  char         SegID   [20];   //!< segment identifier
+  typedef  char         Element [10];   //!< chemical element name
+  typedef  Element  *   PElement;       //!< ptr to chemical element name
+  typedef  char         EnergyType[10]; //!< energy type name
+  typedef  EnergyType * PEnergyType;    //!< pointer to energy type name
+
+  // do not forget update this when change the above typedefs:
+  typedef  char  maxMMDBName[40];
+
+
+  //  =====================  constants  ===============================
+
+  //   ANY_RES should be used in selection functions for specifying
+  // "any residue" to select. Defined in mmdb_selmngr.cpp
+  extern const int ANY_RES;
+
+  //    PRNK_XXXXX are the print keys. PRNK_Silent supresses all print
+  // inside mmdb_xxxx unless specifically ordered or catastrophic.
+  // PRNK_SimRWBROOK instructs mmdb to issue, whenever possible and
+  // necessary, printouts and warnings of RWBROOK (fortran) package.
+  enum PRINT_KEY  {
+    PRNK_Silent      = 0,
+    PRNK_SimRWBROOK  = 1
+  };
+
+  //  Error_XXXX may be returned by XX::ConvertPDBString() and GetCIF(..)
+  // functions.
+  //  Error_WrongSection is returned if the string passed into function
+  // does not belong to the corresponding PDB section.
+
+
+  enum ERROR_CODE  {
+
+    Error_EmptyCIF     =-1,  //!< used as signal at reading CIF files
+
+    Error_NoError      = 0,
+    Error_Ok           = 0,
+    Error_WrongSection = 1,
+    Error_WrongChainID = 2,
+    Error_WrongEntryID = 3,
+
+    //  Error_SEQRES_serNum is returned by CSeqRes::ConvertPDBASCII() if
+    //  serial numbers of SEQRES records do not increment by 1
+    Error_SEQRES_serNum = 4,
+
+    //  Error_SEQRES_numRes is returned by CSeqRes::ConvertPDBASCII() if
+    //  SEQRES records show different number of residues
+    Error_SEQRES_numRes = 5,
+
+    //  Error_SEQRES_extraRes is returned by CSeqRes::ConvertPDBASCII() if
+    //  SEQRES contains more residues than specified
+    Error_SEQRES_extraRes = 6,
+
+    Error_NCSM_Unrecognized   = 7,
+    Error_NCSM_AlreadySet     = 8,
+    Error_NCSM_WrongSerial    = 9,
+    Error_NCSM_UnmatchIG      = 10,
+
+    Error_ATOM_Unrecognized   = 11,
+    Error_ATOM_AlreadySet     = 12,
+    Error_ATOM_NoResidue      = 13,
+    Error_ATOM_Unmatch        = 14,
+
+    Error_CantOpenFile        = 15,
+    Error_UnrecognizedInteger = 16,
+    Error_WrongModelNo        = 17,
+    Error_DuplicatedModel     = 18,
+    Error_NoModel             = 19,
+    Error_ForeignFile         = 20,
+    Error_WrongEdition        = 21,
+
+    //  CIF specific
+    Error_NotACIFFile         = 22,
+    Error_NoData              = 23,
+    Error_NoLoop              = 24,
+    Error_NoStruct            = 25,
+    Error_UnrecognCIFItems    = 26,
+    Error_MissingCIFField     = 27,
+    Error_EmptyCIFLoop        = 28,
+    Error_EmptyCIFStruct      = 29,
+    Error_UnexpEndOfCIF       = 30,
+    Error_MissgCIFLoopField   = 31,
+    Error_NotACIFStructure    = 32,
+    Error_NotACIFLoop         = 33,
+    Error_UnrecognizedReal    = 34,
+
+    Error_NoSheetID           = 35,
+    Error_WrongSheetID        = 36,
+    Error_WrongStrandNo       = 37,
+
+    //   Error_WrongNumberOfStrands may be issued when reading
+    // sheet data from CIF
+    Error_WrongNumberOfStrands = 38,
+
+    //   Error_WrongSheetOrder may be issued when reading
+    // sheet data from CIF
+    Error_WrongSheetOrder      = 39,
+
+    //   Error_HBondInconsistency may be issued when reading
+    // sheet data from CIF
+    Error_HBondInconsistency   = 40,
+
+    //   Error_EmptyResidueName is issued when PDB ATOM record
+    // does not have a residue name
+    Error_EmptyResidueName     = 41,
+
+    //   Error_DuplicateSeqNum is issued when PDB ATOM records
+    // show the sequence number and insertion code assigned
+    // to more than one residue name
+    Error_DuplicateSeqNum      = 42,
+
+    //   Error_NoLogicalName may be returned by file i/o functions
+    // if the specified environmental variable for file name
+    // is not found.
+    Error_NoLogicalName        = 43,
+
+    //   Error_EmptyFile may be returned at reading non-existing
+    // coordinate files
+    Error_EmptyFile            = 44,
+
+    Error_Unknown              = 45,
+
+    //   Error_CIF_EmptyRow is the event of encountering
+    // an empty row in _atom_site loop. It is handled
+    // internally and has no effect on API
+    Error_CIF_EmptyRow      = 99999,
+
+    Error_GeneralError1     = 10000
+
+  };
+
+  //  ClassID_XXXX are used by container classes for proper
+  // creating containered classes when reading from binary file.
+
+  enum CLASS_ID {
+    ClassID_Template   ,
+    ClassID_String     ,
+    ClassID_ObsLine    ,
+    ClassID_TitleLine  ,
+    ClassID_CAVEAT     ,
+    ClassID_Compound   ,
+    ClassID_Source     ,
+    ClassID_ExpData    ,
+    ClassID_MdlType    ,
+    ClassID_Author     ,
+    ClassID_RevData    ,
+    ClassID_Supersede  ,
+    ClassID_Journal    ,
+    ClassID_Remark     ,
+    ClassID_DBReference,
+    ClassID_SeqAdv     ,
+    ClassID_ModRes     ,
+    ClassID_Het        ,
+    ClassID_NCSMatrix  ,
+    ClassID_TVect      ,
+    ClassID_Helix      ,
+    ClassID_Turn       ,
+    ClassID_Link       ,
+    ClassID_LinkR      ,
+    ClassID_CisPep
+  };
+
+
+  //  =====================  classes  ===============================
+
+  DefineClass(Atom);
+  DefineClass(Residue);
+  DefineClass(Chain);
+  DefineClass(Model);
+  DefineClass(Manager);
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb/mmdb_ficif.cpp b/mmdb2/mmdb_ficif.cpp
old mode 100755
new mode 100644
similarity index 93%
rename from mmdb/mmdb_ficif.cpp
rename to mmdb2/mmdb_ficif.cpp
index d57c94a..e7892d5
--- a/mmdb/mmdb_ficif.cpp
+++ b/mmdb2/mmdb_ficif.cpp
@@ -6,13 +6,13 @@
 //
 //   Copyright (C) Eugene Krissinel 2000-2008.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -29,27 +29,22 @@
 //  **** Module  :  MMDB_FICIF  <implementation>
 //       ~~~~~~~~~
 //  **** Project :  MacroMolecular Data Base (MMDB)
-//       ~~~~~~~~~ 
-//  **** Classes :  
-//       ~~~~~~~~~  
+//       ~~~~~~~~~
+//  **** Classes :
+//       ~~~~~~~~~
 //
 //  (C) E. Krissinel 2000-2008
 //
 //  =================================================================
 //
 
-#ifndef  __MMDB_MMCIF__
-#include "mmdb_mmcif.h"
-#endif
-
-#ifndef  __MMDB_FICIF__
+#include "mmdb_mmcif_.h"
 #include "mmdb_ficif.h"
-#endif
 
 
 //  ==================================================================
 
-PCMMCIFData mmCIFData = NULL;
+mmcif::PData mmCIFData = NULL;
 
 
 FORTRAN_SUBR ( MMDB_FCIF_INIT, mmdb_fcif_init,(),(),() )  {
@@ -90,14 +85,14 @@ FORTRAN_SUBR ( MMDB_FCIF_CREATE, mmdb_fcif_create,
 char S[500];
 
   if (mmCIFData)  delete mmCIFData;
-  mmCIFData = new CMMCIFData ( makeString(S,sizeof(S),
+  mmCIFData = new mmcif::Data ( makeString(S,sizeof(S),
                                FTN_STR(DataName),FTN_LEN(DataName)) );
 
 }
 
 void MMDB_CCIF_Create ( pstr DataName )  {
   if (mmCIFData)  delete mmCIFData;
-  mmCIFData = new CMMCIFData ( DataName );
+  mmCIFData = new mmcif::Data ( DataName );
 }
 
 
@@ -107,13 +102,13 @@ FORTRAN_SUBR ( MMDB_FCIF_WRITE, mmdb_fcif_write,
                 int * iRet,         // return code
                 int   FileName_len  // fortran-hidden length of FileName
                ), ( // lengths-in-structure list
-		fpstr FileName, int *iRet
+    fpstr FileName, int *iRet
                ), ( // lengths-follow list
-		fpstr FileName, int FileName_len, int * iRet
+    fpstr FileName, int FileName_len, int * iRet
                ) )  {
 pstr S;
 
-  if (!mmCIFData)  
+  if (!mmCIFData)
     *iRet = -1000;
   else  {
     S = new char[FTN_LEN(FileName)+10];
@@ -182,7 +177,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTDOT, mmdb_fcif_putdot,
 char CN[200],TN[200];
   if (!mmCIFData)
        *iRet = -1000;
-  else *iRet = mmCIFData->PutNoData ( CIF_NODATA_DOT,
+  else *iRet = mmCIFData->PutNoData ( mmcif::CIF_NODATA_DOT,
                                       makeString(CN,sizeof(CN),
                                       FTN_STR(CatName),FTN_LEN(CatName)),
                                       makeString(TN,sizeof(TN),
@@ -192,7 +187,7 @@ char CN[200],TN[200];
 
 int MMDB_CCIF_PutDot ( pstr CatName, pstr Tag )  {
   if (!mmCIFData)  return  -1000;
-             else  return  mmCIFData->PutNoData ( CIF_NODATA_DOT,
+             else  return  mmCIFData->PutNoData ( mmcif::CIF_NODATA_DOT,
                                                   CatName,Tag );
 }
 
@@ -214,7 +209,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTQUESTION, mmdb_fcif_putquestion,
 char CN[200],TN[200];
   if (!mmCIFData)
        *iRet = -1000;
-  else *iRet = mmCIFData->PutNoData ( CIF_NODATA_QUESTION,
+  else *iRet = mmCIFData->PutNoData ( mmcif::CIF_NODATA_QUESTION,
                                       makeString(CN,sizeof(CN),
                                       FTN_STR(CatName),FTN_LEN(CatName)),
                                       makeString(TN,sizeof(TN),
@@ -223,8 +218,10 @@ char CN[200],TN[200];
 
 
 int MMDB_CCIF_PutQuestion ( pstr CatName, pstr Tag )  {
-  if (!mmCIFData)  return  -1000;
-             else  return  mmCIFData->PutNoData ( CIF_NODATA_QUESTION,
+  if (!mmCIFData)
+    return  -1000;
+  else
+    return  mmCIFData->PutNoData ( mmcif::CIF_NODATA_QUESTION,
                                                   CatName,Tag );
 }
 
@@ -241,7 +238,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTSTRING, mmdb_fcif_putstring,
                ), ( // lengths-in-structure list
                 fpstr Data, fpstr CatName, fpstr Tag, int * iRet
                ), ( // lengths-follow list
-		fpstr Data,    int Data_len,
+    fpstr Data,    int Data_len,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * iRet
@@ -254,7 +251,7 @@ pstr S;
   else  {
     S = new char[FTN_LEN(Data)+10];
     *iRet = mmCIFData->PutString ( makeString(S,FTN_LEN(Data)+5,
-				   FTN_STR(Data),FTN_LEN(Data)),
+           FTN_STR(Data),FTN_LEN(Data)),
                                    makeString(CN,sizeof(CN),
                                    FTN_STR(CatName),FTN_LEN(CatName)),
                                    makeString(TN,sizeof(TN),
@@ -281,7 +278,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTREAL, mmdb_fcif_putreal,
                ), ( // lengths-in-structure list
                 apireal * V, fpstr CatName, fpstr Tag, int * iRet
                ), ( // lengths-follow list
-		apireal * V,
+    apireal * V,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * iRet
@@ -315,7 +312,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTINTEGER, mmdb_fcif_putinteger,
                ), ( // lengths-in-structure list
                 int * I, fpstr CatName, fpstr Tag, int * iRet
                ), ( // lengths-follow list
-		int * I,
+    int * I,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * iRet
@@ -355,7 +352,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPDOT, mmdb_fcif_putloopdot,
 char CN[200],TN[200];
   if (!mmCIFData)
        *iRet = -1000;
-  else *iRet = mmCIFData->PutLoopNoData ( CIF_NODATA_DOT,
+  else *iRet = mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_DOT,
                                       makeString(CN,sizeof(CN),
                                       FTN_STR(CatName),FTN_LEN(CatName)),
                                       makeString(TN,sizeof(TN),
@@ -364,8 +361,10 @@ char CN[200],TN[200];
 
 
 int MMDB_CCIF_PutLoopDot ( pstr CatName, pstr Tag, int nrow )  {
-  if (!mmCIFData)  return  -1000;
-             else  return  mmCIFData->PutLoopNoData ( CIF_NODATA_DOT,
+  if (!mmCIFData)
+    return  -1000;
+  else
+    return  mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_DOT,
                                                   CatName,Tag,nrow );
 }
 
@@ -388,7 +387,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPQUESTION, mmdb_fcif_putloopquestion,
 char CN[200],TN[200];
   if (!mmCIFData)
        *iRet = -1000;
-  else *iRet = mmCIFData->PutLoopNoData ( CIF_NODATA_QUESTION,
+  else *iRet = mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_QUESTION,
                                       makeString(CN,sizeof(CN),
                                       FTN_STR(CatName),FTN_LEN(CatName)),
                                       makeString(TN,sizeof(TN),
@@ -396,9 +395,11 @@ char CN[200],TN[200];
 }
 
 int MMDB_CCIF_PutLoopQuestion ( pstr CatName, pstr Tag, int nrow )  {
-  if (!mmCIFData)  return  -1000;
-             else  return  mmCIFData->PutLoopNoData ( CIF_NODATA_QUESTION,
-                                                  CatName,Tag,nrow );
+  if (!mmCIFData)
+    return  -1000;
+  else
+    return  mmCIFData->PutLoopNoData ( mmcif::CIF_NODATA_QUESTION,
+                                                   CatName,Tag,nrow );
 }
 
 
@@ -416,7 +417,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPSTRING, mmdb_fcif_putloopstring,
                 fpstr Data, fpstr CatName, fpstr Tag,
                 int * nrow, int * iRet
                ), ( // lengths-follow list
-		fpstr Data,    int Data_len,
+    fpstr Data,    int Data_len,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * nrow,    int * iRet
@@ -429,7 +430,7 @@ pstr S;
   else  {
     S = new char[FTN_LEN(Data)+10];
     *iRet = mmCIFData->PutLoopString ( makeString(S,FTN_LEN(Data)+5,
-				       FTN_STR(Data),FTN_LEN(Data)),
+               FTN_STR(Data),FTN_LEN(Data)),
                                        makeString(CN,sizeof(CN),
                                        FTN_STR(CatName),FTN_LEN(CatName)),
                                        makeString(TN,sizeof(TN),
@@ -459,7 +460,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPREAL, mmdb_fcif_putloopreal,
                 apireal * V, fpstr CatName, fpstr Tag,
                 int * nrow, int * iRet
                ), ( // lengths-follow list
-		apireal * V,
+    apireal * V,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * nrow,    int * iRet
@@ -495,7 +496,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPINTEGER, mmdb_fcif_putloopinteger,
                 int * I, fpstr CatName, fpstr Tag,
                 int * nrow, int * iRet
                ), ( // lengths-follow list
-		int * I,
+    int * I,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * nrow,    int * iRet
diff --git a/mmdb/mmdb_ficif.h b/mmdb2/mmdb_ficif.h
old mode 100755
new mode 100644
similarity index 96%
rename from mmdb/mmdb_ficif.h
rename to mmdb2/mmdb_ficif.h
index 5a015f2..7347f38
--- a/mmdb/mmdb_ficif.h
+++ b/mmdb2/mmdb_ficif.h
@@ -1,4 +1,4 @@
-//  $Id: mmdb_ficif.h,v 1.19 2012/01/26 17:52:20 ekr Exp $
+//  $Id: mmdb_ficif.h $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
@@ -6,13 +6,13 @@
 //
 //   Copyright (C) Eugene Krissinel 2000-2008.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -22,7 +22,7 @@
 //
 //  =================================================================
 //
-//    15.12.02   <--  Date of Last Modification.
+//    12.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
@@ -30,10 +30,10 @@
 //       ~~~~~~~~~
 //  **** Project :  MacroMolecular Data Base (MMDB)
 //       ~~~~~~~~~
-//  **** Classes :  
-//       ~~~~~~~~~  
+//  **** Classes :
+//       ~~~~~~~~~
 //
-//  (C) E. Krissinel 2000-2008
+//  (C) E. Krissinel 2000-2013
 //
 //  =================================================================
 //
@@ -41,13 +41,10 @@
 #ifndef __MMDB_FICIF__
 #define __MMDB_FICIF__
 
+#include "mmdb_machine_.h"
 
-#ifndef  __Machine__
-#include "machine_.h"
-#endif
-
-
-
+using namespace mmdb;
+using namespace mmdb::machine;
 
 //  ====================  FORTRAN INTERFACE  ========================
 
@@ -71,9 +68,9 @@ FORTRAN_SUBR ( MMDB_FCIF_WRITE, mmdb_fcif_write,
                 int * iRet,         // return code
                 int   FileName_len  // fortran-hidden length of FileName
                ), ( // lengths-in-structure list
-		fpstr FileName, int *iRet
+    fpstr FileName, int *iRet
                ), ( // lengths-follow list
-		fpstr FileName, int FileName_len, int * iRet
+    fpstr FileName, int FileName_len, int * iRet
                ) );
 
 FORTRAN_SUBR ( MMDB_FCIF_PUTDATE, mmdb_fcif_putdate,
@@ -133,7 +130,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTSTRING, mmdb_fcif_putstring,
                ), ( // lengths-in-structure list
                 fpstr Data, fpstr CatName, fpstr Tag, int * iRet
                ), ( // lengths-follow list
-		fpstr Data,    int Data_len,
+    fpstr Data,    int Data_len,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * iRet
@@ -150,11 +147,11 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTREAL, mmdb_fcif_putreal,
                ), ( // lengths-in-structure list
                 apireal * V, fpstr CatName, fpstr Tag, int * iRet
                ), ( // lengths-follow list
-		apireal * V,
+    apireal * V,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * iRet
-               ) );  
+               ) );
 
 FORTRAN_SUBR ( MMDB_FCIF_PUTINTEGER, mmdb_fcif_putinteger,
                (    // lengths-at-end list
@@ -167,7 +164,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTINTEGER, mmdb_fcif_putinteger,
                ), ( // lengths-in-structure list
                 int * I, fpstr CatName, fpstr Tag, int * iRet
                ), ( // lengths-follow list
-		int * I,
+    int * I,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * iRet
@@ -219,7 +216,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPSTRING, mmdb_fcif_putloopstring,
                 fpstr Data, fpstr CatName, fpstr Tag,
                 int * nrow, int * iRet
                ), ( // lengths-follow list
-		fpstr Data,    int Data_len,
+    fpstr Data,    int Data_len,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * nrow,    int * iRet
@@ -238,7 +235,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPREAL, mmdb_fcif_putloopreal,
                 apireal * V, fpstr CatName, fpstr Tag,
                 int * nrow, int * iRet
                ), ( // lengths-follow list
-		apireal * V,
+    apireal * V,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * nrow,    int * iRet
@@ -257,7 +254,7 @@ FORTRAN_SUBR ( MMDB_FCIF_PUTLOOPINTEGER, mmdb_fcif_putloopinteger,
                 int * I, fpstr CatName, fpstr Tag,
                 int * nrow, int * iRet
                ), ( // lengths-follow list
-		int * I,
+                int * I,
                 fpstr CatName, int CatName_len,
                 fpstr Tag,     int Tag_len,
                 int * nrow,    int * iRet
diff --git a/mmdb2/mmdb_io_file.cpp b/mmdb2/mmdb_io_file.cpp
new file mode 100644
index 0000000..606bdf2
--- /dev/null
+++ b/mmdb2/mmdb_io_file.cpp
@@ -0,0 +1,1873 @@
+//  $Id: file_.cpp,v 1.29 2012/01/26 17:52:19 ekr Exp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    29.01.10   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_io_file  <implementation>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::io::File  - file I/O Support.
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef  _WIN32
+# include <windows.h>
+# define sleep Sleep
+#else
+# ifndef  __UNISTD_H
+#  include <unistd.h>
+# endif
+#endif
+
+#include "mmdb_io_file.h"
+
+
+// _WIN32_NEWLINE should be raised when compilinig on Windows in
+// order to enforce Windows' line endings when writing text in
+// files opened for *binary* output. Otherwise, writing text lines
+// in binary files will results in UNIX line endings. Line endings
+// in files, opened for output in text mode, will be always
+// platform-specific.
+
+#ifdef  _WIN32_NEWLINE
+//  for DOS/WINDOWS machines:
+#define  NEWLINE  "\r\n"
+#else
+//  for UNIX machines:
+#define  NEWLINE  "\n"
+#endif
+
+namespace mmdb  {
+
+  namespace io  {
+
+#ifdef _WIN32
+    const char _dir_sep_c = '\\';
+    cpstr      _dir_sep   = "\\";
+#else
+    const char _dir_sep_c = '/';
+    cpstr      _dir_sep   = "/";
+#endif
+
+    // ===================  Auxilary Functions  =========================
+
+    cpstr GetFPath ( pstr FilePath, SYSKEY syskey )  {
+    pstr P;
+
+      if (syskey==syskey_unix)
+        P = strrchr(FilePath,'/');
+      else if (syskey==syskey_win)
+        P = strrchr(FilePath,'\\');
+      else if (syskey==syskey_all)  {
+        P = strrchr(FilePath,'/');
+        if (!P)  P = strrchr(FilePath,'\\');
+      } else
+        P = NULL;
+
+      if (P)  {
+        P = P + 1;
+        *P = char(0);
+      } else
+        FilePath[0] = char(0);
+
+      return FilePath;
+
+    }
+
+    cpstr GetFName ( cpstr FilePath, SYSKEY syskey )  {
+    pstr P;
+      if (syskey==syskey_unix)
+        P = strrchr(FilePath,'/');
+      else if (syskey==syskey_win)
+        P = strrchr(FilePath,'\\');
+      else if (syskey==syskey_all)  {
+        P = strrchr(FilePath,'/');
+        if (!P)  P = strrchr(FilePath,'\\');
+      } else
+        P = NULL;
+      if (!P)  return FilePath;
+         else  return P + 1;
+    }
+
+    cpstr GetFExt ( cpstr FilePath )  {
+    pstr P;
+      P = strchr ( GetFName(FilePath),'.');
+      if (!P) return &(FilePath[strlen(FilePath)]);
+         else return P;
+    }
+
+    cpstr ChangeExt ( pstr FilePath, cpstr newExt, SYSKEY syskey )  {
+    int i;
+      i = strlen(FilePath)-1;
+      if (syskey==syskey_unix)
+        while ((i>0) && (FilePath[i]!='.') && (FilePath[i]!='/'))  i--;
+      else if (syskey==syskey_win)
+        while ((i>0) && (FilePath[i]!='.') && (FilePath[i]!='\\'))  i--;
+      else if (syskey==syskey_all)
+        while ((i>0) && (FilePath[i]!='.') &&
+               (FilePath[i]!='/') && (FilePath[i]!='\\'))  i--;
+      if (FilePath[i]=='.')  {
+        FilePath[i+1] = char(0);
+        strcat ( FilePath,newExt );
+      } else  {
+        strcat ( FilePath,"."    );
+        strcat ( FilePath,newExt );
+      }
+      return FilePath;
+    }
+
+    bool FileExists ( cpstr FileName, PFile f )  {
+    PFile  g;
+    bool B;
+      if (FileName)  {
+        if (!f)  g = new File();
+           else  g = f;
+        g->assign ( FileName );
+        B = g->exists();
+        if (!f)  delete g;
+        return B;
+      } else
+        return false;
+    }
+
+
+    //  ========================  File Class  ========================
+
+    #define ARCH_NONE      0
+    #define ARCH_GZIP      1
+    #define ARCH_COMPRESS  2
+    #define ARCH_ENFORCE   3
+
+    File::File ( word BufSize )  {
+      Buf_Size  = BufSize;
+      BufLen    = 0;
+      BufInc    = 1;
+      EofFile   = false;
+      hFile     = NULL;
+      FName     = NULL;
+      BufCnt    = 0;
+      IOBuf     = NULL;
+      IOSuccess = true;
+      TextMode  = false;
+      UniBin    = false;
+      StdIO     = false;
+      gzipIO    = ARCH_NONE;
+      memIO     = false;
+    }
+
+    File::~File()  {
+      shut      ();
+      FreeBuffer();
+    }
+
+    void  File::FreeBuffer ()  {
+      if (IOBuf)  {
+        if (!memIO)  delete[] IOBuf;
+        IOBuf = NULL;
+      }
+      if (FName)  {
+        delete[] FName;
+        FName = NULL;
+      }
+    }
+
+    void  File::assign ( cpstr FileName, bool Text, bool UniB,
+                         GZ_MODE gzMode )  {
+    pstr p;
+
+      shut();
+
+      FreeBuffer();
+
+      CreateCopy ( FName,FileName );
+      StdIO = (!strcmp(FName,"stdin" )) ||
+              (!strcmp(FName,"stdout")) ||
+              (!strcmp(FName,"stderr"));
+
+      if (StdIO)  TextMode = true;
+            else  TextMode = Text;
+
+      UniBin = UniB;
+
+      gzipMode = gzMode;
+      gzipIO   = ARCH_NONE;
+      if ((gzipMode==GZM_ENFORCE) || (gzipMode==GZM_ENFORCE_GZIP))
+        gzipIO = ARCH_GZIP;
+      else if (gzipMode==GZM_ENFORCE_COMPRESS)
+        gzipIO = ARCH_COMPRESS;
+      else if (gzipMode==GZM_CHECK)  {
+        p = strrchr ( FName,'.' );
+        if (p)  {
+          if (!strcmp(p,".gz"))      gzipIO = ARCH_GZIP;
+          else if (!strcmp(p,".Z"))  gzipIO = ARCH_COMPRESS;
+        }
+      }
+
+      memIO = false;
+
+    }
+
+
+    void  File::assign ( word poolSize, word sizeInc, pstr filePool )  {
+
+      shut      ();
+      FreeBuffer();
+
+      IOBuf    = (pstr)filePool;
+      BufLen   = poolSize;
+      FLength  = poolSize;
+      BufInc   = sizeInc;
+      BufCnt   = 0;
+
+      memIO    = true;
+      gzipMode = GZM_NONE;
+      gzipIO   = ARCH_NONE;
+
+    }
+
+    void  File::GetFilePool ( pstr & filePool, word & fileSize )  {
+      if (memIO)  {
+        filePool = IOBuf;
+        fileSize = FLength;
+        IOBuf    = NULL;
+        BufLen   = 0;
+        BufCnt   = 0;
+        FLength  = 0;
+      } else  {
+        filePool = NULL;
+        fileSize = 0;
+      }
+    }
+
+    static pstr gzip_path       = pstr("gzip ");
+    static pstr ungzip_path     = pstr("gzip -dc ");
+    static pstr compress_path   = pstr("compress ");
+    static pstr uncompress_path = pstr("uncompress -c ");
+
+    void  SetGZIPPath ( pstr gzipPath, pstr ungzipPath )  {
+      if (!gzipPath)  gzip_path = pstr("gzip ");
+                else  gzip_path = gzipPath;
+      if (!ungzipPath)  ungzip_path = pstr("gzip -d ");
+                  else  ungzip_path = ungzipPath;
+    }
+
+    void  SetCompressPath ( pstr compressPath, pstr uncompressPath )  {
+      if (!compressPath)  compress_path = pstr("compress ");
+                    else  compress_path = compressPath;
+      if (!uncompressPath)  uncompress_path = pstr("uncompress -c ");
+                      else  uncompress_path = uncompressPath;
+    }
+
+
+    bool  File::reset ( bool ReadOnly, int retry )  {
+    #ifndef _MSC_VER
+    pstr p;
+    int  i;
+    #endif
+
+      if (memIO)  {
+
+        shut();
+        if (!IOBuf)  return false;
+        BufCnt    = 0;
+        IOSuccess = true;
+
+      } else  {
+
+        if (!FName)  return false;
+        shut();
+        BufLen = 0;
+        BufCnt = 0;
+
+        if (!strcmp(FName,"stdin"))  {
+
+          hFile     = stdin;
+          StdIO     = true;
+          TextMode  = true;
+          FLength   = 1;
+          EofFile   = false;
+          IOSuccess = true;
+
+        } else  {
+
+          StdIO = false;
+          if (gzipIO==ARCH_GZIP)  {
+    #ifndef _MSC_VER
+            p = NULL;
+            CreateConcat  ( p,ungzip_path,FName );
+            for (i=0;(i<=retry) && (!hFile);i++)  {
+              if (i>0)  sleep ( 1 );
+              hFile = popen ( p,"r" );
+            }
+            if (p)  delete[] p;
+    #endif
+
+          } else if (gzipIO==ARCH_COMPRESS)  {
+    #ifndef _MSC_VER
+            p = NULL;
+            CreateConcat  ( p,uncompress_path,FName );
+            for (i=0;(i<=retry) && (!hFile);i++)  {
+              if (i>0)  sleep ( 1 );
+              hFile = popen ( p,"r" );
+            }
+            if (p)  delete[] p;
+    #endif
+
+          } else  {
+
+    #ifndef _MSC_VER
+            for (i=0;(i<=retry) && (!hFile);i++)  {
+              if (i>0)  sleep ( 1 );
+              if (TextMode)  {
+                if (ReadOnly)  hFile = fopen ( FName,"rt"  );
+                         else  hFile = fopen ( FName,"r+t" );
+              } else  {
+                if (ReadOnly)  hFile = fopen ( FName,"rb"  );
+                         else  hFile = fopen ( FName,"r+b" );
+              }
+            }
+    #endif
+
+          }
+
+          if (hFile)  {
+            if (gzipIO==ARCH_NONE)  {
+              fseek ( hFile,0L,SEEK_END );
+              FLength = ftell ( hFile );
+              fseek ( hFile,0L,SEEK_SET );
+              EofFile = (FLength<=0);
+            } else  {
+              FLength = 1;
+              EofFile = false;
+            }
+            IOSuccess = true;
+          } else  {
+            EofFile   = true;
+            IOSuccess = false;
+          }
+
+        }
+
+      }
+
+      return  IOSuccess;
+
+    }
+
+    bool  File::rewrite()  {
+    #ifndef _MSC_VER
+    pstr p;
+    #endif
+
+      if (memIO)  {
+
+        shut();
+        FreeBuffer();
+        IOBuf = new char[BufLen];
+        BufCnt    = 0;
+        FLength   = 0;
+        IOSuccess = true;;
+
+      } else  {
+
+        if (!FName)  return false;
+        shut();
+        BufLen = 0;
+        BufCnt = 0;
+
+        if (gzipIO==ARCH_GZIP)  {
+    #ifndef _MSC_VER
+          p = NULL;
+          CreateConcat  ( p,gzip_path,pstr(" > "),FName );
+          hFile = popen ( p,"w" );
+          if (p)  delete[] p;
+    #else
+          hFile = NULL;
+    #endif
+          StdIO = false;
+        } else if (gzipIO==ARCH_COMPRESS)  {
+    #ifndef _MSC_VER
+          p = NULL;
+          CreateConcat  ( p,compress_path,pstr(" > "),FName );
+          hFile = popen ( p,"w" );
+          if (p)  delete[] p;
+    #else
+          hFile = NULL;
+    #endif
+          StdIO = false;
+        } else if (!TextMode)  {
+          hFile = fopen ( FName,"w+b" );
+          StdIO = false;
+        } else if (!strcmp(FName,"stdout"))  {
+          hFile = stdout;
+          StdIO = true;
+        } else if (!strcmp(FName,"stderr")) {
+          hFile = stderr;
+          StdIO = true;
+        } else  {
+          hFile = fopen ( FName,"w+t" );
+          StdIO = false;
+        }
+
+        FLength   = 0;
+        IOSuccess = (hFile!=NULL);
+
+      }
+
+      return  IOSuccess;
+
+    }
+
+
+    bool  File::append()  {
+    #ifndef _MSC_VER
+    pstr p;
+    #endif
+
+      if (memIO)  {
+
+        if (!IOBuf)  {
+          IOBuf  = new char[BufLen];
+          BufCnt = 0;
+        }
+        FLength   = BufCnt;
+        IOSuccess = true;
+
+      } else  {
+
+        if (!FName)  return false;
+
+        shut();
+        BufLen  = 0;
+        BufCnt  = 0;
+        if (gzipIO==ARCH_GZIP)  {
+    #ifndef _MSC_VER
+          p = NULL;
+          CreateConcat  ( p,gzip_path,pstr(" >> "),FName );
+          hFile = popen ( p,"w" );
+          if (p)  delete[] p;
+    #else
+          hFile = NULL;
+    #endif
+          StdIO = false;
+        } else if (gzipIO==ARCH_COMPRESS)  {
+    #ifndef _MSC_VER
+          p = NULL;
+          CreateConcat  ( p,compress_path,pstr(" >> "),FName );
+          hFile = popen ( p,"w" );
+          if (p)  delete[] p;
+    #else
+          hFile = NULL;
+    #endif
+          StdIO = false;
+        } else if (!TextMode)  {
+          hFile = fopen ( FName,"ab" );
+          StdIO = false;
+        } else if (!strcmp(FName,"stdout"))  {
+          hFile = stdout;
+          StdIO = true;
+        } else if (!strcmp(FName,"stderr")) {
+          hFile = stderr;
+          StdIO = true;
+        } else  {
+          hFile = fopen ( FName,"at" );
+          StdIO = false;
+        }
+
+        FLength = 0;
+        IOSuccess = hFile!=NULL;
+
+      }
+
+      return  IOSuccess;
+
+    }
+
+    bool  File::erase()  {
+      if (!FName)  return false;
+      shut();
+      if (!StdIO)  {
+        BufLen = 0;
+        BufCnt = 0;
+        if (FName)
+          IOSuccess = (remove(FName)==0);
+        FLength = 0;
+      } else
+        IOSuccess = true;
+      return  IOSuccess;
+    }
+
+    bool  File::exists()  {
+
+      if (memIO)  {
+
+        IOSuccess = (IOBuf!=NULL);
+
+      } else  {
+
+        if (!FName)  return false;
+        shut();
+        if (!StdIO)  {
+          hFile     = fopen ( FName,"r" );
+          IOSuccess = (hFile!=NULL);
+          BufLen    = 0;
+          BufCnt    = 0;
+          FLength   = 0;
+          if (hFile)  fclose ( hFile );
+        } else
+          IOSuccess = true;
+        hFile = NULL;
+      }
+
+      return  IOSuccess;
+
+    }
+
+    bool  File::parse ( cpstr FileName )  {
+    UNUSED_ARGUMENT(FileName);
+      return true;
+    }
+
+    bool  File::rename ( cpstr NewFileName )  {
+      if (!FName)  return false;
+      shut();
+      if (!StdIO)
+        IOSuccess = (::rename(FName,NewFileName)==0);
+      if (IOSuccess)  assign ( NewFileName,TextMode,UniBin,gzipMode );
+      return  IOSuccess;
+    }
+
+    long  File::Position()  {
+    // do not use on text files
+
+      if (memIO)  return BufCnt;
+
+      if (hFile==NULL)  return 0L;
+      return  ftell ( hFile );
+
+    }
+
+    bool  File::seek ( long Position )  {
+    // do not use on text files
+      if (memIO)  {
+        if (Position<=(long)BufLen)  {
+          BufCnt    = Position;
+          IOSuccess = true;
+        } else
+          IOSuccess = false;
+        return IOSuccess;
+      } else if (hFile==NULL)
+        return false;
+      else if (!StdIO)  {
+        IOSuccess = fseek(hFile,Position,SEEK_SET)==0;
+        return IOSuccess;
+      } else
+        return true;
+    }
+
+    bool  File::FileEnd()  {
+
+      if (memIO)  return ((long)BufCnt>=FLength);
+
+      if (TextMode)  {
+        if (EofFile || ((!hFile) && (!StdIO)))
+           return true;
+        if (feof(hFile)==0)
+           return false;
+        return true;
+      }
+
+      return  EofFile && (BufLen==0);
+
+    }
+
+    void  File::flush ()  {
+
+      if (hFile!=NULL)  {
+        if (!StdIO)  {
+    #ifndef _MSC_VER
+          if (gzipIO==ARCH_NONE)
+            fflush ( hFile );
+    #else
+          fflush ( hFile );
+    #endif
+        }
+      }
+    }
+
+    void  File::shut ()  {
+
+      if (hFile!=NULL)  {
+        if (!StdIO)  {
+    #ifndef _MSC_VER
+          if (gzipIO!=ARCH_NONE)  pclose ( hFile );
+                            else  fclose ( hFile );
+    #else
+          fclose ( hFile );
+    #endif
+        }
+        hFile = NULL;
+      }
+
+    }
+
+    bool File::isOpen()  {
+      if (memIO)  return (IOBuf!=NULL);
+      return (hFile!=NULL);
+    }
+
+    word  File::ReadLine ( pstr Line, word MaxLen )  {
+    word     LCnt;
+    int      Done;
+    bool  HSuccess = IOSuccess;
+
+      if (memIO)  {
+
+        LCnt = 0;
+        while (((long)BufCnt<FLength) &&
+               (LCnt<MaxLen-1)        &&
+               (IOBuf[BufCnt]!='\r')  &&
+               (IOBuf[BufCnt]!='\n') )
+          Line[LCnt++] = IOBuf[BufCnt++];
+        Line[LCnt] = char(0);
+
+        while (((long)BufCnt<FLength) &&
+               (IOBuf[BufCnt]!='\r')  &&
+               (IOBuf[BufCnt]!='\n') )
+          BufCnt++;
+
+        if ((long)BufCnt<FLength)  {
+          if (IOBuf[BufCnt]=='\r')  {
+            BufCnt++;
+            if ((long)BufCnt<FLength)  {
+              if (IOBuf[BufCnt]=='\n')  BufCnt++;
+            }
+          } else if (IOBuf[BufCnt]=='\n')  {
+            BufCnt++;
+            if ((long)BufCnt<FLength)  {
+              if (IOBuf[BufCnt]=='\r')  BufCnt++;
+            }
+          }
+        }
+
+        return LCnt;
+
+      } else  {
+
+        if ((!hFile) && (!StdIO))  {
+          Line[0]   = char(0);
+          EofFile   = true;
+          BufLen    = 0;
+          IOSuccess = false;
+          return 0;
+        }
+        if (TextMode)  {
+          Line[0] = char(0);
+          if (fgets(Line,MaxLen,hFile))  {
+            LCnt = strlen(Line);
+            while (LCnt>0)  {
+              if ((Line[LCnt-1]!='\n') &&
+                  (Line[LCnt-1]!='\r'))  break;
+              Line[LCnt-1] = char(0);
+              LCnt--;
+            }
+          } else
+            LCnt = 0;
+          return LCnt;
+        } else  {
+          if (IOBuf==NULL)  {
+            IOBuf     = new char[Buf_Size];
+            BufLen    = ReadFile ( IOBuf,Buf_Size );
+            IOSuccess = HSuccess;
+            BufCnt    = 0;
+          }
+          LCnt = 0;
+          do {
+            while ((BufCnt<BufLen)       &&
+                   (LCnt<MaxLen-1)       &&
+                   (IOBuf[BufCnt]!='\r') &&
+                   (IOBuf[BufCnt]!='\n') )
+              Line[LCnt++] = IOBuf[BufCnt++];
+            if (BufCnt>=BufLen)  {
+              HSuccess  = IOSuccess;
+              BufLen    = ReadFile ( IOBuf,Buf_Size );
+              IOSuccess = HSuccess;
+              BufCnt    = 0;
+            }
+            if (IOBuf[BufCnt]=='\r')      Done = 1;
+            else if (IOBuf[BufCnt]=='\n') Done = 2;
+                                     else Done = 0;
+            if (Done)  BufCnt++;
+            if (BufCnt>=BufLen)  {
+              HSuccess  = IOSuccess;
+              BufLen    = ReadFile ( IOBuf,Buf_Size );
+              IOSuccess = HSuccess;
+              BufCnt    = 0;
+            }
+            if (BufLen>0)  {
+              if (((Done==2) && (IOBuf[BufCnt]=='\r')) ||
+                  ((Done==1) && (IOBuf[BufCnt]=='\n')))
+                BufCnt++;
+            }
+          } while ((!Done) && (LCnt<MaxLen-1) && (BufLen>0));
+          Line[LCnt] = char(0);
+          return LCnt;
+        }
+
+      }
+
+    }
+
+    word  File::ReadNonBlankLine ( pstr S, word MaxLen )  {
+    word  i,j;
+      do  {
+        j = ReadLine ( S,MaxLen );
+        i = 0;
+        while ((i<j) && (S[i]==' ')) i++;
+      } while ((i>=j) && (!FileEnd()));
+      if (i>=j)  {
+        S[0] = char(0);
+        j    = 0;
+      }
+      return  j;
+    }
+
+
+    bool  File::WriteLine ( cpstr Line )  {
+      if ((!memIO) && TextMode)  {
+        if (hFile==NULL)  return false;
+        fputs ( Line,hFile );
+    //    return (fputs(NEWLINE,hFile)>=0);
+        return (fputs("\n",hFile)>=0);
+      } else  {
+        if (WriteFile(Line,strlen(Line)))
+              return  WriteFile ( (void *)NEWLINE,strlen(NEWLINE) );
+        else  return  false;
+      }
+    }
+
+    bool  File::Write ( cpstr Line )  {
+      if ((!memIO) && TextMode)  {
+        if (hFile==NULL)  return false;
+        return (fputs(Line,hFile)>=0);
+      } else
+        return WriteFile(Line,strlen(Line));
+    }
+
+    bool  File::Write ( realtype V, int length )  {
+    char N[50];
+      sprintf ( N,"%-.*g",length,V );
+      if ((!memIO) && TextMode)  {
+        if (hFile==NULL)  return false;
+        return (fputs(N,hFile)>=0);
+      } else
+        return WriteFile(N,strlen(N));
+    }
+
+    bool  File::Write ( int iV, int length )  {
+    char N[50];
+      sprintf ( N,"%*i",length,iV );
+      if ((!memIO) && TextMode)  {
+        if (hFile==NULL)  return false;
+        return (fputs(N,hFile)>=0);
+      } else
+        return WriteFile(N,strlen(N));
+    }
+
+    bool  File::LF()  {
+      if ((!memIO) && TextMode)  {
+        if (hFile==NULL)  return false;
+    //    return (fputs(NEWLINE,hFile)>=0);
+        return (fputs("\n",hFile)>=0);
+      } else
+        return WriteFile ( (void *)NEWLINE,strlen(NEWLINE) );
+    }
+
+    bool  File::WriteDataLine ( realtype X, realtype Y, int length )  {
+      Write ( pstr("   ") );
+      Write ( X,length    );
+      Write ( pstr("   ") );
+      Write ( Y,length    );
+      return LF();
+    }
+
+    bool  File::WriteParameter ( cpstr S, realtype X,
+                                 int ParColumn, int length )  {
+    int  l=strlen(S);
+      if ((!memIO) && TextMode)  {
+        fputs ( S,hFile );
+        while (l<ParColumn)  {
+          fputs ( " ",hFile );
+          l++;
+        }
+      } else  {
+        WriteFile ( S,l );
+        while (l<ParColumn)  {
+          WriteFile ( (void *)" ",1 );
+          l++;
+        }
+      }
+      Write ( X,length );
+      return LF();
+    }
+
+    bool  File::WriteParameters ( cpstr S, int n_X, rvector X,
+                                  int ParColumn, int length )  {
+    int  i;
+    int  l=strlen(S);
+      if ((!memIO) && TextMode)  {
+        fputs ( S,hFile );
+        while (l<ParColumn)  {
+          fputs ( " ",hFile );
+          l++;
+        }
+      } else  {
+        WriteFile ( S,l );
+        while (l<ParColumn)  {
+          WriteFile ( (void *)" ",1 );
+          l++;
+        }
+      }
+      for (i=0;i<n_X;i++)  {
+        Write ( X[i],length );
+        if (i!=n_X-1)  WriteFile ( (void *)", ",2 );
+      }
+      return LF();
+    }
+
+    bool  File::ReadParameter  ( pstr S, realtype & X,
+                                 int ParColumn )  {
+      ReadLine ( S );
+      if ((int)strlen(S)>ParColumn)  {
+    //    X = atof ( &(S[ParColumn]) );
+        X = GetNumber ( &(S[ParColumn]) );
+        return true;
+      } else  {
+        X = 0.0;
+        return false;
+      }
+    }
+
+    bool  File::ReadParameters ( pstr S, int & n_X, rvector X,
+                                 int MaxLen, int ParColumn )  {
+    pstr S1,S2;
+      ReadLine ( S,MaxLen );
+      if ((int)strlen(S)>ParColumn)  {
+        n_X = 0;
+        S2 = &(S[ParColumn]);
+        S1 = S2;
+        while (*S1!=char(0))  {
+          if (*S1==',')  *S1 = ' ';
+          S1++;
+        }
+        while (*S2!=char(0))  {
+          S1 = S2;
+          X[n_X] = strtod ( S1,&S2 );
+          n_X++;
+          while ((*S2!=char(0)) && (*S2==' '))  S2++;
+        }
+        return true;
+      } else  {
+        n_X  = 0;
+        X[0] = 0.0;
+        return false;
+      }
+    }
+
+    bool  File::ReadParameter  ( pstr S, int & X,
+                                 int ParColumn )  {
+    realtype  V;
+      if (ReadParameter(S,V,ParColumn))  {
+        X = mround(V);
+        return true;
+      } else  {
+        X = 0;
+        return false;
+      }
+    }
+
+    bool  File::CreateWrite ( cpstr Line )  {
+    wordUniBin wUB;
+    word       i;
+      if (UniBin)  {
+        if (Line)  {
+          i = strlen(Line)+1;
+          word2UniBin ( i,wUB );
+          if (WriteFile(wUB,sizeof(wordUniBin)))
+                 return WriteFile ( Line,i );
+          else   return false;
+        } else  {
+          i = 0;
+          word2UniBin ( i,wUB );
+          return WriteFile ( wUB,sizeof(wordUniBin) );
+        }
+      } else  {
+        if (Line)  {
+          i = strlen(Line)+1;
+          if (WriteFile(&i,sizeof(i)))
+                 return WriteFile ( Line,i );
+          else   return false;
+        } else  {
+          i = 0;
+          return WriteFile ( &i,sizeof(i) );
+        }
+      }
+    }
+
+    #define _max_dyn_string_len  1073741824
+
+    word  File::CreateRead ( pstr & Line )  {
+    wordUniBin wUB;
+    word       i;
+    //unsigned short int i;
+      if (Line)  {
+        delete[] Line;
+        Line = NULL;
+      }
+      if (UniBin)  {
+        ReadFile    ( wUB,sizeof(wordUniBin) );
+        UniBin2word ( wUB,i );
+      } else
+        ReadFile ( &i,sizeof(i) );
+      if ((i>0) && (i<_max_dyn_string_len))  {
+        Line = new char[i];
+        ReadFile ( Line,i );
+      }
+      return i;
+    }
+
+    bool  File::WriteTerLine ( cpstr Line, bool longLine )  {
+    wordUniBin wUB;
+    word       ll;
+    byte       sl;
+    bool    B;
+      if (Line)  ll = strlen(Line);
+           else  ll = 0;
+      if (!longLine)  {
+        sl = byte(ll);
+        B = WriteFile ( &sl,sizeof(sl) );
+      } else if (UniBin)  {
+        word2UniBin ( ll,wUB );
+        B = WriteFile ( wUB,sizeof(wordUniBin) );
+      } else
+        B = WriteFile ( &ll,sizeof(ll) );
+      if (B && (ll>0))  B = WriteFile ( Line,ll );
+      return B;
+    }
+
+    word  File::ReadTerLine ( pstr Line, bool longLine )  {
+    wordUniBin wUB;
+    word       ll;
+    byte       sl;
+      if (!longLine)  {
+        ReadFile ( &sl,sizeof(sl) );
+        ll = sl;
+      } else if (UniBin)  {
+        ReadFile    ( wUB,sizeof(wordUniBin) );
+        UniBin2word ( wUB,ll );
+      } else
+        ReadFile ( &ll,sizeof(ll) );
+      if (ll>0)  ReadFile ( Line,ll );
+      Line[ll] = char(0);
+      return ll+1;
+    }
+
+    word  File::ReadFile ( void * Buffer, word Count )  {
+    word  Cnt;
+      if (memIO)  {
+        Cnt       = WMin(Count,FLength-BufCnt);
+        if (Cnt>0)  {
+          memcpy ( Buffer,&(IOBuf[BufCnt]),Cnt );
+          BufCnt += Cnt;
+        }
+        IOSuccess = (Cnt==Count);
+        EofFile   = ((Cnt<Count) || ((long)BufCnt>=FLength));
+        return  Cnt;
+      } else if (hFile)  {
+        Cnt       = (word)fread ( Buffer,1,Count,hFile );
+        EofFile   = (Cnt<Count) ||
+                     ((gzipIO==ARCH_NONE) && (Position()==FLength));
+        IOSuccess = (Cnt==Count);
+        return  Cnt;
+      } else
+        return  0;
+    }
+
+    bool  File::WriteFile ( const void * Buffer, word Count )  {
+    pstr IOB;
+    word Cnt;
+    long Pos;
+
+      if (memIO)  {
+
+        Cnt = BufCnt + Count;
+        if (Cnt>BufLen)  {
+          Cnt += BufInc;
+          IOB = new char[Cnt];
+          if (IOBuf)  {
+            memcpy ( IOB,IOBuf,BufCnt );
+            delete[] IOBuf;
+          }
+          IOBuf = IOB;
+          BufLen = Cnt;
+        }
+        memcpy ( &(IOBuf[BufCnt]),Buffer,Count );
+        BufCnt += Count;
+        FLength = BufCnt;
+        IOSuccess = true;
+
+      } else  {
+
+        if (hFile==NULL)  return false;
+        Cnt = (word)fwrite ( Buffer,1,Count,hFile );
+        Pos = Position();
+        if (Pos>FLength)  FLength = Pos;
+        IOSuccess = Cnt==Count;
+
+      }
+
+      return IOSuccess;
+
+    }
+
+    bool  File::WriteReal ( realtype * V )  {
+    realUniBin  rUB;
+      if (UniBin)  {
+        real2UniBin ( *V,rUB );
+        return WriteFile ( rUB,sizeof(realUniBin) );
+      } else
+        return WriteFile ( V,sizeof(realtype) );
+    }
+
+    bool  File::WriteFloat ( realtype * V )  {
+    floatUniBin fUB;
+    float       fV;
+      if (UniBin)  {
+        float2UniBin ( *V,fUB );
+        return WriteFile ( fUB,sizeof(floatUniBin) );
+      } else  {
+        fV = (float)*V;
+        return WriteFile ( &fV,sizeof(float) );
+      }
+    }
+
+    bool  File::WriteInt ( int * I )  {
+    intUniBin  iUB;
+      if (UniBin)  {
+        int2UniBin ( *I,iUB );
+        return WriteFile ( iUB,sizeof(intUniBin) );
+      } else
+        return WriteFile ( I,sizeof(int) );
+    }
+
+    bool  File::WriteShort ( short * S )  {
+    shortUniBin  sUB;
+      if (UniBin)  {
+        short2UniBin ( *S,sUB );
+        return WriteFile ( sUB,sizeof(shortUniBin) );
+      } else
+        return WriteFile ( S,sizeof(short) );
+    }
+
+    bool  File::WriteLong ( long * L )  {
+    longUniBin  lUB;
+      if (UniBin)  {
+        long2UniBin ( *L,lUB );
+        return WriteFile ( lUB,sizeof(longUniBin) );
+      } else
+        return WriteFile ( L,sizeof(long) );
+    }
+
+    bool  File::WriteBool ( bool * B )  {
+    intUniBin  iUB;
+    int        k;
+      if (UniBin)  {
+        if (*B)  k = 1;
+           else  k = 0;
+        int2UniBin ( k,iUB );
+        return WriteFile ( iUB,sizeof(intUniBin) );
+      } else
+        return WriteFile ( B,sizeof(bool) );
+    }
+
+    bool  File::WriteByte ( byte * B )  {
+      return WriteFile ( B,sizeof(byte) );
+    }
+
+    bool  File::WriteWord ( word * W )  {
+    wordUniBin  wUB;
+      if (UniBin)  {
+        word2UniBin ( *W,wUB );
+        return WriteFile ( wUB,sizeof(wordUniBin) );
+      } else
+        return WriteFile ( W,sizeof(word) );
+    }
+
+    bool  File::ReadReal ( realtype * V )  {
+    realUniBin  rUB;
+      if (UniBin)  {
+        if (ReadFile(rUB,sizeof(realUniBin))==sizeof(realUniBin))  {
+          UniBin2real ( rUB,*V );
+          return true;
+        } else
+          return false;
+      } else
+        return ( ReadFile(V,sizeof(realtype))==sizeof(realtype) );
+    }
+
+    bool  File::ReadFloat ( realtype * V )  {
+    floatUniBin  fUB;
+    float        fV;
+      if (UniBin)  {
+        if (ReadFile(fUB,sizeof(floatUniBin))==sizeof(floatUniBin))  {
+          UniBin2float ( fUB,*V );
+          return true;
+        }
+      } else if (ReadFile(&fV,sizeof(float))==sizeof(float))  {
+        *V = fV;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::ReadInt ( int * I )  {
+    intUniBin  iUB;
+      if (UniBin)  {
+        if (ReadFile(iUB,sizeof(intUniBin))==sizeof(intUniBin))  {
+          UniBin2int ( iUB,*I );
+          return true;
+        } else
+          return false;
+      } else
+        return ( ReadFile(I,sizeof(int))==sizeof(int) );
+    }
+
+    bool  File::ReadShort ( short * S )  {
+    shortUniBin  sUB;
+      if (UniBin)  {
+        if (ReadFile(sUB,sizeof(shortUniBin))==sizeof(shortUniBin))  {
+          UniBin2short ( sUB,*S );
+          return true;
+        } else
+          return false;
+      } else
+        return ( ReadFile(S,sizeof(short))==sizeof(short) );
+    }
+
+    bool  File::ReadLong ( long * L )  {
+    longUniBin  lUB;
+      if (UniBin)  {
+        if (ReadFile(lUB,sizeof(longUniBin))==sizeof(longUniBin))  {
+          UniBin2long ( lUB,*L );
+          return true;
+        } else
+          return false;
+      } else
+        return ( ReadFile(L,sizeof(long))==sizeof(long) );
+    }
+
+    bool  File::ReadBool ( bool * B )  {
+    intUniBin  iUB;
+    int        k;
+      if (UniBin)  {
+        if (ReadFile(iUB,sizeof(intUniBin))==sizeof(intUniBin))  {
+          UniBin2int ( iUB,k );
+          *B = (k!=0);
+          return true;
+        } else
+          return false;
+      } else
+        return ( ReadFile(B,sizeof(bool))==sizeof(bool) );
+    }
+
+    bool  File::ReadByte ( byte * B )  {
+      return ( ReadFile(B,sizeof(byte))==sizeof(byte) );
+    }
+
+    bool  File::ReadWord ( word * W )  {
+    wordUniBin  wUB;
+      if (UniBin)  {
+        if (ReadFile(wUB,sizeof(wordUniBin))==sizeof(wordUniBin))  {
+          UniBin2word ( wUB,*W );
+          return true;
+        } else
+          return false;
+      } else
+        return ( ReadFile(W,sizeof(word))==sizeof(word) );
+    }
+
+    bool  File::AddReal ( realtype * V )  {
+    realtype x;
+      if (ReadReal(&x))  {
+        *V += x;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::AddFloat ( realtype * V )  {
+    realtype x;
+      if (ReadFloat(&x))  {
+        *V += x;
+        return true;
+      }
+      return false;
+    }
+
+
+    bool  File::AddInt ( int * I )  {
+    int k;
+      if (ReadInt(&k))  {
+        *I += k;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::AddShort ( short * S )  {
+    short k;
+      if (ReadShort(&k))  {
+        *S += k;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::AddLong ( long * L )  {
+    long k;
+      if (ReadLong(&k))  {
+        *L += k;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::AddByte ( byte * B )  {
+    byte k;
+      if (ReadByte(&k))  {
+        *B += k;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::AddWord ( word * W )  {
+    word k;
+      if (ReadWord(&k))  {
+        *W += k;
+        return true;
+      }
+      return false;
+    }
+
+    bool  File::WriteVector ( rvector V, int len, int Shift )  {
+    intUniBin  iUB;
+    realUniBin rUB;
+    int        i;
+    int        l = len;
+      if (V==NULL)  l = 0;
+      if (UniBin)  {
+        int2UniBin ( l,iUB );
+        WriteFile ( iUB,sizeof(intUniBin) );
+        for (i=0;i<len;i++)  {
+          real2UniBin ( V[Shift+i],rUB );
+          WriteFile   ( rUB,sizeof(realUniBin) );
+        }
+      } else  {
+        WriteFile ( &l,sizeof(l) );
+        if (l>0)  WriteFile ( &(V[Shift]),sizeof(realtype)*l );
+      }
+      return IOSuccess;
+    }
+
+    bool  File::WriteVector ( ivector iV, int len, int Shift )  {
+    intUniBin  iUB;
+    int        i;
+    int        l = len;
+      if (iV==NULL)  l = 0;
+      if (UniBin)  {
+        int2UniBin ( l,iUB );
+        WriteFile ( iUB,sizeof(intUniBin) );
+        for (i=0;i<len;i++)  {
+          int2UniBin ( iV[Shift+i],iUB );
+          WriteFile  ( iUB,sizeof(intUniBin) );
+        }
+      } else  {
+        WriteFile ( &l,sizeof(l) );
+        if (l>0)  WriteFile ( &(iV[Shift]),sizeof(int)*l );
+      }
+      return IOSuccess;
+    }
+
+    bool  File::WriteVector ( lvector lV, int len, int Shift )  {
+    intUniBin  iUB;
+    longUniBin lUB;
+    int        i;
+    int        l = len;
+      if (lV==NULL)  l = 0;
+      if (UniBin)  {
+        int2UniBin ( l,iUB );
+        WriteFile ( iUB,sizeof(intUniBin) );
+        for (i=0;i<len;i++)  {
+          long2UniBin ( lV[Shift+i],lUB );
+          WriteFile   ( lUB,sizeof(longUniBin) );
+        }
+      } else  {
+        WriteFile ( &l,sizeof(l) );
+        if (l>0)  WriteFile ( &(lV[Shift]),sizeof(long)*l );
+      }
+      return IOSuccess;
+    }
+
+    bool  File::WriteVector ( bvector B, int len, int Shift )  {
+    intUniBin iUB;
+    int       l = len;
+      if (B==NULL)  l = 0;
+      if (UniBin)  {
+        int2UniBin ( l,iUB );
+        WriteFile  ( iUB,sizeof(intUniBin) );
+      } else
+        WriteFile ( &l,sizeof(l) );
+      if (l>0)  WriteFile ( &(B[Shift]),sizeof(byte)*l );
+      return IOSuccess;
+    }
+
+    bool  File::ReadVector ( rvector V, int maxlen, int Shift )  {
+    intUniBin  iUB;
+    realUniBin rUB;
+    int        i,l,ll;
+    realtype   B;
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,l );
+        if (IOSuccess && (l>0))  {
+          ll = IMin(l,maxlen);
+          if (V)
+            for (i=0;i<=ll;i++)  {
+              ReadFile    ( rUB,sizeof(realUniBin) );
+              UniBin2real ( rUB,V[Shift+i] );
+            }
+          for (i=ll+1;i<=l;i++)
+            ReadFile ( rUB,sizeof(realUniBin) );
+        }
+      } else  {
+        ReadFile ( &l,sizeof(l) );
+        if (IOSuccess && (l>0))  {
+          ll = IMin(l,maxlen);
+          if (V)  ReadFile ( &(V[Shift]),sizeof(realtype)*ll );
+          for (i=ll+1;i<=l;i++)  ReadFile ( &B,sizeof(B) );
+        }
+      }
+      return IOSuccess;
+    }
+
+    bool  File::ReadVector ( ivector iV, int maxlen, int Shift )  {
+    intUniBin  iUB;
+    int        i,l,ll,iB;
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,l );
+        if (IOSuccess && (l>0))  {
+          ll = IMin(l,maxlen);
+          if (iV)
+            for (i=0;i<=ll;i++)  {
+              ReadFile   ( iUB,sizeof(intUniBin) );
+              UniBin2int ( iUB,iV[Shift+i]       );
+            }
+          for (i=ll+1;i<=l;i++)
+            ReadFile ( iUB,sizeof(intUniBin) );
+        }
+      } else  {
+        ReadFile ( &l,sizeof(l) );
+        if (IOSuccess && (l>0))  {
+          ll = IMin(l,maxlen);
+          if (iV)  ReadFile ( &(iV[Shift]),sizeof(int)*ll );
+          for (i=ll+1;i<=l;i++)  ReadFile ( &iB,sizeof(iB) );
+        }
+      }
+      return IOSuccess;
+    }
+
+    bool  File::ReadVector ( lvector lV, int maxlen, int Shift )  {
+    intUniBin  iUB;
+    longUniBin lUB;
+    int        i,l,ll;
+    long       lB;
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,l );
+        if (IOSuccess && (l>0))  {
+          ll = IMin(l,maxlen);
+          if (lV)
+            for (i=0;i<=ll;i++)  {
+              ReadFile    ( lUB,sizeof(longUniBin) );
+              UniBin2long ( lUB,lV[Shift+i]       );
+            }
+          for (i=ll+1;i<=l;i++)
+            ReadFile ( lUB,sizeof(longUniBin) );
+        }
+      } else  {
+        ReadFile ( &l,sizeof(l) );
+        if (IOSuccess && (l>0))  {
+          ll = IMin(l,maxlen);
+          if (lV)  ReadFile ( &(lV[Shift]),sizeof(long)*ll );
+          for (i=ll+1;i<=l;i++)  ReadFile ( &lB,sizeof(lB) );
+        }
+      }
+      return IOSuccess;
+    }
+
+    bool  File::ReadVector ( bvector B, int maxlen, int Shift )  {
+    intUniBin  iUB;
+    int        i,l,ll;
+    byte       t;
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,l );
+      } else
+        ReadFile ( &l,sizeof(l) );
+      if (IOSuccess && (l>0))  {
+        ll = IMin(l,maxlen);
+        if (B)  ReadFile ( &(B[Shift]),sizeof(byte)*ll );
+        for (i=ll+1;i<=l;i++)  ReadFile ( &t,sizeof(t) );
+      }
+      return IOSuccess;
+    }
+
+    bool  File::CreateReadVector ( rvector & V, int & len,
+                                       int Shift )  {
+    intUniBin  iUB;
+    realUniBin rUB;
+    int        i;
+    realtype   B;
+      FreeVectorMemory ( V,Shift );
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,len );
+        if (IOSuccess && (len>0))  {
+          GetVectorMemory ( V,len,Shift );
+          if (V)
+            for (i=0;i<len;i++)  {
+              ReadFile    ( rUB,sizeof(realUniBin) );
+              UniBin2real ( rUB,V[Shift+i] );
+            }
+          else for (i=0;i<len;i++)
+            ReadFile ( rUB,sizeof(realUniBin) );
+        }
+      } else  {
+        ReadFile ( &len,sizeof(len) );
+        if (IOSuccess && (len>0))  {
+          GetVectorMemory ( V,len,Shift );
+          if (V)  ReadFile ( &(V[Shift]),sizeof(realtype)*len );
+            else for (i=0;i<len;i++)
+                   ReadFile ( &B,sizeof(B) );
+        }
+      }
+      return IOSuccess;
+    }
+
+    bool  File::CreateReadVector ( rvector & V, int Shift )  {
+    int len;
+      return CreateReadVector ( V,len,Shift );
+    }
+
+    bool  File::CreateReadVector ( ivector & iV, int & len,
+                                       int Shift )  {
+    intUniBin  iUB;
+    int        i,iB;
+      FreeVectorMemory ( iV,Shift );
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,len );
+        if (IOSuccess && (len>0))  {
+          GetVectorMemory ( iV,len,Shift );
+          if (iV)
+            for (i=0;i<len;i++)  {
+              ReadFile   ( iUB,sizeof(intUniBin) );
+              UniBin2int ( iUB,iV[Shift+i]       );
+            }
+          else for (i=0;i<len;i++)
+            ReadFile ( iUB,sizeof(intUniBin) );
+        }
+      } else  {
+        ReadFile ( &len,sizeof(len) );
+        if (IOSuccess && (len>0))  {
+          GetVectorMemory ( iV,len,Shift );
+          if (iV)  ReadFile ( &(iV[Shift]),sizeof(int)*len );
+             else for (i=0;i<len;i++)
+                    ReadFile ( &iB,sizeof(iB) );
+        }
+      }
+      return IOSuccess;
+    }
+
+    bool  File::CreateReadVector ( ivector & iV, int Shift )  {
+    int len;
+      return CreateReadVector ( iV,len,Shift );
+    }
+
+    bool  File::CreateReadVector ( lvector & lV, int & len,
+                                       int Shift )  {
+    intUniBin  iUB;
+    longUniBin lUB;
+    int        i;
+    long       lB;
+      FreeVectorMemory ( lV,Shift );
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,len );
+        if (IOSuccess && (len>0))  {
+          GetVectorMemory ( lV,len,Shift );
+          if (lV)
+            for (i=0;i<len;i++)  {
+              ReadFile    ( lUB,sizeof(intUniBin) );
+              UniBin2long ( lUB,lV[Shift+i]       );
+            }
+          else for (i=0;i<len;i++)
+            ReadFile ( lUB,sizeof(longUniBin) );
+        }
+      } else  {
+        ReadFile ( &len,sizeof(len) );
+        if (IOSuccess && (len>0))  {
+          GetVectorMemory ( lV,len,Shift );
+          if (lV) ReadFile ( &(lV[Shift]),sizeof(long)*len );
+             else for (i=0;i<len;i++)
+                    ReadFile ( &lB,sizeof(lB) );
+        }
+      }
+      return IOSuccess;
+    }
+
+    bool  File::CreateReadVector ( lvector & lV, int Shift )  {
+    int len;
+      return CreateReadVector ( lV,len,Shift );
+    }
+
+
+    bool  File::CreateReadVector ( bvector & B, int & len,
+                                       int Shift )  {
+    intUniBin  iUB;
+    int        i;
+    byte       t;
+      FreeVectorMemory ( B,Shift );
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,len );
+      } else
+        ReadFile ( &len,sizeof(len) );
+      if (IOSuccess && (len>0))  {
+        GetVectorMemory ( B,len,Shift );
+        if (B)  ReadFile ( &(B[Shift]),sizeof(byte)*len );
+          else for (i=0;i<len;i++)
+                 ReadFile ( &t,sizeof(t) );
+      }
+      return IOSuccess;
+    }
+
+    bool  File::CreateReadVector ( bvector & B, int Shift )  {
+    int len;
+      return CreateReadVector ( B,len,Shift );
+    }
+
+
+    bool  File::WriteMatrix ( rmatrix & A, int N, int M,
+                                  int ShiftN, int ShiftM )  {
+    intUniBin  iUB;
+    realUniBin rUB;
+    int        i,j;
+      if (UniBin)  {
+        if (!A)  {
+          i = 0;
+          int2UniBin ( i,iUB );
+          WriteFile  ( iUB,sizeof(intUniBin) );
+        } else  {
+          int2UniBin ( N,iUB );
+          WriteFile  ( iUB,sizeof(intUniBin) );
+          int2UniBin ( M,iUB );
+          WriteFile  ( iUB,sizeof(intUniBin) );
+          for (i=0;i<N;i++)
+            for (j=0;j<M;j++)  {
+              real2UniBin ( A[ShiftN+i][ShiftM+j],rUB );
+              WriteFile   ( rUB,sizeof(realUniBin) );
+            }
+        }
+      } else if (!A) {
+        i = 0;
+        WriteFile ( &i,sizeof(i) );
+      } else  {
+        WriteFile ( &N,sizeof(N) );
+        WriteFile ( &M,sizeof(M) );
+        for (i=0;i<N;i++)
+          WriteFile ( &(A[ShiftN][ShiftM]),sizeof(realtype)*M );
+      }
+      return IOSuccess;
+    }
+
+    bool  File::CreateReadMatrix ( rmatrix & A, int ShiftN,
+                                       int ShiftM )  {
+    int N,M;
+      return CreateReadMatrix ( A,N,M,ShiftN,ShiftM );
+    }
+
+    bool  File::CreateReadMatrix ( rmatrix & A, int & N, int & M,
+                                       int ShiftN, int ShiftM )  {
+    intUniBin  iUB;
+    realUniBin rUB;
+    int        i,j;
+      FreeMatrixMemory ( A,N,ShiftN,ShiftM );
+      if (UniBin)  {
+        ReadFile   ( iUB,sizeof(intUniBin) );
+        UniBin2int ( iUB,N );
+        if (IOSuccess && (N>0))  {
+          ReadFile   ( iUB,sizeof(intUniBin) );
+          UniBin2int ( iUB,M );
+          if (IOSuccess && (M>0))  {
+            GetMatrixMemory ( A,N,M,ShiftN,ShiftM );
+            for (i=0;i<N;i++)
+              for (j=0;j<M;j++)  {
+                ReadFile    ( rUB,sizeof(realUniBin) );
+                UniBin2real ( rUB,A[ShiftN+i][ShiftM+j] );
+              }
+          }
+        }
+      } else  {
+        ReadFile ( &N,sizeof(N) );
+        if (N>0)  {
+          ReadFile ( &M,sizeof(M) );
+          if (M>0)  {
+            GetMatrixMemory ( A,N,M,ShiftN,ShiftM );
+            for (i=0;i<N;i++)
+              ReadFile ( &(A[ShiftN][ShiftM]),sizeof(realtype)*M );
+          }
+        }
+      }
+      return IOSuccess;
+    }
+
+
+    bool  File::WriteColumns ( rvector X, rvector Y, rvector Z,
+                                   int len, int Shift, int MLength )  {
+    //   WriteColumns writes data stored in X, Y and Z in the form
+    // of columns, adding a blank line in the end. If Z (or Z and Y)
+    // are set to NULL, then only X and Y (or only X) are written.
+    //   Shift corresponds to the begining of arrays' enumeration
+    // X[Shift..Shift+len-1].
+    int  i,l;
+      l = Shift+len;
+      for (i=Shift;i<l;i++)  {
+        Write ( pstr("   ")  );
+        Write ( X[i],MLength );
+        if (Y)  {
+          Write ( pstr(",   ") );
+          Write ( Y[i],MLength );
+        }
+        if (Z)  {
+          Write ( pstr(",   ") );
+          Write ( Z[i],MLength );
+        }
+        LF();
+      }
+      return LF();
+    }
+
+    bool  File::WriteColumns ( rvector X, rvector Y,
+                                   int len, int Shift, int MLength )  {
+      return WriteColumns ( X,Y,NULL,len,Shift,MLength );
+    }
+
+    int  File::ReadColumns ( int maxlen, rvector X, rvector Y, rvector Z,
+                              int xCol, int yCol, int zCol, int Shift )  {
+    //   ReadColumns reads data stored by WriteColumns. X, Y, and Z must
+    // be allocated prior to call.
+    //   xCol, yCol and zCol specify the order number of columns
+    // (starting from 0) to be read into X, Y and Z, correspondingly.
+    // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+    //   Shift corresponds to the begining of arrays' enumeration
+    // X[Shift..Shift+len-1].
+    //   Returns number of lines read.
+    int   DataLen;
+    char  S[1025];
+      DataLen = maxlen;
+      _ReadColumns ( DataLen,S,sizeof(S),X,Y,Z,xCol,yCol,zCol,Shift );
+      return DataLen;
+    }
+
+    int  File::ReadColumns ( int maxlen, rvector X, rvector Y,
+                              int xCol, int yCol, int Shift )  {
+      return  ReadColumns ( maxlen,X,Y,NULL,xCol,yCol,-1,Shift );
+    }
+
+
+    int  File::CreateReadColumns ( rvector & X, rvector & Y, rvector & Z,
+                                    int xCol, int yCol, int zCol,
+                                    int Shift )  {
+    //   ReadColumns reads data stored by WriteColumns. X, Y, and Z
+    // must be set to NULL prior to call. They will be allocated
+    // within the procedure.
+    //   xCol, yCol and zCol specify the order number of columns
+    // (starting from 0) to be read into X, Y and Z, correspondingly.
+    // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+    //   Shift corresponds to the begining of arrays' enumeration
+    // X[Shift..Shift+len-1].
+    //   Returns number of lines read, errors are reported by ErrorCode().
+    int      i,j,DataLen;
+    char     S[1025];
+    bool  Ok;
+      DataLen = 0;
+      ErrCode = 0;
+      if (!FileEnd())  {
+        i = 0;
+        j = 1;
+        // the loop terminates at first blank line
+        while ((i<j) && (!FileEnd()))  {
+          j = ReadLine ( S,sizeof(S) );
+          i = 0;
+          // check for blank line
+          while ((i<j) && (S[i]==' '))  i++;
+          DataLen++;
+        }
+        if (i>=j)  DataLen--;
+        if (DataLen>0)  {
+          Ok = GetVectorMemory(X,DataLen,Shift);
+          if (Ok && (yCol>=0))
+            Ok = Ok && GetVectorMemory(Y,DataLen,Shift);
+          if (Ok && (zCol>=0))
+            Ok = Ok && GetVectorMemory(Z,DataLen,Shift);
+          if (Ok)  {
+            reset();
+            _ReadColumns ( DataLen,S,sizeof(S),X,Y,Z,xCol,yCol,
+                           zCol,Shift );
+          } else  ErrCode = FileError_NoMemory;
+        } else  ErrCode = FileError_NoDataFound;
+      } else  ErrCode = FileError_NoDataFound;
+      return DataLen;
+    }
+
+    int  File::CreateReadColumns ( rvector & X, rvector & Y,
+                                    int xCol, int yCol, int Shift )  {
+      return  CreateReadColumns ( X,Y,X,xCol,yCol,-1,Shift );
+    }
+
+    void  File::_ReadColumns ( int & DLen, pstr S, int SLen,
+                                rvector X, rvector Y, rvector Z,
+                                int xCol, int yCol, int zCol,
+                                int Shift )  {
+    int      i,is,j,k,m,n,cmax;
+    char     SV[256];
+    realtype Res;
+      ErrCode = 0;
+      i       = 0;
+      cmax    = IMax(zCol,IMax(xCol,yCol));
+      while ((i<DLen) && (ErrCode==0))  {
+        k = ReadLine ( S,SLen );
+        RemoveDelimiters(S,k);
+        j = 0;
+        m = -1;
+        n = 0;
+        while ((m<cmax) && (ErrCode==0))  {
+          do {
+            PickOutNumber ( S,SV,k,j );
+            if ((m<0) && (SV[0]==char(0)) && (j>=k))  {
+              DLen = i;
+              return;
+            }
+            m++;
+          } while ((m!=xCol) && (m!=yCol) && (m!=zCol));
+          if (SV[0]==char(0))  {
+            if (n>0)  ErrCode = FileError_NoColumn;
+                else  ErrCode = FileError_ShortData;
+          } else  {
+            Res = GetNumber ( SV );
+            if (ErrCode==0)  {
+              is = i+Shift;
+              if      (m==xCol)  X[is] = Res;
+              else if (m==yCol)  Y[is] = Res;
+                           else  Z[is] = Res;
+              n++;
+            }
+          }
+        }
+        if ((ErrCode==0) && (n<2))  ErrCode = FileError_NoColumn;
+        i++;
+      }
+      if ((ErrCode==FileError_ShortData) && (i>1))  {
+        ErrCode = 0;
+        DLen    = i-1;
+      }
+      if (ErrCode!=0)  ErrCode = FileError_BadData;
+    }
+
+    void  RemoveDelimiters ( pstr S, int SLen )  {
+    int j;
+      for (j=0;j<SLen;j++)
+        if ((S[j]==',') || (S[j]==';') ||
+            (S[j]==':') || (S[j]==char(9)))
+          S[j] = ' ';
+    }
+
+    void  PickOutNumber ( cpstr S, pstr SV, int SLen, int & j )  {
+    int l;
+      l = 0;
+      while ((j<SLen) && (S[j]==' '))  j++;
+      if ((S[j]=='+') || (S[j]=='-'))  SV[l++] = S[j++];
+      if (S[j]=='.')                   SV[l++] = '0';
+      while ((j<SLen) && (S[j]!=' '))  SV[l++] = S[j++];
+      SV[l] = char(0);
+    }
+
+    realtype  File::GetNumber ( cpstr S )  {
+    char *   endptr;
+    realtype V;
+      V = strtod ( S,&endptr );
+      if ((*endptr!=' ') && (*endptr))
+        ErrCode = FileError_BadData;
+      return V;
+    }
+
+    cpstr FileError ( int ErrCode )  {
+      switch (ErrCode)  {
+        case 0                      : return "Ok";
+        case FileError_NoMemory     : return "Insufficient memory";
+        case FileError_NoDataFound  : return "No data found";
+        case FileError_NoColumn     : return "No column structure";
+        case FileError_BadData      : return "Incorrect data format";
+        case FileError_WrongMemoryAllocation
+                                    : return "Wrong Memory Allocation";
+        default : return "Unknown I/O error";
+      }
+    }
+
+ }
+
+}
diff --git a/mmdb2/mmdb_io_file.h b/mmdb2/mmdb_io_file.h
new file mode 100644
index 0000000..726666e
--- /dev/null
+++ b/mmdb2/mmdb_io_file.h
@@ -0,0 +1,301 @@
+//  $Id: mmdb_io_file.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    11.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  file_  <interface>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::io::File  - file I/O Support.
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef  __MMDB_IO_File__
+#define  __MMDB_IO_File__
+
+#include <stdio.h>
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  namespace io  {
+
+    //  ========================  File Class  ========================
+
+    enum GZ_MODE  {
+      GZM_NONE             = 0,
+      GZM_CHECK            = 1,
+      GZM_ENFORCE          = 2,
+      GZM_ENFORCE_GZIP     = 2,
+      GZM_ENFORCE_COMPRESS = 3
+    };
+
+    enum FILE_ERROR  {
+      FileError_NoMemory              = 110,
+      FileError_ShortData             = 111,
+      FileError_NoDataFound           = 112,
+      FileError_NoColumn              = 113,
+      FileError_BadData               = 114,
+      FileError_WrongMemoryAllocation = 115
+    };
+
+    enum SYSKEY  {
+      syskey_unix = 1,
+      syskey_win  = 2,
+      syskey_all  = 3
+    };
+
+    extern const char _dir_sep_c;
+    extern cpstr      _dir_sep;
+
+    // ===================  Auxilary Functions  ========================
+
+
+    extern cpstr GetFPath  ( pstr  FilePath, SYSKEY syskey=syskey_unix );
+    extern cpstr GetFName  ( cpstr FilePath, SYSKEY syskey=syskey_unix );
+    extern cpstr GetFExt   ( cpstr FilePath );
+    extern cpstr ChangeExt ( pstr  FilePath, cpstr newExt,
+                                             SYSKEY syskey=syskey_unix );
+    extern cpstr FileError        ( int   ErrCode     );
+    extern void  RemoveDelimiters ( pstr  S, int SLen );
+    extern void  PickOutNumber    ( cpstr S, pstr SV, int SLen, int & j );
+
+
+    // ==========================  File  ===============================
+
+    DefineClass(File);
+
+    class  File  {
+
+      public :
+
+        File ( word BufSize=4096 );
+        virtual  ~File();
+
+        // ---- control functions
+        //   FileName allows for "stdin", "stdout" and "stderr" as
+        // for standard UNIX streams.
+        void  assign      ( cpstr   FileName,
+                            bool    Text=false,
+                            bool    UniB=false,
+                            GZ_MODE gzMode=GZM_NONE );
+        //   assign for memory IO
+        void  assign      ( word poolSize, word sizeInc, pstr filePool );
+        void  GetFilePool ( pstr & filePool, word & fileSize );
+
+        inline cpstr FileName() { return FName; }
+        bool  reset       ( bool ReadOnly=false, int retry=0 );
+                                // = true if opened, each retry 1 sec sleep
+        bool  erase       ();   // = true if erased
+        bool  exists      ();   // = true if exists
+        bool  parse       ( cpstr FileName    ); // true if filled
+        bool  rename      ( cpstr NewFileName ); // true if renamed
+        bool  rewrite     ();    // = true if opened
+        bool  append      ();    // = true if opened
+        bool  isOpen      ();
+        long  Position    ();
+        inline long  FileLength  () { return FLength; }
+        bool  seek        ( long Position );
+        bool  FileEnd     ();
+        inline bool  Success   () { return IOSuccess; }
+        inline void  SetSuccess() { IOSuccess = true; }
+        void  flush       ();
+        void  shut        ();
+
+        // ---- binary I/O
+        word  ReadFile     ( void * Buffer, word Count );
+        word  CreateRead   ( pstr & Line );
+        word  ReadTerLine  ( pstr  Line, bool longLine=false );
+        bool  WriteFile    ( const void * Buffer, word Count );
+        bool  CreateWrite  ( cpstr Line );
+        bool  WriteTerLine ( cpstr Line, bool longLine=false );
+
+        //  machine-independent binary I/O
+        bool  WriteReal   ( realtype * V );
+        bool  WriteFloat  ( realtype * V );
+        bool  WriteInt    ( int      * I );
+        bool  WriteShort  ( short    * S );
+        bool  WriteLong   ( long     * L );
+        bool  WriteBool   ( bool     * B );
+        bool  WriteByte   ( byte     * B );
+        bool  WriteWord   ( word     * W );
+        bool  ReadReal    ( realtype * V );
+        bool  ReadFloat   ( realtype * V );
+        bool  ReadInt     ( int      * I );
+        bool  ReadShort   ( short    * S );
+        bool  ReadLong    ( long     * L );
+        bool  ReadBool    ( bool     * B );
+        bool  ReadByte    ( byte     * B );
+        bool  ReadWord    ( word     * B );
+        bool  AddReal     ( realtype * V );
+        bool  AddFloat    ( realtype * V );
+        bool  AddInt      ( int      * I );
+        bool  AddShort    ( short    * S );
+        bool  AddLong     ( long     * L );
+        bool  AddByte     ( byte     * B );
+        bool  AddWord     ( word     * B );
+
+        //  complex data binary I/O
+        bool  WriteVector      ( rvector    V, int len,    int Shift );
+        bool  WriteVector      ( ivector   iV, int len,    int Shift );
+        bool  WriteVector      ( lvector   lV, int len,    int Shift );
+        bool  WriteVector      ( bvector    B, int len,    int Shift );
+        bool  ReadVector       ( rvector    V, int maxlen, int Shift );
+        bool  ReadVector       ( ivector   iV, int maxlen, int Shift );
+        bool  ReadVector       ( lvector   lV, int maxlen, int Shift );
+        bool  ReadVector       ( bvector    B, int maxlen, int Shift );
+        bool  CreateReadVector ( rvector &  V, int & len,  int Shift );
+        bool  CreateReadVector ( ivector & iV, int & len,  int Shift );
+        bool  CreateReadVector ( lvector & lV, int & len,  int Shift );
+        bool  CreateReadVector ( bvector &  B, int & len,  int Shift );
+        bool  CreateReadVector ( rvector &  V, int Shift );
+        bool  CreateReadVector ( ivector & iV, int Shift );
+        bool  CreateReadVector ( lvector & lV, int Shift );
+        bool  CreateReadVector ( bvector &  B, int Shift );
+        bool  WriteMatrix      ( rmatrix & A,  int N, int M,
+                                    int  ShiftN,  int ShiftM );
+        bool  CreateReadMatrix ( rmatrix & A,  int ShiftN, int ShiftM );
+        bool  CreateReadMatrix ( rmatrix & A,  int & N, int & M,
+                                    int ShiftN, int ShiftM );
+
+        /// ---- text I/O
+        bool  Write       ( cpstr  Line );     //!< writes without LF
+        bool  Write       ( realtype V, int length=10 ); //!< w/o LF
+        bool  Write       ( int     iV, int length=5  ); //!< w/o LF
+        bool  WriteLine   ( cpstr  Line );     //!< writes and adds LF
+        bool  LF          ();                  //!< just adds LF
+        word  ReadLine    ( pstr   Line, word MaxLen=255 );
+        word  ReadNonBlankLine ( pstr S, word MaxLen=255 );
+
+        ///  complex data text I/O
+
+        // writes with spaces and adds LF
+        bool  WriteDataLine  ( realtype X, realtype Y, int length=10 );
+
+        bool  WriteParameter ( cpstr S, realtype X, // writes parameter
+                               int ParColumn=40,    // name S and value X
+                               int length=10 );     // at column ParColumn
+                                                    // and adds LF.
+
+        bool  WriteParameters ( cpstr S, int n_X, // writes parameter
+                                rvector X,      // name S and n_X values
+                                int ParColumn=40, // X[0..n_X-1] at col
+                                int length=10 );  // ParColumn, ads LF.
+
+        bool  ReadParameter  ( pstr S, realtype & X, // reads parameter
+                               int ParColumn=40 );   // name S and val X
+        bool  ReadParameter  ( pstr S, int & X,
+                               int ParColumn=40 );
+
+        bool  ReadParameters ( pstr S, int & n_X,  // reads parameter
+                               rvector X,          // name S, counts the
+                               int MaxLen=255,     // of values n_X and
+                               int ParColumn=40 ); // reads X[0..n_X-1].
+                                                  // MaxLen gives sizeof(S)
+
+        //   WriteColumns writes data stored in X, Y and Z in the form
+        // of columns, adding a blank line in the end. If Z (or Z and Y)
+        // are set to NULL, then only X and Y (or only X) are written.
+        //   Shift corresponds to the begining of arrays' enumeration
+        // X[Shift..Shift+len-1].
+        bool  WriteColumns ( rvector X, rvector Y, rvector Z,
+                             int len, int Shift, int MLength );
+        bool  WriteColumns ( rvector X, rvector Y,
+                             int len, int Shift, int MLength );
+
+        //   ReadColumns reads data stored by WriteColumns. X, Y, and Z
+        // must be allocated prior to call.
+        //   xCol, yCol and zCol specify the order number of columns
+        // (starting from 0) to be read into X, Y and Z, correspondingly.
+        // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+        //   Shift corresponds to the begining of arrays' enumeration
+        // X[Shift..Shift+len-1].
+        //   Returns number of lines read.
+        int   ReadColumns  ( int maxlen, rvector X, rvector Y, rvector Z,
+                             int xCol, int yCol, int zCol, int Shift );
+        int   ReadColumns  ( int maxlen, rvector X, rvector Y,
+                             int xCol, int yCol, int Shift );
+
+        //   CreateReadColumns reads data stored by WriteColumns. X, Y,
+        // and Z must be set to NULL prior to call. They will be allocated
+        // within the procedure.
+        //   xCol, yCol and zCol specify the order number of columns
+        // (starting from 0) to be read into X, Y and Z, correspondingly.
+        // If zCol (or zCol and yCol) < 0 then Z (or Z and Y) are not read.
+        //   Shift corresponds to the begining of arrays' enumeration
+        // X[Shift..Shift+len-1].
+        //   Returns number of lines read, errors are reported by
+        // ErrorCode().
+        int  CreateReadColumns ( rvector & X, rvector & Y, rvector & Z,
+                                 int xCol, int yCol, int zCol, int Shift );
+        int  CreateReadColumns ( rvector & X, rvector & Y,
+                                 int xCol, int yCol, int Shift );
+
+        // ---- miscellaneous
+        realtype GetNumber ( cpstr S );
+        FILE *   GetHandle () { return hFile; }
+
+      protected :
+        word    Buf_Size;
+        bool    TextMode,UniBin;
+        GZ_MODE gzipMode;
+        pstr    IOBuf;
+        word    BufCnt,BufLen,BufInc;
+        FILE *  hFile;
+        bool    EofFile;
+        pstr    FName;
+        long    FLength;
+        bool    IOSuccess;
+        int     ErrCode;
+
+        void  FreeBuffer   ();
+        void  _ReadColumns ( int & DLen, pstr S, int SLen,
+                             rvector X, rvector Y, rvector Z,
+                             int xCol, int yCol, int zCol, int Shift );
+
+      private :
+        int   gzipIO;
+        bool  StdIO,memIO;
+
+    };
+
+
+    extern void SetGZIPPath     ( pstr gzipPath,     pstr ungzipPath     );
+    extern void SetCompressPath ( pstr compressPath, pstr uncompressPath );
+
+    extern bool FileExists      ( cpstr FileName, PFile f=NULL );
+
+  }
+
+}
+
+
+#endif
+
diff --git a/mmdb2/mmdb_io_stream.cpp b/mmdb2/mmdb_io_stream.cpp
new file mode 100644
index 0000000..4dbdd46
--- /dev/null
+++ b/mmdb2/mmdb_io_stream.cpp
@@ -0,0 +1,112 @@
+//  $Id: mmdb_io_stream.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    11.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  Stream_ <interface>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::io::Stream  ( Basic Stream Class )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 1995-2013
+//
+//  =================================================================
+//
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb  {
+
+  namespace io  {
+
+    //  ==========================  CStream  ===========================
+
+    //     Each streamable class should be derived from Stream
+    //  and have constructor Class(PStream & Object), which should
+    //  initialize all memory of the class, and virtual functions
+    //  read(..) and write(..) (see below). Constructor Class(PStream&)
+    //  must not touch the Object variable. This constructor is used
+    //  only once just before read(..) function. It is assumed that
+    //  read/write functions of Class provide storage/reading of
+    //  all vital data. Function read(..) must read data in exactly
+    //  the same way as function write(..) stores it.
+    //     For using Class in streams, three following functions should
+    //  be supplied:
+    //
+    //     1.
+    //     void StreamWrite ( RFile f, RPClass Object )  {
+    //       StreamWrite ( f,(PStream)PClass );
+    //     }
+    //
+    //     2.
+    //     PCStream ClassInit ( RPStream Object )  {
+    //       return (PStream)(new Class(Object));
+    //     }
+    //
+    //     3.
+    //     void StreamRead ( RFile f, RPClass Object )  {
+    //       StreamRead_ ( f,(PStream)Object,ClassInit );
+    //     }
+    //
+    //    All these functions are automatically generated by macros
+    //  DefineStreamFunctions(CClass) -- in the header -- and
+    //  MakeStreamFunctions(CClass) -- in the implementation body.
+    //  Then CClass may be streamed in/out using functions #1 and #3.
+    //    StreamRead will return NULL for Object if it was not
+    //  in the stream. If Object existed before StreamRead(..) but
+    //  was not found in the stream, it will be disposed.
+
+    void StreamRead_ ( RFile f, RPStream Object,
+                       InitStreamObject Init )  {
+    int i;
+      f.ReadInt ( &i );
+      if (i)  {
+        if (!Object)
+          Object = Init(Object); //Object = new CStream ( Object );
+        Object->read ( f );
+      } else  {
+        if (Object)  delete Object;
+        Object = NULL;
+      }
+    }
+
+    void StreamWrite_ ( RFile f, RPStream Object )  {
+    int i;
+      if (Object)  {
+        i = 1;
+        f.WriteInt ( &i );
+        Object->write ( f );
+      } else  {
+        i = 0;
+        f.WriteInt ( &i );
+      }
+    }
+
+    MakeStreamFunctions(Stream)
+
+  }
+
+}
diff --git a/mmdb2/mmdb_io_stream.h b/mmdb2/mmdb_io_stream.h
new file mode 100644
index 0000000..689b37f
--- /dev/null
+++ b/mmdb2/mmdb_io_stream.h
@@ -0,0 +1,193 @@
+//  $Id: mmdb_io_stream.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    11.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  Stream <interface>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::io::Stream ( Basic Stream Class )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 1995-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_IO_Stream__
+#define __MMDB_IO_Stream__
+
+#include "mmdb_io_file.h"
+
+//  *******************************************************************
+
+#ifndef __ClassMacros
+
+# define __ClassMacros
+
+ //  A Class definition macros
+# define DefineClass(ClassName)             \
+   class ClassName;                         \
+   typedef ClassName    * P##ClassName;     \
+   typedef ClassName    & R##ClassName;     \
+   typedef P##ClassName * PP##ClassName;    \
+   typedef P##ClassName & RP##ClassName;
+
+ //  A Structure definition macros
+# define DefineStructure(StructureName)             \
+   struct StructureName;                            \
+   typedef StructureName    * P##StructureName;     \
+   typedef StructureName    & R##StructureName;     \
+   typedef P##StructureName * PP##StructureName;    \
+   typedef P##StructureName & RP##StructureName;
+
+#endif
+
+
+#define  DefineStreamFunctions(ClassName)                              \
+  extern void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object ); \
+  extern void StreamRead  ( mmdb::io::RFile f, RP##ClassName Object );
+
+
+#define  MakeStreamFunctions(ClassName)                                \
+  void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object )  {      \
+    StreamWrite_ ( f,(mmdb::io::RPStream)Object );                     \
+  }                                                                    \
+  mmdb::io::PStream StreamInit##ClassName ( mmdb::io::RPStream Object ) { \
+    return (mmdb::io::PStream)(new ClassName(Object));                 \
+  }                                                                    \
+  void StreamRead ( mmdb::io::RFile f, RP##ClassName Object )  {       \
+    StreamRead_ ( f,(mmdb::io::RPStream)Object,StreamInit##ClassName );\
+  }
+
+#define  DefineFactoryFunctions(ClassName)                             \
+  typedef P##ClassName      Make##ClassName();                         \
+  typedef Make##ClassName * PMake##ClassName;                          \
+  typedef P##ClassName  StreamMake##ClassName ( mmdb::io::RPStream Object ); \
+  P##ClassName  new##ClassName ();                                     \
+  P##ClassName  streamNew##ClassName ( mmdb::io::RPStream Object );    \
+  typedef StreamMake##ClassName * PStreamMake##ClassName;              \
+  extern void SetMakers##ClassName ( void * defMk, void * streamMk );  \
+  extern void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object ); \
+  extern void StreamRead  ( mmdb::io::RFile f, RP##ClassName Object );
+
+
+#define  MakeFactoryFunctions(ClassName)                               \
+  static PMake##ClassName       make##ClassName       = NULL;          \
+  static PStreamMake##ClassName streamMake##ClassName = NULL;          \
+  P##ClassName new##ClassName()  {                                     \
+    if (make##ClassName)  return (*make##ClassName)();                 \
+                    else  return new ClassName();                      \
+  }                                                                    \
+  P##ClassName streamNew##ClassName ( mmdb::io::RPStream Object )  {   \
+    if (streamMake##ClassName)                                         \
+          return (*streamMake##ClassName)(Object);                     \
+    else  return new ClassName(Object);                                \
+  }                                                                    \
+  void SetMakers##ClassName ( void * defMk, void * streamMk )  {       \
+    make##ClassName       = PMake##ClassName(defMk);                   \
+    streamMake##ClassName = PStreamMake##ClassName(streamMk);          \
+  }                                                                    \
+  void StreamWrite ( mmdb::io::RFile f, RP##ClassName Object )  {      \
+    StreamWrite_ ( f,(mmdb::io::RPStream)Object );                     \
+  }                                                                    \
+  mmdb::io::PStream StreamInit##ClassName ( mmdb::io::RPStream Object ) { \
+    return (mmdb::io::PStream)(streamNew##ClassName(Object));          \
+  }                                                                    \
+  void StreamRead ( mmdb::io::RFile f, RP##ClassName Object )  {       \
+    StreamRead_ ( f,(mmdb::io::RPStream)Object,StreamInit##ClassName ); \
+  }
+
+namespace mmdb  {
+
+  namespace io  {
+
+    //  ==========================  Stream  ===========================
+
+    //     Each streamable class should be derived from Stream
+    //  and have constructor Class(PStream & Object), which should
+    //  initialize all memory of the class, and virtual functions
+    //  read(..) and write(..) (see below). Constructor Class(PStream&)
+    //  must not touch the Object variable. This constructor is used
+    //  only once just before the read(..) function. It is assumed that
+    //  read(..)/write(..) functions of the Class provide storage/reading
+    //  of  all vital data. Function read(..) must read data in exactly
+    //  the same way as function write(..) stores it.
+    //     For using Class in streams, three following functions should
+    //  be supplied:
+    //
+    //     1.
+    //     void StreamWrite ( File & f, PClass & Object )  {
+    //       StreamWrite ( f,(PStream)Object );
+    //     }
+    //
+    //     2.
+    //     PStream ClassInit ( PStream & Object )  {
+    //       return (PStream)(new Class(Object));
+    //     }
+    //
+    //     3.
+    //     void StreamRead ( File & f, PClass & Object )  {
+    //       StreamRead_ ( f,(PStream)Object,ClassInit );
+    //     }
+    //
+    //    All these functions are automatically generated by macros
+    //  DefineStreamFunctions(Class) -- in the header -- and
+    //  MakeStreamFunctions(Class) -- in the implementation body. Note
+    //  that macro DefineClass(Class) should always be issued for
+    //  streamable classes prior to the stream-making macros. Then
+    //  Class may be streamed using functions #1 and #3.
+    //    StreamRead will return NULL for Object if it was not in
+    //  the stream. If Object existed before calling StreamRead(..)
+    //  but was not found in the stream, it will be disposed (NULL
+    //  assigned).
+
+
+    DefineClass(Stream);
+    DefineStreamFunctions(Stream);
+
+    class Stream  {
+      public :
+        Stream            ()           {}
+        Stream            ( RPStream ) {}
+        virtual ~Stream   ()           {}
+        virtual void read  ( RFile )   {}
+        virtual void write ( RFile )   {}
+    };
+
+
+    typedef PStream InitStreamObject(RPStream Object);
+
+    extern  void StreamRead_  ( RFile f, RPStream Object,
+                                         InitStreamObject Init );
+
+    extern  void StreamWrite_ ( RFile f, RPStream Object );
+
+
+  }
+
+}
+
+#endif
diff --git a/mmdb2/mmdb_machine_.cpp b/mmdb2/mmdb_machine_.cpp
new file mode 100644
index 0000000..fb50378
--- /dev/null
+++ b/mmdb2/mmdb_machine_.cpp
@@ -0,0 +1,155 @@
+//  $Id: mmdb_machine.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   Machine  <interface>
+//       ~~~~~~~~~
+//  **** Functions : mmdb::machine::GetMachineID   - returns ID code
+//       ~~~~~~~~~~~                                 for the machine
+//                   mmdb::machine::GetMachineName - returns name of
+//                                                   the machine
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include "mmdb_machine_.h"
+
+namespace mmdb  {
+
+  namespace machine  {
+
+#ifdef CALL_LIKE_SUN
+
+    int GetMachineID()  {
+    int k = CALL_LIKE_SUN;
+      switch (k)  {
+        case 1  : return MACHINE_ALLIANT;
+        case 2  : return MACHINE_CONVEX;
+        case 3  : return MACHINE_ESV;
+        case 4  : return MACHINE_SGI;
+        case 5  : return MACHINE_SOLBOURNE;
+        case 6  : return MACHINE_SOLARIS;
+        case 7  : return MACHINE_ALPHA;
+        case 8  : return MACHINE_F2C_G77;
+        case 9  : return MACHINE_LINUX;
+        default : return MACHINE_UNKNOWN;
+      }
+    }
+
+#elif defined(CALL_LIKE_HPUX)
+
+    int GetMachineID()  {
+    int k = CALL_LIKE_HPUX;
+      switch (k)  {
+        case 1  : return MACHINE_RS6000;
+        case 2  : return MACHINE_HP9000;
+        default : return MACHINE_UNKNOWN;
+      }
+    }
+
+#elif defined(CALL_LIKE_STARDENT)
+
+    int GetMachineID()  {
+    int k = CALL_LIKE_STARDENT;
+      switch (k)  {
+        case 1  : return MACHINE_ARDENT;
+        case 2  : return MACHINE_TITAN;
+        case 3  : return MACHINE_STARDENT;
+        default : return MACHINE_UNKNOWN;
+      }
+    }
+
+#elif defined(CALL_LIKE_VMS)
+
+    int GetMachineID()  {
+      return MACHINE_VMS;
+    }
+
+#elif defined(CALL_LIKE_MVS)
+
+    int GetMachineID()  {
+      return MACHINE_MVS;
+    }
+
+#else
+
+    int GetMachineID()  {
+      return MACHINE_UNKNOWN;
+    }
+
+#endif
+
+    static cpstr MCH_SGI       = cpstr("Silicon Graphics");
+    static cpstr MCH_RS6000    = cpstr("IBM RS/6000");
+    static cpstr MCH_ALLIANT   = cpstr("Alliant");
+    static cpstr MCH_ARDENT    = cpstr("Ardent");
+    static cpstr MCH_TITAN     = cpstr("Titan");
+    static cpstr MCH_STARDENT  = cpstr("Stardent");
+    static cpstr MCH_CONVEX    = cpstr("Convex");
+    static cpstr MCH_ESV       = cpstr("Evans or Sutherland");
+    static cpstr MCH_HP9000    = cpstr("Hewlett Packard 9000");
+    static cpstr MCH_SOLBOURNE = cpstr("Solbourne");
+    static cpstr MCH_SOLARIS   = cpstr("Solaris");
+    static cpstr MCH_ALPHA     = cpstr("DEC Alpha");
+    static cpstr MCH_VMS       = cpstr("A VMS machine");
+    static cpstr MCH_MVS       = cpstr("MS Windows");
+    static cpstr MCH_F2C_G77   = cpstr("SUN compatible");
+    static cpstr MCH_LINUX     = cpstr("Linux");
+
+    cpstr GetMachineName ( int MachineID )  {
+      switch (MachineID)  {
+        case MACHINE_SGI       : return MCH_SGI;
+        case MACHINE_RS6000    : return MCH_RS6000;
+        case MACHINE_ALLIANT   : return MCH_ALLIANT;
+        case MACHINE_ARDENT    : return MCH_ARDENT;
+        case MACHINE_TITAN     : return MCH_TITAN;
+        case MACHINE_STARDENT  : return MCH_STARDENT;
+        case MACHINE_CONVEX    : return MCH_CONVEX;
+        case MACHINE_ESV       : return MCH_ESV;
+        case MACHINE_HP9000    : return MCH_HP9000;
+        case MACHINE_SOLBOURNE : return MCH_SOLBOURNE;
+        case MACHINE_SOLARIS   : return MCH_SOLARIS;
+        case MACHINE_ALPHA     : return MCH_ALPHA;
+        case MACHINE_VMS       : return MCH_VMS;
+        case MACHINE_MVS       : return MCH_MVS;
+        case MACHINE_F2C_G77   : return MCH_F2C_G77;
+        case MACHINE_LINUX     : return MCH_LINUX;
+        default                :
+        case MACHINE_UNKNOWN   : return pstr("Unidentified machine");
+      }
+    }
+
+    cpstr GetMachineName()  {
+      return GetMachineName ( GetMachineID() );
+    }
+
+
+  }
+
+}
diff --git a/mmdb/machine_.h b/mmdb2/mmdb_machine_.h
old mode 100755
new mode 100644
similarity index 79%
rename from mmdb/machine_.h
rename to mmdb2/mmdb_machine_.h
index e7f812b..6897d06
--- a/mmdb/machine_.h
+++ b/mmdb2/mmdb_machine_.h
@@ -1,18 +1,18 @@
-//  $Id: machine_.h,v 1.31 2012/01/26 17:52:19 ekr Exp $
+//  $Id: mmdb_machine.h $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
 //   functionality in protein crystallography applications.
 //
-//   Copyright (C) Eugene Krissinel 2000-2008.
+//   Copyright (C) Eugene Krissinel 2000-2013.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -22,26 +22,26 @@
 //
 //  =================================================================
 //
-//    08.07.08   <--  Date of Last Modification.
+//    12.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
-//  **** Module  :   machine_  <interface>
+//  **** Module  :   Machine  <interface>
 //       ~~~~~~~~~
-//  **** Functions : GetMachineID   - returns ID code for the machine
-//       ~~~~~~~~~~~ GetMachineName - returns name of a machine
+//  **** Functions : mmdb::machine::GetMachineID   - returns ID code
+//       ~~~~~~~~~~~                                 for the machine
+//                   mmdb::machine::GetMachineName - returns name of
+//                                                   the machine
 //
-//  (C) E. Krissinel 2000-2008
+//  (C) E. Krissinel 2000-2013
 //
 //  =================================================================
 //
 
-#ifndef  __Machine__
-#define  __Machine__
+#ifndef  __MMDB_Machine__
+#define  __MMDB_Machine__
 
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
+#include "mmdb_mattype.h"
 
 /*
 // Programs written in plain C, should define __PlainC each time
@@ -54,29 +54,34 @@
 #endif
 */
 
+namespace mmdb  {
+
+  namespace machine  {
 
-//  ==================  List of known machines  ========================
 
-#define  MACHINE_SGI         1
-#define  MACHINE_RS6000      2
-#define  MACHINE_ALLIANT     3
-#define  MACHINE_ARDENT      4
-#define  MACHINE_TITAN       5
-#define  MACHINE_STARDENT    6
-#define  MACHINE_CONVEX      7
-#define  MACHINE_ESV         8
-#define  MACHINE_HP9000      9
-#define  MACHINE_SOLBOURNE  10
-#define  MACHINE_SOLARIS    11
-#define  MACHINE_ALPHA      12
-#define  MACHINE_VMS        13
-#define  MACHINE_MVS        14
-#define  MACHINE_F2C_G77    15
-#define  MACHINE_LINUX      16
-#define  MACHINE_UNKNOWN    100
+    //  ==================  List of known machines  =================
 
+    enum MACHINE  {
+      MACHINE_SGI       = 1,
+      MACHINE_RS6000    = 2,
+      MACHINE_ALLIANT   = 3,
+      MACHINE_ARDENT    = 4,
+      MACHINE_TITAN     = 5,
+      MACHINE_STARDENT  = 6,
+      MACHINE_CONVEX    = 7,
+      MACHINE_ESV       = 8,
+      MACHINE_HP9000    = 9,
+      MACHINE_SOLBOURNE = 10,
+      MACHINE_SOLARIS   = 11,
+      MACHINE_ALPHA     = 12,
+      MACHINE_VMS       = 13,
+      MACHINE_MVS       = 14,
+      MACHINE_F2C_G77   = 15,
+      MACHINE_LINUX     = 16,
+      MACHINE_UNKNOWN   = 100
+    };
 
-//  ================  Identification of the machine  ===================
+    //  =============  Identification of the machine  ===============
 
 // IBM Unix RS/6000
 #if defined(_AIX) || defined(___AIX)
@@ -103,7 +108,7 @@
 # define CALL_LIKE_SUN  3
 
 // Hewlett Packard 9000/750 (RISC) models
-#elif defined(__hpux) 
+#elif defined(__hpux)
 # define CALL_LIKE_HPUX 2
 
 // Silicon Graphics IRIX systems, Iris'es, Indigo's, Crimson's etc.
@@ -127,13 +132,13 @@
 # define CALL_LIKE_VMS  1
 
 // MVS stands for Microsoft Visual Studio
-#elif defined(_MVS) 
+#elif defined(_MVS)
 # define CALL_LIKE_MVS  1
 
 #elif defined(F2C) || defined(G77)
 # define CALL_LIKE_SUN  8
 
-#elif defined(linux) 
+#elif defined(linux)
 # define CALL_LIKE_SUN  9
 
 #else
@@ -147,19 +152,19 @@
 //  =================  Machine-dependent definitions  ==================
 
 #ifdef CALL_LIKE_STARDENT
-  // SStrParam is used in Ardent-like machines' fortran calls
-  // for passing a string parameter
-  DefineStructure(SStrPar)
-  struct SStrPar  {
-    pstr S;
-    int  len;
-    int  id;
-  };
+    // StrPar is used in Ardent-like machines' fortran calls
+    // for passing a string parameter
+    DefineStructure(StrPar)
+    struct StrPar  {
+      pstr S;
+      int  len;
+      int  id;
+    };
 #endif
 
 
 //
-//   Macro  FORTRAN_SUBR(NAME,name,p_send,p_sstruct,p_sflw)
+//   Macro  FORTRAN_SUBR(NAME,name,p_send,p_struct,p_sflw)
 // makes function header statements that allow for linking with
 // programs written in FORTRAN.
 //
@@ -169,7 +174,7 @@
 //   name      name of the FORTRAN subroutine in small letters
 //   p_send    parameter list (in brackets) with string lengths
 //             attached to the end of it (see below)
-//   p_sstruct parameter list (in brackets) with strings passed
+//   p_struct  parameter list (in brackets) with strings passed
 //             as complex parameters, or structures
 //   p_sflw    parameter list (in brackets) with string lengths
 //             following immediately the string parameters
@@ -194,7 +199,7 @@
 //           complex parameter, 'fpstr' is identical to the
 //           pointer on the corresponding structure:
 //             CALL_LIKE_STARDENT :
-//                 'fpstr' is identical to 'PSStrPar'
+//                 'fpstr' is identical to 'PStrPar'
 //             CALL_LIKE_VMS      :
 //                 'fpstr' is identical to 'dsc$descriptor_s *'
 //
@@ -206,7 +211,7 @@
 //        ii) FTN_LEN(s)  - returns integer length of fortran-
 //                          passed string s. For this macro to
 //                          work properly with SUN- and MVS-like
-//                          machines, always use suffix '_len' 
+//                          machines, always use suffix '_len'
 //                          for the string length parameters as
 //                          described in a) above.
 //
@@ -224,7 +229,7 @@
 //                 retain the order in which the strings appear
 //                 in the list.
 //
-//       p_sstruct strings enter their place in the list as in
+//       p_struct strings enter their place in the list as in
 //                 the corresponding FORTRAN call, having 'fpstr'
 //                 parameter type.
 //
@@ -268,7 +273,7 @@
 //
 //
 //
-//   Macro  FORTRAN_CALL(NAME,name,p_send,p_sstruct,p_sflw)
+//   Macro  FORTRAN_CALL(NAME,name,p_send,p_struct,p_sflw)
 // calls function defined with macro FORTRAN_SUBR(...), from
 // a C/C++ application. Its parameters and their meaning are
 // exactly identical to those of FORTRAN_SUBR(...).
@@ -279,27 +284,27 @@
 //  **** type of real numbers in the API functions
 //       comment or uncomment the proper string
 
-typedef  float      apireal;   // FORTRAN  real*4
+    typedef  float      apireal;   // FORTRAN  real*4
 /*
-typedef  double     apireal;    // FORTRAN  real*8
+    typedef  double     apireal;    // FORTRAN  real*8
 */
 
 
 #if defined(CALL_LIKE_SUN)
 
-  typedef pstr fpstr;
+    typedef pstr fpstr;
 
 # define FTN_STR(s)  s
 # define FTN_LEN(s)  s##_len
 
 # define char_struct(s)           \
-    pstr  s;                      \
+    mmdb::pstr  s;                      \
     int   s##_len;
 # define fill_char_struct(s,str)  \
     s  = str;                     \
     s##_len = strlen(str);
 
-# ifdef __cplusplus 
+# ifdef __cplusplus
 #   define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
     extern "C" void name##_ p_sun
 # else
@@ -315,7 +320,7 @@ typedef  double     apireal;    // FORTRAN  real*8
 
 # elif defined(CALL_LIKE_HPUX)
 
-  typedef pstr fpstr;
+    typedef pstr fpstr;
 
 # define FTN_STR(s)  s
 # define FTN_LEN(s)  s##_len
@@ -327,7 +332,7 @@ typedef  double     apireal;    // FORTRAN  real*8
     s  = str;                     \
     s##_len = strlen(str);
 
-# ifdef __cplusplus 
+# ifdef __cplusplus
 #   define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
     extern "C" void name p_sun
 # else
@@ -343,35 +348,35 @@ typedef  double     apireal;    // FORTRAN  real*8
 
 #elif defined(CALL_LIKE_STARDENT)
 
-  typedef PStrPar fpstr;
+    typedef PStrPar fpstr;
 
 # define FTN_STR(s)  s->S
 # define FTN_LEN(s)  s->len
 
 # define char_struct(s)           \
-    SStrPar s;
+    StrPar s;
 # define fill_char_struct(s,str)  \
     s.S   = str;                  \
     s.len = strlen(FName);        \
     s.id  = 0;
 
-# ifdef __cplusplus 
-#   define FORTRAN_SUBR(NAME,name,p_send,p_sstruct,p_sflw) \
+# ifdef __cplusplus
+#   define FORTRAN_SUBR(NAME,name,p_send,p_struct,p_sflw) \
     extern "C" void NAME p_stardent
 # else
-#   define FORTRAN_SUBR(NAME,name,p_send,p_sstruct,p_sflw) \
+#   define FORTRAN_SUBR(NAME,name,p_send,p_struct,p_sflw) \
     void NAME p_stardent
 # endif
 
 # define FORTRAN_EXTERN(NAME,name,p_sun,p_stardent,p_mvs) \
     extern "C" void NAME p_stardent
 
-# define FORTRAN_CALL(NAME,name,p_send,p_sstruct,p_sflw) \
+# define FORTRAN_CALL(NAME,name,p_send,p_struct,p_sflw) \
     NAME p_stardent
 
 #elif defined(CALL_LIKE_VMS)
 
-  typedef dsc$descriptor_s * fpstr;
+    typedef dsc$descriptor_s * fpstr;
 
 # define FTN_STR(s)  s->dsc$a_pointer;
 # define FTN_LEN(s)  s->dsc$w_length;
@@ -384,7 +389,7 @@ typedef  double     apireal;    // FORTRAN  real*8
     s.dsc$b_dtype   = DSC$K_DTYPE_T; \
     s.dsc$b_class   = DSC$K_CLASS_S;
 
-# ifdef __cplusplus 
+# ifdef __cplusplus
 #   define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
     extern "C" void NAME p_stardent
 # else
@@ -400,7 +405,7 @@ typedef  double     apireal;    // FORTRAN  real*8
 
 #elif defined(CALL_LIKE_MVS)
 
-  typedef pstr fpstr;
+    typedef pstr fpstr;
 
 # define FTN_STR(s)  s
 # define FTN_LEN(s)  s##_len
@@ -430,7 +435,7 @@ typedef  double     apireal;    // FORTRAN  real*8
 
 # error  Unknown machine!!!
 
-  typedef pstr fpstr;
+    typedef pstr fpstr;
 
 # define FTN_STR(s)  s
 # define FTN_LEN(s)  s##_len
@@ -442,7 +447,7 @@ typedef  double     apireal;    // FORTRAN  real*8
     s  = str;                     \
     s##_len = strlen(str);
 
-# ifdef __cplusplus 
+# ifdef __cplusplus
 #   define FORTRAN_SUBR(NAME,name,p_sun,p_stardent,p_mvs) \
     extern "C" void name##_ p_sun
 # else
@@ -459,12 +464,14 @@ typedef  double     apireal;    // FORTRAN  real*8
 #endif
 
 
+    //  ==============  Machine-dependent functions  ===============
 
-//  ================  Machine-dependent functions  =================
+    extern int         GetMachineID   ();
+    extern mmdb::cpstr GetMachineName ();
+    extern mmdb::cpstr GetMachineName ( int MachineID );
 
-extern int   GetMachineID   ();
-extern cpstr GetMachineName ();
-extern cpstr GetMachineName ( int MachineID );
+  }
 
+}
 
 #endif
diff --git a/mmdb2/mmdb_manager.cpp b/mmdb2/mmdb_manager.cpp
new file mode 100644
index 0000000..4681adb
--- /dev/null
+++ b/mmdb2/mmdb_manager.cpp
@@ -0,0 +1,389 @@
+//  $Id: mmdb_manager.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    15.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_manager <implementation>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Manager  ( MMDB file manager )
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#include <string.h>
+
+#include "mmdb_manager.h"
+
+namespace mmdb  {
+
+//  =====================   Manager   =======================
+
+  Manager::Manager() : BondManager()  {
+  }
+
+  Manager::Manager ( io::RPStream Object ) : BondManager(Object)  {
+  }
+
+  Manager::~Manager()  {}
+
+  void  Manager::Copy ( PManager MMDB, COPY_MASK CopyMask )  {
+  PModel  mdl;
+  PPChain chain;
+  PChain  ch;
+  ChainID chID;
+  int     i,j, nchains;
+
+    if (CopyMask & MMDBFCM_Flags)  Flags = MMDB->Flags;
+
+    if (CopyMask & MMDBFCM_Title)  title.Copy ( &(MMDB->title) );
+    if (CopyMask & MMDBFCM_Cryst)  cryst.Copy ( &(MMDB->cryst) );
+
+    if (CopyMask & MMDBFCM_Coord)  {
+
+      FreeCoordMemory    ();
+      DeleteAllSelections();
+
+      nAtoms = MMDB->nAtoms;
+      atmLen = nAtoms;
+      if (nAtoms>0)  {
+        atom = new PAtom[atmLen];
+        for (i=0;i<nAtoms;i++)  {
+          if (MMDB->atom[i])  {
+            atom[i] = newAtom();
+            atom[i]->Copy ( MMDB->atom[i] );
+            // the internal atom references are installed
+            // by residue classes when they are read in
+            // model->chain below
+            atom[i]->SetAtomIndex ( i+1 );
+          } else
+            atom[i] = NULL;
+        }
+      }
+
+      nModels = MMDB->nModels;
+      if (nModels>0)  {
+        model = new PModel[nModels];
+        for (i=0;i<nModels;i++)  {
+          if (MMDB->model[i])  {
+            model[i] = newModel();
+            model[i]->SetMMDBManager ( this,0 );
+            model[i]->_copy ( MMDB->model[i] );
+          } else
+            model[i] = NULL;
+        }
+      }
+
+      crModel = NULL;
+      crChain = NULL;
+      crRes   = NULL;
+
+      if (MMDB->crModel)  {
+
+        for (i=0;i<nModels;i++)
+          if (model[i])  {
+            if (model[i]->serNum==MMDB->crModel->serNum)  {
+              crModel = model[i];
+              break;
+            }
+          }
+
+        if (crModel && crModel->chain && MMDB->crChain)
+          for (i=0;i<crModel->nChains;i++)
+            if (crModel->chain[i])  {
+              if (!strcmp(crModel->chain[i]->chainID,
+                          MMDB->crModel->chain[i]->chainID))  {
+                crChain = crModel->chain[i];
+                break;
+              }
+            }
+
+        if (crChain && crChain->residue && MMDB->crRes)
+          for (i=0;i<crChain->nResidues;i++)
+            if (crChain->residue[i])  {
+              if ((!strcmp(crChain->residue[i]->name,
+                           MMDB->crRes->name))                       &&
+                  (crChain->residue[i]->seqNum==MMDB->crRes->seqNum) &&
+                  (!strcmp(crChain->residue[i]->insCode,
+                           MMDB->crRes->insCode)))  {
+                crRes = crChain->residue[i];
+                break;
+              }
+            }
+      }
+
+      /*
+      if ((MMDB->nSelections>0) && MMDB->Mask)  {
+        nSelections = MMDB->nSelections;
+        if (nSelections>0)  {
+          Mask      = new PCMask [nSelections];
+          SelAtom   = new PPAtom[nSelections];
+          nSelAtoms = new int    [nSelections];
+          for (i=0;i<nSelections;i++)  {
+            Mask[i] = new CMask();
+            Mask[i]->CopyMask ( MMDB->Mask[i] );
+            nSelAtoms[i] = MMDB->nSelAtoms[i];
+            if (nSelAtoms[i]>0)  {
+              SelAtom[i] = new PAtom[nSelAtoms[i]];
+              for (j=0;j<nSelAtoms[i];j++)
+                SelAtom[i][j] = Atom[MMDB->SelAtom[i][j]->index];
+            } else
+              SelAtom[i] = NULL;
+          }
+        }
+      }
+      */
+
+    } else if (CopyMask & (MMDBFCM_HetInfo | MMDBFCM_SecStruct |
+                            MMDBFCM_Links | MMDBFCM_CisPeps |
+                            MMDBFCM_ChainAnnot))  {
+
+      for (i=0;i<MMDB->nModels;i++)
+        if (MMDB->model[i])  {
+
+          mdl = GetModel ( i+1 );
+          if (!mdl)  {
+            mdl = new Model( NULL,i+1 );
+            AddModel ( mdl );
+          }
+
+          if (CopyMask & MMDBFCM_HetInfo)
+            mdl->CopyHets ( MMDB->model[i] );
+          if (CopyMask & MMDBFCM_SecStruct)
+            mdl->CopySecStructure ( MMDB->model[i] );
+          if (CopyMask & MMDBFCM_Links)  {
+            mdl->CopyLinks  ( MMDB->model[i] );
+            mdl->CopyLinkRs ( MMDB->model[i] );
+          }
+          if (CopyMask & MMDBFCM_CisPeps)
+            mdl->CopyCisPeps ( MMDB->model[i] );
+          if (CopyMask & MMDBFCM_ChainAnnot)  {
+            MMDB->GetChainTable ( i+1,chain,nchains );
+            for (j=0;j<nchains;j++)
+              if (chain[j])  {
+                chain[j]->GetChainID ( chID );
+                ch = mdl->GetChain ( chID );
+                if (!ch)  {
+                  ch = new Chain();
+                  ch->SetChainID ( chID );
+                  mdl->AddChain ( ch );
+                }
+                ch->CopyAnnotations ( chain[j] );
+              }
+
+          }
+
+        }
+
+    }
+
+    if (CopyMask & MMDBFCM_SA)  SA.Copy ( &(MMDB->SA) );
+    if (CopyMask & MMDBFCM_SB)  SB.Copy ( &(MMDB->SB) );
+    if (CopyMask & MMDBFCM_SC)  SC.Copy ( &(MMDB->SC) );
+    if (CopyMask & MMDBFCM_Footnotes)
+                         Footnote.Copy ( &(MMDB->Footnote) );
+
+    if (CopyMask & MMDBFCM_Buffer)  {
+      lcount = MMDB->lcount;
+      strncpy ( S,MMDB->S,sizeof(S) );
+    }
+
+  }
+
+  void  Manager::Delete ( word DelMask )  {
+  PPModel model;
+  PPChain chain;
+  int      i,j,nm, nchains;
+
+    if (DelMask & MMDBFCM_Flags)  Flags = 0;
+
+    if (DelMask & MMDBFCM_Title)        title.Copy ( NULL );
+    if (DelMask & MMDBFCM_TitleKeepBM)  title.FreeMemory ( true );
+    if (DelMask & MMDBFCM_Cryst)        cryst.Copy ( NULL );
+
+    if (DelMask & MMDBFCM_Coord)  {
+      FreeCoordMemory    ();
+      DeleteAllSelections();
+    }
+
+    if (DelMask & MMDBFCM_SecStruct)  {
+      GetModelTable ( model,nm );
+      if (model)
+        for (i=0;i<nm;i++)
+          if (model[i])
+            model[i]->RemoveSecStructure();
+    }
+
+    if (DelMask & MMDBFCM_HetInfo)  {
+      GetModelTable ( model,nm );
+      if (model)
+        for (i=0;i<nm;i++)
+          if (model[i])
+            model[i]->RemoveHetInfo();
+    }
+
+    if (DelMask & MMDBFCM_Links)  {
+      GetModelTable ( model,nm );
+      if (model)
+        for (i=0;i<nm;i++)
+          if (model[i])  {
+            model[i]->RemoveLinks ();
+            model[i]->RemoveLinkRs();
+          }
+    }
+
+    if (DelMask & MMDBFCM_CisPeps)  {
+      GetModelTable ( model,nm );
+      if (model)
+        for (i=0;i<nm;i++)
+          if (model[i])
+            model[i]->RemoveCisPeps();
+    }
+
+    if (DelMask & MMDBFCM_ChainAnnot)  {
+      nm = GetNumberOfModels();
+      for (i=1;i<=nm;i++)  {
+        GetChainTable ( i,chain,nchains );
+        if (chain)
+          for (j=0;j<nchains;j++)
+            if (chain[j])
+              chain[j]->FreeAnnotations();
+      }
+    }
+
+    if (DelMask & MMDBFCM_SA)        SA.FreeContainer();
+    if (DelMask & MMDBFCM_SB)        SB.FreeContainer();
+    if (DelMask & MMDBFCM_SC)        SC.FreeContainer();
+    if (DelMask & MMDBFCM_Footnotes) Footnote.FreeContainer();
+
+    if (DelMask & MMDBFCM_Buffer)  {
+      lcount = 0;
+      S[0]   = char(0);
+    }
+
+  }
+
+  PTitleContainer Manager::GetRemarks()  {
+    return title.GetRemarks();
+  }
+
+
+  PTitleContainer Manager::GetJournal()  {
+    return title.GetJournal();
+  }
+
+  realtype Manager::GetResolution()  {
+    return title.GetResolution();
+  }
+
+  int Manager::ParseBiomolecules()  {
+    return title.ParseBiomolecules();
+  }
+
+  int Manager::GetNofBiomolecules()  {
+    return title.GetNofBiomolecules();
+  }
+
+  void Manager::GetBiomolecules ( PPBiomolecule & BM, int & nBMs )  {
+    title.GetBiomolecules ( BM,nBMs );
+  }
+
+  PBiomolecule Manager::GetBiomolecule ( int bmNo )  {
+    return title.GetBiomolecule ( bmNo );
+  }
+
+  PManager Manager::MakeBiomolecule ( int bmNo, int modelNo ) {
+  PManager M;
+  PPChain      ch;
+  PChain       chain;
+  PModel       model;
+  PBiomolecule BM;
+  int           i,j,k,n,n0,nChains;
+
+    BM = title.GetBiomolecule ( bmNo );
+    if (!BM)  return NULL;
+
+    GetChainTable ( modelNo,ch,nChains );
+    if ((!ch) || (nChains<=0))  return NULL;
+
+    n0    = 0;
+    model = new Model();
+
+    for (i=0;(i<BM->nBMAs) && (n0>=0);i++)
+      if (BM->bmApply[i])  {
+        for (j=0;(j<BM->bmApply[i]->nMatrices) && (n0>=0);j++)
+          for (k=0;(k<BM->bmApply[i]->nChains) && (n0>=0);k++)  {
+            n0 = -1;
+            for (n=0;(n<nChains) && (n0<0);n++)
+              if (!strcmp(ch[n]->GetChainID(),BM->bmApply[i]->chain[k]))
+                n0 = n;
+            if (n0>=0)  {
+              chain = new Chain();
+              chain->Copy ( ch[n0] );
+              chain->ApplyTransform ( BM->bmApply[i]->tm[j] );
+              model->AddChain ( chain );
+            }
+          }
+      }
+
+    if (n0>=0)  {
+      M = new Manager();
+      M->AddModel ( model );
+      M->PDBCleanup ( PDBCLEAN_SERIAL | PDBCLEAN_INDEX );
+    } else  {
+      delete model;
+      M = NULL;
+    }
+
+    return M;
+
+  }
+
+
+  //  -------------------  Stream functions  ----------------------
+
+
+  void  Manager::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    BondManager::write ( f );
+  }
+
+  void  Manager::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    BondManager::read ( f );
+  }
+
+
+  MakeStreamFunctions(Manager)
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_manager.h b/mmdb2/mmdb_manager.h
new file mode 100644
index 0000000..c70d804
--- /dev/null
+++ b/mmdb2/mmdb_manager.h
@@ -0,0 +1,124 @@
+//  $Id: mmdb_manager.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    15.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_manager <interface>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Manager  ( MMDB file manager )
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Manager__
+#define __MMDB_Manager__
+
+#include "mmdb_bondmngr.h"
+
+namespace mmdb  {
+
+  // =======================  Manager  ===========================
+
+  // copy masks
+  enum COPY_MASK  {
+    MMDBFCM_None        = 0x00000000,
+    MMDBFCM_All         = 0xFFFFFFFF,
+    MMDBFCM_Title       = 0x00000001,
+    MMDBFCM_TitleKeepBM = 0x00000002,
+    MMDBFCM_Cryst       = 0x00000004,
+    MMDBFCM_Coord       = 0x00000008,
+    MMDBFCM_SecStruct   = 0x00000010,
+    MMDBFCM_HetInfo     = 0x00000020,
+    MMDBFCM_Links       = 0x00000040,
+    MMDBFCM_CisPeps     = 0x00000080,
+    MMDBFCM_SA          = 0x00000100,
+    MMDBFCM_SB          = 0x00000200,
+    MMDBFCM_SC          = 0x00000400,
+    MMDBFCM_Footnotes   = 0x00000800,
+    MMDBFCM_ChainAnnot  = 0x00001000,
+    MMDBFCM_Flags       = 0x00002000,
+    MMDBFCM_Buffer      = 0x80000000,
+    MMDBFCM_Top         = 0xFFFFFFF7
+  };
+
+  DefineStreamFunctions(Manager);
+
+  class Manager : public BondManager  {
+
+    public :
+
+      Manager ();
+      Manager ( io::RPStream Object );
+      ~Manager();
+
+
+      //  ---------------  Copying/Deleting  -----------------------
+
+      //   Copy(..) will transfer different sort of information
+      // between two MMDB's according to the copy mask given
+      // (cf. MMDBFCM_XXXXX values). Note that the copying content
+      // replaces the corresponding information (e.g. copying
+      // coordinates will replace existing coordinates rather than
+      // add to them).
+      void  Copy   ( PManager MMDB, COPY_MASK CopyMask );
+
+      //   Delete(..) deletes different sort of information from
+      // the MMDB according to the delete mask given.
+      void  Delete ( word DelMask );  // DelMask is the same as CopyMask
+
+      PTitleContainer GetRemarks();
+      PTitleContainer GetJournal();
+
+      realtype GetResolution(); // -1.0 means no resolution record in file
+
+      int   ParseBiomolecules(); // returns the number of biomolecules,
+                                 // -2 for general format error
+                                 // -3 for errors in BIOMT records
+      int   GetNofBiomolecules();
+      void  GetBiomolecules   ( PPBiomolecule & BM, int & nBMs );
+
+      PBiomolecule GetBiomolecule ( int bmNo ); // bmno=0,1,..
+                                 // returns NULL if bmNo is incorrect
+      PManager MakeBiomolecule ( int bmNo, int modelNo=1 );
+
+
+    protected :
+
+      //  ---------------  Stream I/O  -----------------------------
+      void  write  ( io::RFile f );
+      void  read   ( io::RFile f );
+
+  };
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_mask.cpp b/mmdb2/mmdb_mask.cpp
new file mode 100644
index 0000000..dbf9891
--- /dev/null
+++ b/mmdb2/mmdb_mask.cpp
@@ -0,0 +1,240 @@
+//  $Id: mmdb_mask.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_Mask <implementation>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::Mask  ( atom selection mask )
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_mask.h"
+
+namespace mmdb  {
+
+  //  ====================  Mask  ========================
+
+  Mask::Mask() : io::Stream()  {
+    InitMask();
+  }
+
+  Mask::Mask ( io::RPStream Object ) : io::Stream(Object)  {
+    InitMask();
+  }
+
+  Mask::~Mask()  {
+    ClearMask();
+  }
+
+  void Mask::InitMask()  {
+    mlen = 0;
+    m    = NULL;
+  }
+
+  void Mask::SetMaskBit ( int BitNo )  {
+  int n,i;
+    n = BitNo/(8*sizeof(word));
+    Expand ( n+1 );
+    i = BitNo - n*(8*sizeof(word));
+    m[n] |= ((word)1 << i);
+  }
+
+  void Mask::Expand ( int n )  {
+  wvector m1;
+  int     i;
+    if (mlen<n)  {
+      m1 = new word[n];
+      for (i=0;i<mlen;i++)
+        m1[i] = m[i];
+      for (i=mlen;i<n;i++)
+        m1[i] = 0;
+      if (m)  delete[] m;
+      m    = m1;
+      mlen = n;
+    }
+  }
+
+  void  Mask::NewMask ( PPMask Mask, int nMasks )  {
+  int  i,nlen;
+  word w;
+    ClearMask();
+    if (Mask && (nMasks>0))  {
+      nlen = 0;
+      w    = 0;
+      while (w==0)  {
+        for (i=0;i<nMasks;i++)
+          if (Mask[i])  {
+            if (nlen<Mask[i]->mlen)
+              w |= Mask[i]->m[nlen];
+          }
+        nlen++;
+        w = ~w;
+      }
+      Expand ( nlen );
+      i    = nlen-1;
+      m[i] = 1;
+      while (!(m[i] & w))
+        m[i] <<= 1;
+    } else  {
+      Expand ( 1 );
+      m[0] = 1;
+    }
+  }
+
+  void  Mask::CopyMask ( PMask Mask )  {
+  int i;
+    if (mlen!=Mask->mlen)  ClearMask();
+    if (Mask)  {
+      mlen = Mask->mlen;
+      if (mlen>0)  {
+        m = new word[mlen];
+        for (i=0;i<mlen;i++)
+          m[i] = Mask->m[i];
+      }
+    }
+  }
+
+  void  Mask::SetMask ( PMask Mask )  {
+  int i;
+    if (Mask) {
+      Expand ( Mask->mlen );
+      for (i=0;i<Mask->mlen;i++)
+        m[i] |= Mask->m[i];
+    }
+  }
+
+  void  Mask::RemoveMask ( PMask Mask )  {
+  int i,l;
+    if (Mask) {
+      l = IMin(mlen,Mask->mlen);
+      for (i=0;i<l;i++)
+        m[i] &= ~Mask->m[i];
+    }
+  }
+
+  void  Mask::SelMask ( PMask Mask )  {
+  int i,l;
+    if (Mask)  {
+      l = IMin(mlen,Mask->mlen);
+      for (i=0;i<l;i++)
+        m[i] &= Mask->m[i];
+      for (i=l;i<mlen;i++)
+        m[i] = 0;
+    } else
+      ClearMask();
+  }
+
+  void  Mask::XadMask ( PMask Mask )  {
+  int i;
+    if (Mask) {
+      Expand ( Mask->mlen );
+      for (i=0;i<Mask->mlen;i++)
+        m[i] ^= Mask->m[i];
+    }
+  }
+
+  void  Mask::ClearMask()  {
+    if (m)  delete[] m;
+    m = NULL;
+    mlen = 0;
+  }
+
+  void  Mask::NegMask()  {
+  int i;
+    for (i=0;i<mlen;i++)
+      m[i] = ~m[i];
+  }
+
+  bool  Mask::CheckMask ( PMask Mask )  {
+  int i,l;
+    if (Mask)  {
+      i = 0;
+      l = IMin(mlen,Mask->mlen);
+      while ((i<l) && (!(m[i] & Mask->m[i])))  i++;
+      return (i<l);
+    } else
+      return false;
+  }
+
+  bool  Mask::isMask()  {
+  int i=0;
+    while ((i<mlen) && (!m[i]))  i++;
+    return (i<mlen);
+  }
+
+  pstr  Mask::Print ( pstr S )  {
+  int  i,j,k;
+  word w;
+    j = 0;
+    for (i=0;i<mlen;i++)  {
+      w = 1;
+      for (k=0;k<8*(int)sizeof(word);k++)  {
+        if (w & m[i])  S[j] = '1';
+                 else  S[j] = '0';
+        w <<= 1;
+        j++;
+      }
+    }
+    S[j] = char(0);
+    return S;
+  }
+
+  void  Mask::write ( io::RFile f )  {
+  int i;
+    f.WriteInt ( &mlen );
+    for (i=0;i<mlen;i++)
+      f.WriteWord ( &(m[i]) );
+  }
+
+  void  Mask::read ( io::RFile f )  {
+  int i;
+    if (m)  {
+      delete[] m;
+      m = NULL;
+    }
+    f.ReadInt ( &mlen );
+    if (mlen>0)  {
+      m = new word[mlen];
+      for (i=0;i<mlen;i++)
+        f.ReadWord ( &(m[i]) );
+    }
+  }
+
+  MakeStreamFunctions(Mask)
+
+}  // namespace mmdb
+
diff --git a/mmdb/mmdb_mask.h b/mmdb2/mmdb_mask.h
old mode 100755
new mode 100644
similarity index 50%
rename from mmdb/mmdb_mask.h
rename to mmdb2/mmdb_mask.h
index 62930d4..697b328
--- a/mmdb/mmdb_mask.h
+++ b/mmdb2/mmdb_mask.h
@@ -1,10 +1,10 @@
-//  $Id: mmdb_mask.h,v 1.19 2012/01/26 17:52:20 ekr Exp $
+//  $Id: mmdb_mask.h $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
 //   functionality in protein crystallography applications.
 //
-//   Copyright (C) Eugene Krissinel 2000-2008.
+//   Copyright (C) Eugene Krissinel 2000-2013.
 //
 //    This library is free software: you can redistribute it and/or
 //    modify it under the terms of the GNU Lesser General Public
@@ -22,7 +22,7 @@
 //
 //  =================================================================
 //
-//    17.11.00   <--  Date of Last Modification.
+//    12.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
@@ -31,10 +31,10 @@
 //  **** Project :   MacroMolecular Data Base (MMDB)
 //       ~~~~~~~~~
 //
-//  **** Classes :   CMask  ( atom selection mask )
+//  **** Classes :   mmdb::Mask  ( atom selection mask )
 //       ~~~~~~~~~
 //
-//  (C) E. Krissinel 2000-2008
+//  (C) E. Krissinel 2000-2013
 //
 //  =================================================================
 //
@@ -42,56 +42,54 @@
 #ifndef __MMDB_Mask__
 #define __MMDB_Mask__
 
+#include "mmdb_io_stream.h"
 
-#ifndef __Stream__
-#include "stream_.h"
-#endif
-
-
+namespace mmdb  {
 
-//  ====================  CMask  ========================
+  //  ==========================  Mask  =============================
 
-DefineClass(CMask)
-DefineStreamFunctions(CMask)
+  DefineClass(Mask);
+  DefineStreamFunctions(Mask);
 
-class CMask : public CStream  {
+  class Mask : public io::Stream  {
 
-  public :
+    public :
 
-    CMask ();
-    CMask ( RPCStream Object );
-    ~CMask();
+      Mask ();
+      Mask ( io::RPStream Object );
+      ~Mask();
 
-    void SetMaskBit ( int   BitNo );
-    void NewMask    ( PPCMask Mask, int nMasks );
+      void SetMaskBit ( int  BitNo );
+      void NewMask    ( PPMask Mask, int nMasks );
 
-    void CopyMask   ( PCMask Mask );   //  this = Mask
-    void SetMask    ( PCMask Mask );   //  this = this | Mask
-    void RemoveMask ( PCMask Mask );   //  this = this & (~Mask)
-    void SelMask    ( PCMask Mask );   //  this = this & Mask
-    void XadMask    ( PCMask Mask );   //  this = this ^ Mask
-    void ClearMask  ();                //  this = NULL
-    void NegMask    ();                //  this = ~this
+      void CopyMask   ( PMask Mask );   //  this = Mask
+      void SetMask    ( PMask Mask );   //  this = this | Mask
+      void RemoveMask ( PMask Mask );   //  this = this & (~Mask)
+      void SelMask    ( PMask Mask );   //  this = this & Mask
+      void XadMask    ( PMask Mask );   //  this = this ^ Mask
+      void ClearMask  ();               //  this = NULL
+      void NegMask    ();               //  this = ~this
 
-    Boolean CheckMask ( PCMask Mask ); //  True if the bit is on
-    Boolean isMask    ();              // true if any mask bit is on
+      bool CheckMask ( PMask Mask );    // true if the bit is on
+      bool isMask    ();                // true if any mask bit is on
 
-    inline int getLength() { return mlen; }
+      inline int getLength() { return mlen; }
 
-    pstr Print ( pstr S ); // returns binary string
+      pstr Print ( pstr S ); // returns binary string
 
-    void write ( RCFile f );
-    void read  ( RCFile f );
+      void write ( io::RFile f );
+      void read  ( io::RFile f );
 
-  protected :
-    int     mlen;
-    wvector m;
+    protected :
+      int     mlen;
+      wvector m;
 
-    void InitMask();
-    void Expand  ( int n );
+      void InitMask();
+      void Expand  ( int n );
 
-};
+  };
 
+}  // namespace mmdb
 
 #endif
 
diff --git a/mmdb2/mmdb_math_.cpp b/mmdb2/mmdb_math_.cpp
new file mode 100644
index 0000000..23cfdc8
--- /dev/null
+++ b/mmdb2/mmdb_math_.cpp
@@ -0,0 +1,203 @@
+//  $Id: mmdb_math.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    11.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  Math <implementation>
+//       ~~~~~~~~~
+//  **** Functions :   mmdb::math::GetTorsion
+//       ~~~~~~~~~~~   mmdb::math::GetAngle
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    // --------------------------------------------------------------
+
+    realtype  GetTorsion ( rvector U, rvector W, rvector V )  {
+    //      U     W      V
+    //   o<----o----->o----->o
+    //
+    realtype A[3],B[3],C[3],Wmag,S,T;
+
+      A[0] = U[1]*W[2] - W[1]*U[2];
+      A[1] = U[2]*W[0] - W[2]*U[0];
+      A[2] = U[0]*W[1] - W[0]*U[1];
+
+      B[0] = V[1]*W[2] - W[1]*V[2];
+      B[1] = V[2]*W[0] - W[2]*V[0];
+      B[2] = V[0]*W[1] - W[0]*V[1];
+
+      C[0] = A[1]*B[2] - B[1]*A[2];
+      C[1] = A[2]*B[0] - B[2]*A[0];
+      C[2] = A[0]*B[1] - B[0]*A[1];
+
+      Wmag = sqrt(W[0]*W[0]+W[1]*W[1]+W[2]*W[2]);
+
+      S    = C[0]*W[0] + C[1]*W[1] + C[2]*W[2];
+      T    = A[0]*B[0] + A[1]*B[1] + A[2]*B[2];
+      T   *= Wmag;
+
+      if ((S==0.0) && (T==0.0))  return NO_TORSION;
+                           else  return atan2(S,T);
+
+    }
+
+
+    realtype GetAngle ( rvector v1, rvector v2 )  {
+    realtype l1,l2;
+
+      l1 = v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2];
+      if (l1==0.0)  l1 = 1.0;
+      l2 = v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2];
+      if (l2==0.0)  l2 = 1.0;
+
+      return  acos((v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])/sqrt(l1*l2));
+
+    }
+
+
+    #define  nCombMax  500
+
+    realtype Combinations ( int n, int m )  {
+    //  0<=n<=nCombMax,  0<=m<=n
+    realtype P[nCombMax+1];
+    int      i,j;
+      if ((m<0)  || (m>n))    return 0.0;
+      if ((m==0) || (m==n))   return 1.0;
+      if ((m==1) || (m==n-1)) return realtype(n);
+      P[0] = 1.0;
+      P[1] = 3.0;
+      P[2] = 3.0;
+      P[3] = 1.0;
+      for (i=4;i<=n;i++)  {
+        P[i] = 1.0;
+        for (j=i-1;j>0;j--)
+          P[j] += P[j-1];
+      }
+      return P[m];
+    }
+
+    realtype log1mx ( realtype x )  {
+    //  Calculates precisely log(1-x) for x<1, including
+    //  very small x
+    realtype z,z1,z2,n;
+
+      if (x>=1.0-10.0*MachEps)  z = -MaxReal;
+      else if (fabs(x)>1.0e-8)  z = log(1.0-x);
+      else  {
+        z1 = x;
+        z  = 0.0;
+        n  = 1.0;
+        do  {
+          z2  = z;
+          z  -= z1/n;
+          z1 *= x;
+          n  += 1.0;
+        } while (z!=z2);
+      }
+
+      return z;
+
+    }
+
+    realtype expc ( realtype x )  {
+    //  Calculates precisely 1 - exp(x) for any x including
+    //  very small values
+    realtype z,z1,z2,n;
+
+      if (x>LnMaxReal)         z = -MaxReal;
+      else if (x<-LnMaxReal)   z = 1.0;
+      else if (fabs(x)>1.0e-8) z = 1.0 - Exp(x);
+      else  {
+        z1 = x;
+        z  = x;
+        n  = 1.0;
+        do  {
+          z2  = z;
+          n  += 1.0;
+          z1 *= x/n;
+          z  += z1;
+        } while (z!=z2);
+        z = -z;
+      }
+
+      return z;
+
+    }
+
+
+    realtype expc1mx ( realtype x, realtype y )  {
+    //  Calculates precisely 1-(1-x)**y including very small x and
+    //  very large y
+    realtype z,z1,z2,n,s;
+
+      //  Calculate (1-x)**y as exp(y*log(1-x)).  Get log(1-x) first:
+      if (x>1.0e-8)  z = log(1.0-x);
+      else  {
+        z1 = x;
+        z  = 0.0;
+        n  = 1.0;
+        do  {
+          z2  = z;
+          z  -= z1/n;
+          z1 *= x;
+          n  += 1.0;
+        } while (z!=z2);
+      }
+
+      //  Now calculate 1 - exp(y*log(1-x)) :
+      z *= y;
+      if (fabs(z)>1.0e-8)  s = 1.0 - exp(z);
+      else  {
+        z1 = z;
+        s  = z;
+        n  = 1.0;
+        do  {
+          z2  = s;
+          n  += 1.0;
+          z1 *= z/n;
+          s  += z1;
+        } while (s!=z2);
+        s = -s;
+      }
+
+      return s;
+
+    }
+
+  }
+
+}
diff --git a/mmdb2/mmdb_math_.h b/mmdb2/mmdb_math_.h
new file mode 100644
index 0000000..70172ee
--- /dev/null
+++ b/mmdb2/mmdb_math_.h
@@ -0,0 +1,77 @@
+//  $Id: mmdb_math.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    11.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  Math <interface>
+//       ~~~~~~~~~
+//  **** Functions :   mmdb::math::GetTorsion
+//       ~~~~~~~~~~~   mmdb::math::GetAngle
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef  __MMDB_Math__
+#define  __MMDB_Math__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    // ------------------------------------------------------------------
+
+    const realtype NO_TORSION = -MaxReal;
+
+    //  U[0,1,2] = x,y,z
+    extern realtype GetTorsion   ( rvector U, rvector W, rvector V );
+    extern realtype GetAngle     ( rvector U, rvector V );
+
+    //  Calculates the binomial coefficient n choose m, 0<=n<=500, 0<=m<=n
+    extern realtype Combinations ( int n, int m );
+
+    //  Calculates precisely log(1-x) for x<1, including very small x
+    extern realtype log1mx  ( realtype x );
+
+    //  Calculates precisely 1 - exp(x) for any x including very small values
+    extern realtype expc    ( realtype x );
+
+    inline double exp10  ( double x ) { return exp(x*ln10);   }
+
+    //  Calculates precisely 1-(1-x)**y including very small x and very large y
+    extern realtype expc1mx ( realtype x, realtype y );
+
+  }
+
+}
+
+
+#endif
+
+
diff --git a/mmdb2/mmdb_math_align.cpp b/mmdb2/mmdb_math_align.cpp
new file mode 100644
index 0000000..a974839
--- /dev/null
+++ b/mmdb2/mmdb_math_align.cpp
@@ -0,0 +1,1226 @@
+//  $Id: mmdb_math_align.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :     Align <implementation>
+//       ~~~~~~~~~
+//  **** Classes    :  mmdb::math::Alignment  (char strings alignment)
+//       ~~~~~~~~~~~~  mmdb::math::Alignment1 (int  vectors alignment)
+//
+//  (C) E.Krissinel  2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <math.h>
+
+#include "mmdb_math_align.h"
+
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  =====================   CAligParams   ======================
+
+    AlignParams::AlignParams() : Stream()  {
+      InitAlignParams();
+    }
+
+    AlignParams::AlignParams ( io::RPStream Object ) :
+                  io::Stream ( Object )  {
+      InitAlignParams();
+    }
+
+    void AlignParams::InitAlignParams()  {
+      gapWeight   = -1.0;
+      spaceWeight = -1.0;
+      equalScore  =  2.0;
+      nequalScore = -1.0;
+      method      = ALIGN_GLOBAL;
+    }
+
+    void AlignParams::write ( io::RFile f )  {
+      f.WriteReal ( &gapWeight   );
+      f.WriteReal ( &spaceWeight );
+      f.WriteReal ( &equalScore  );
+      f.WriteReal ( &nequalScore );
+      f.WriteInt  ( &method      );
+    }
+
+    void AlignParams::read ( io::RFile f )  {
+      f.ReadReal ( &gapWeight   );
+      f.ReadReal ( &spaceWeight );
+      f.ReadReal ( &equalScore  );
+      f.ReadReal ( &nequalScore );
+      f.ReadInt  ( &method      );
+    }
+
+    MakeStreamFunctions(AlignParams)
+
+
+    //  =====================   Alignment   ======================
+
+    Alignment::Alignment() : io::Stream()  {
+      InitAlignment();
+    }
+
+    Alignment::Alignment ( io::RPStream Object ) :
+              io::Stream ( Object )  {
+      InitAlignment();
+    }
+
+    Alignment::~Alignment()  {
+      FreeMemory();
+    }
+
+    void  Alignment::InitAlignment()  {
+      Space     = '-';
+      SLen      = 0;
+      TLen      = 0;
+      VT        = NULL;
+      ET        = NULL;
+      FT        = NULL;
+      AlgnS     = NULL;
+      AlgnT     = NULL;
+      AlignKey  = ALIGN_GLOBAL;
+      VAchieved = 0.0;
+      SEq       =  2.0;
+      SNEq      = -1.0;
+      Wg        =  0.0;
+      Ws        = -1.0;
+    }
+
+    void  Alignment::FreeMemory()  {
+      FreeMatrixMemory ( VT,TLen+1,0,0 );
+      FreeMatrixMemory ( ET,TLen+1,0,0 );
+      FreeMatrixMemory ( FT,TLen+1,0,0 );
+      if (AlgnS)  {
+        delete[] AlgnS;
+        AlgnS = NULL;
+      }
+      if (AlgnT)  {
+        delete[] AlgnT;
+        AlgnT = NULL;
+      }
+      TLen = 0;
+      SLen = 0;
+    }
+
+    void  Alignment::SetAffineModel ( realtype WGap, realtype WSpace )  {
+      Wg = WGap;
+      Ws = WSpace;
+    }
+
+    void  Alignment::SetScores ( realtype SEqual, realtype SNEqual )  {
+      SEq  = SEqual;
+      SNEq = SNEqual;
+    }
+
+    void  Alignment::Align  ( cpstr S, cpstr T, ALIGN_METHOD Method )  {
+    int i,j,i0,j0;
+
+      FreeMemory();
+
+      AlignKey = Method;
+
+      switch (Method)  {
+
+        default             :
+        case ALIGN_GLOBAL   : // global pairwise alignment of S and T
+                              BuildGATable ( S,T, false,false );
+                              VAchieved = VT[TLen][SLen];
+                              Backtrace ( S,T,SLen,TLen,false );
+                              if ((AlgnS[0]!=Space) && (AlgnT[0]!=Space))
+                                VAchieved -= Wg;
+                            break;
+
+        case ALIGN_LOCAL    : // local pairwise alignment of S and T
+                              BuildLATable ( S,T );
+                              VAchieved  = 0.0;
+                              i0 = -1;
+                              j0 = -1;
+                              for (i=0;i<=TLen;i++)
+                                for (j=0;j<=SLen;j++)
+                                  if (VT[i][j]>VAchieved)  {
+                                    VAchieved = VT[i][j];
+                                    i0 = i;
+                                    j0 = j;
+                                  }
+                              Backtrace ( S,T,j0,i0,true );
+                            break;
+
+        case ALIGN_GLOBLOC  : // global alignment with non-penalized
+                              // end gaps in T
+                              BuildGATable ( S,T,false,true );
+                              VAchieved = -MaxReal;
+                              i0 = -1;
+                              j0 = -1;
+                              for (i=0;i<=TLen;i++)
+                                if (VT[i][SLen]>VAchieved)  {
+                                  VAchieved = VT[i][SLen];
+                                  i0 = i;
+                                  j0 = SLen;
+                                }
+                              Backtrace  ( S,T,j0,i0,false );
+                              AdjustEnds ( S,T,j0,i0 );
+                            break;
+
+        case ALIGN_FREEENDS : // global alignment with non-penalized
+                              // end gaps in both S and T
+                              BuildGATable ( S,T,true,true );
+                              VAchieved = -MaxReal;
+                              i0 = -1;
+                              j0 = -1;
+                              for (i=0;i<=TLen;i++)
+                                if (VT[i][SLen]>VAchieved)  {
+                                  VAchieved = VT[i][SLen];
+                                  i0 = i;
+                                  j0 = SLen;
+                                }
+                              for (j=0;j<=SLen;j++)
+                                if (VT[TLen][j]>VAchieved)  {
+                                  VAchieved = VT[TLen][j];
+                                  i0 = TLen;
+                                  j0 = j;
+                                }
+                              Backtrace  ( S,T,j0,i0,false );
+                              AdjustEnds ( S,T,j0,i0 );
+
+      }
+
+    }
+
+
+    void  Alignment::BuildGATable ( cpstr S, cpstr T,
+                                    bool FreeSEnd, bool FreeTEnd )  {
+    int      i,j;
+    realtype V1;
+
+      SLen = strlen ( S );
+      TLen = strlen ( T );
+      GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+      //  Base conditions
+      if (FreeSEnd || FreeTEnd)  VT[0][0] = RMax(0.0,Wg);
+                           else  VT[0][0] = Wg;
+      ET[0][0] = VT[0][0];
+      FT[0][0] = VT[0][0];
+
+      if (FreeTEnd)
+        for (i=1;i<=TLen;i++)  {
+          V1       = RMax ( 0.0,VT[i-1][0]+Ws );
+          VT[i][0] = V1;
+          ET[i][0] = V1;
+        }
+      else
+        for (i=1;i<=TLen;i++)  {
+          V1       = VT[i-1][0] + Ws;
+          VT[i][0] = V1;
+          ET[i][0] = V1;
+        }
+
+      if (FreeSEnd)
+        for (j=1;j<=SLen;j++)  {
+          V1       = RMax ( 0.0,VT[0][j-1]+Ws );
+          VT[0][j] = V1;
+          FT[0][j] = V1;
+        }
+      else
+        for (j=1;j<=SLen;j++)  {
+          V1       = VT[0][j-1] + Ws;
+          VT[0][j] = V1;
+          FT[0][j] = V1;
+        }
+
+      //  Recurrence
+      for (i=1;i<=TLen;i++)
+        for (j=1;j<=SLen;j++)  {
+          V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+          ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+          FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+          VT[i][j] = RMax ( RMax(V1,ET[i][j]),FT[i][j] );
+        }
+
+      FreeMatrixMemory ( ET,TLen+1,0,0 );
+      FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+    //  PrintVT ( S,T );
+
+    }
+
+
+    void  Alignment::BuildLATable ( cpstr S, cpstr T )  {
+    int      i,j;
+    realtype V1;
+
+      SLen = strlen ( S );
+      TLen = strlen ( T );
+      GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+      //  Base conditions
+      VT[0][0] = RMax ( 0.0,Wg );
+      ET[0][0] = VT[0][0];
+      FT[0][0] = VT[0][0];
+      for (i=1;i<=TLen;i++)  {
+        V1       = RMax ( 0.0,VT[i-1][0]+Ws );
+        VT[i][0] = V1;
+        ET[i][0] = V1;
+      }
+      for (j=1;j<=SLen;j++)  {
+        V1       = RMax ( 0.0,VT[0][j-1]+Ws );
+        VT[0][j] = V1;
+        FT[0][j] = V1;
+      }
+
+      //  Recurrence
+      for (i=1;i<=TLen;i++)
+        for (j=1;j<=SLen;j++)  {
+          V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+          ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+          FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+          VT[i][j] = RMax ( RMax(V1,ET[i][j]),RMax(0.0,FT[i][j]) );
+        }
+
+      FreeMatrixMemory ( ET,TLen+1,0,0 );
+      FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+    //  PrintVT ( S,T );
+
+    }
+
+    void  Alignment::PrintVT ( cpstr S, cpstr T )  {
+    int i,j;
+      printf ( "\n       " );
+      for (j=0;j<=SLen;j++)
+        printf ( " %2i",j );
+      printf ( " \n           " );
+      for (j=1;j<=SLen;j++)
+        printf ( " %c ",S[j-1] );
+      printf ( " \n\n " );
+      for (i=0;i<=TLen;i++)  {
+        if (i>0)  printf ( " %2i %c ",i,T[i-1] );
+            else  printf ( " %2i   ",i );
+        for (j=0;j<=SLen;j++)
+          printf ( " %2i",mround(VT[i][j]) );
+        printf ( " \n " );
+      }
+      printf ( " \n" );
+    }
+
+
+    void  Alignment::Backtrace ( cpstr S, cpstr T, int J, int I,
+                                 bool  StopAtZero )  {
+    int       i,j,k, i1,j1, sk,tk;
+    char      C;
+    realtype  V,SV,TV;
+    bool      Stop;
+
+      //  1. Allocate memory
+
+      if (AlgnS)  delete[] AlgnS;
+      if (AlgnT)  delete[] AlgnT;
+
+      i = SLen+TLen+1;
+      AlgnS = new char[i];
+      AlgnT = new char[i];
+      memset ( AlgnS,Space,i );
+      memset ( AlgnT,Space,i );
+
+      //  2. Initialize backtracing
+      i  = I;   // backtracing
+      j  = J;   //    indices
+      k  = 0;   // alignment index
+      SV = 0.0;  sk = -1;   // alignment indices and leading elements
+      TV = 0.0;  tk = -1;   //   for vertical and horizontal sections
+
+
+      //  3. Backtracing
+      Stop = false;
+      while ((!Stop) && (i>0) && (j>0))  {
+
+        V = VT[i][j];
+
+        // find next leading element
+        if (VT[i][j-1]>VT[i-1][j])  {
+          i1 = i;    j1 = j-1;
+        } else  {
+          i1 = i-1;  j1 = j;
+        }
+        if (VT[i-1][j-1]>=VT[i1][j1])  {
+          i1 = i-1;  j1 = j-1;
+        }
+
+    //printf ( "  i=%i  j=%i \n",i,j );
+
+        Stop = StopAtZero && (VT[i1][j1]<=0.0);  // used at local alignment
+
+        // treat horizontal section
+        if ((sk<0) || (V>SV))  {
+          sk = k;
+          SV = V;
+        }
+        if ((j1!=j) || Stop)  {  // end of horizontal section
+          AlgnS[sk] = S[j-1];
+          sk = -1;
+        }
+
+        // treat vertical section
+        if ((tk<0) || (V>TV))  {
+          tk = k;
+          TV = V;
+        }
+        if ((i1!=i) || Stop)  {  // end of vertical section
+          AlgnT[tk] = T[i-1];
+          tk = -1;
+        }
+
+        i = i1;
+        j = j1;
+        k++;
+
+      }
+
+      if (!StopAtZero)  {
+        //  4. Finish the last horizontal section
+        sk = k;
+        while (j>0)  AlgnS[k++] = S[--j];
+        //  5. Finish the last vertical section
+        while (i>0)  AlgnT[sk++] = T[--i];
+        k = IMax ( k,sk );
+      }
+
+      //  6. Put the termination character
+      AlgnS[k] = char(0);
+      AlgnT[k] = char(0);
+
+      //  7. Reverse the strings
+      i = 0;
+      j = k-1;
+      if (StopAtZero)  {
+        // should work only for local alignment
+        while ((j>0) && ((AlgnS[j]==Space) || (AlgnT[j]==Space)))  j--;
+        k = j+1;
+        AlgnS[k] = char(0);
+        AlgnT[k] = char(0);
+      }
+      while (j>i)  {
+        C = AlgnS[i];  AlgnS[i] = AlgnS[j];  AlgnS[j] = C;
+        C = AlgnT[i];  AlgnT[i] = AlgnT[j];  AlgnT[j] = C;
+        i++;
+        j--;
+      }
+
+      //  8. Collapse the alternating spaces
+      do  {
+        k = 0;
+        i = 0;
+        while (AlgnS[k])  {
+          if ((AlgnS[k]==Space) && (AlgnT[k]==Space))  k++;
+          else if ((AlgnS[k]==Space) && (AlgnS[k+1]!=Space) &&
+                   (AlgnT[k]!=Space) && (AlgnT[k+1]==Space))  {
+            AlgnS[i] = AlgnS[k+1];
+            AlgnT[i] = AlgnT[k];
+            k++;
+          } else if ((AlgnS[k]!=Space) && (AlgnS[k+1]==Space) &&
+                     (AlgnT[k]==Space) && (AlgnT[k+1]!=Space))  {
+            AlgnS[i] = AlgnS[k];
+            AlgnT[i] = AlgnT[k+1];
+            k++;
+          } else if (i!=k)  {
+            AlgnS[i] = AlgnS[k];
+            AlgnT[i] = AlgnT[k];
+          }
+          if (AlgnS[k])  {
+            k++;
+            i++;
+          }
+        }
+        if (i!=k)  {  // terminating character
+          AlgnS[i] = AlgnS[k];
+          AlgnT[i] = AlgnT[k];
+        }
+      } while (k>i);
+
+    }
+
+
+    void  Alignment::AdjustEnds ( cpstr S, cpstr T, int J, int I )  {
+    int si,ti,m;
+
+      if (J<SLen)  strcat ( AlgnS,&(S[J]) );
+      if (I<TLen)  strcat ( AlgnT,&(T[I]) );
+      si = strlen ( AlgnS );
+      ti = strlen ( AlgnT );
+      m  = IMax ( si,ti );
+      while (si<m)  AlgnS[si++] = Space;
+      while (ti<m)  AlgnT[ti++] = Space;
+      AlgnS[si] = char(0);
+      AlgnT[ti] = char(0);
+
+    /*
+    int k,m;
+
+      if (J>I)  {
+        k = J-I;
+        strcat ( AlgnT,&(T[IMax(0,TLen-k)]) );
+        k = strlen ( AlgnS );
+        m = strlen ( AlgnT );
+        while (k<m)
+          AlgnS[k++] = Space;
+        AlgnS[k] = char(0);
+      } else if (I>J)  {
+        k = I-J;
+        strcat ( AlgnS,&(S[IMax(0,SLen-k)]) );
+        k = strlen ( AlgnT );
+        m = strlen ( AlgnS );
+        while (k<m)
+          AlgnT[k++] = Space;
+        AlgnT[k] = char(0);
+      }
+    */
+
+    }
+
+
+    realtype Alignment::Score ( char A, char B )  {
+      if (A==B)  return SEq;
+      if ((A==Space) || (B==Space))  return Ws;
+      return SNEq;
+    }
+
+    realtype Alignment::GetSimilarity()  {
+    realtype s,a;
+    int      i,n;
+
+      s = 0.0;
+      a = 0.0;
+      n = IMin ( strlen(AlgnS),strlen(AlgnT) );
+
+      for (i=0;i<n;i++)
+        if ((AlgnS[i]!=Space) || (AlgnT[i]!=Space))  {
+          a += RMax ( Score(AlgnS[i],AlgnS[i]),Score(AlgnT[i],AlgnT[i]) );
+          s += Score ( AlgnS[i],AlgnT[i] );
+        }
+
+      if ((s>0.0) && (a>0.0))  return s/a;
+      return 0.0;
+
+    }
+
+
+    realtype Alignment::GetSeqId()  {
+    realtype s;
+    int      i,n,ne,ns,nt;
+
+      ne = 0;
+      ns = 0;
+      nt = 0;
+      n  = IMin ( strlen(AlgnS),strlen(AlgnT) );
+
+      for (i=0;i<n;i++)  {
+        if (AlgnS[i]!=Space)  ns++;
+        if (AlgnT[i]!=Space)  {
+          nt++;
+          if (AlgnS[i]==AlgnT[i])
+            ne++;
+        }
+      }
+
+      s = IMin ( ns,nt );
+      if (s>0.0)  return ne/s;
+      return 0.0;
+
+    }
+
+
+    #define  WrapPeriod  61
+
+    void  Alignment::OutputResults ( io::RFile f, cpstr S, cpstr T )  {
+    int   k,l,n;
+    char  P[3];
+
+      P[1] = char(0);
+      if ((!AlgnS) || (!AlgnT))  {
+        f.LF();
+        f.WriteLine ( pstr(" NO ALIGNMENT HAS BEEN DONE.") );
+        f.shut();
+        return;
+      }
+      f.LF();
+      f.WriteLine ( pstr(" ========  INPUT DATA") );
+      f.LF();
+      f.WriteLine ( pstr(" String S:") );
+      f.Write ( pstr(" ") );
+      l = 1;
+      k = 0;
+      while (S[k])  {
+        P[0] = S[k++];
+        f.Write ( P );
+        l++;
+        if (l>=WrapPeriod)  {
+          f.LF();  f.Write ( pstr(" ") );  l = 1;
+        }
+      }
+      f.LF();
+      f.LF();
+      f.WriteLine ( pstr(" String T:") );
+      f.Write ( pstr(" ") );
+      l = 1;
+      k = 0;
+      while (T[k])  {
+        P[0] = T[k++];
+        f.Write ( P );
+        l++;
+        if (l>=WrapPeriod)  {
+          f.LF();  f.Write ( pstr(" ") );  l = 1;
+        }
+      }
+      f.LF();
+      f.LF();
+      f.WriteParameter ( pstr(" Score equal")  ,SEq ,20,10 );
+      f.WriteParameter ( pstr(" Score unequal"),SNEq,20,10 );
+      f.LF();
+      f.WriteParameter ( pstr(" Gap weight")   ,Wg  ,20,10 );
+      f.WriteParameter ( pstr(" Space weight") ,Ws  ,20,10 );
+      f.LF();
+      f.LF();
+      f.Write ( pstr(" ========  RESULT OF ") );
+      switch (AlignKey)  {
+        default             :
+        case ALIGN_GLOBAL   : f.Write ( pstr("GLOBAL")       );  break;
+        case ALIGN_LOCAL    : f.Write ( pstr("LOCAL")        );  break;
+        case ALIGN_GLOBLOC  : f.Write ( pstr("GLOBAL/LOCAL") );  break;
+        case ALIGN_FREEENDS : f.Write ( pstr("FREE-ENDS")    );
+      }
+      f.WriteLine ( pstr(" ALIGNMENT") );
+      f.LF();
+      if (AlignKey==ALIGN_GLOBLOC)  {
+        f.WriteLine ( pstr(" End gaps in T-string were not penalized") );
+        f.LF();
+      }
+      f.WriteParameter ( pstr(" Highest score achieved:"),VAchieved,26,10 );
+      f.LF();
+      f.WriteLine ( pstr(" Aligned S (upper string) and T (lower string):") );
+      f.LF();
+      k = 0;
+      n = 0;
+      l = 1;  f.Write ( pstr(" ") );
+      while (AlgnS[k])  {
+        P[0] = AlgnS[k++];
+        f.Write ( P );
+        l++;
+        if ((l>=WrapPeriod) || (!AlgnS[k]))  {
+          f.LF();  f.Write ( pstr(" ") );  l = 1;
+          while (AlgnT[n] && (l<WrapPeriod))  {
+            P[0] = AlgnT[n++];
+            f.Write ( P );
+            l++;
+          }
+          f.LF(); f.LF(); f.Write ( pstr(" ") );  l = 1;
+        }
+      }
+
+    }
+
+
+    //  -----------------  Streaming  -----------------------------
+
+    void  Alignment::write ( io::RFile f )  {
+    int Version=1;
+      f.WriteFile ( &Version,sizeof(Version) );
+      Stream::write ( f );
+    }
+
+    void  Alignment::read ( io::RFile f )  {
+    int Version;
+      f.ReadFile ( &Version,sizeof(Version) );
+      Stream::write ( f );
+    }
+
+
+
+    //  =====================   Alignment1   ======================
+
+    Alignment1::Alignment1() : io::Stream()  {
+      InitAlignment1();
+    }
+
+    Alignment1::Alignment1 ( io::RPStream Object ) :
+                io::Stream ( Object ) {
+      InitAlignment1();
+    }
+
+    Alignment1::~Alignment1()  {
+      FreeMemory();
+    }
+
+    void  Alignment1::InitAlignment1()  {
+      Space     = 0;
+      SLen      = 0;
+      TLen      = 0;
+      AlgnLen   = 0;
+      VT        = NULL;
+      ET        = NULL;
+      FT        = NULL;
+      AlgnS     = NULL;
+      AlgnT     = NULL;
+      AlignKey  = ALIGN_GLOBAL;
+      VAchieved = 0.0;
+      SEq       =  2.0;
+      SNEq      = -1.0;
+      Wg        =  0.0;
+      Ws        = -1.0;
+    }
+
+    void  Alignment1::FreeMemory()  {
+      FreeMatrixMemory ( VT,TLen+1,0,0 );
+      FreeMatrixMemory ( ET,TLen+1,0,0 );
+      FreeMatrixMemory ( FT,TLen+1,0,0 );
+      FreeVectorMemory ( AlgnS,0 );
+      FreeVectorMemory ( AlgnT,0 );
+      TLen    = 0;
+      SLen    = 0;
+      AlgnLen = 0;
+    }
+
+    void  Alignment1::SetAffineModel ( realtype WGap, realtype WSpace )  {
+      Wg = WGap;
+      Ws = WSpace;
+    }
+
+    void  Alignment1::SetScores ( realtype SEqual, realtype SNEqual )  {
+      SEq  = SEqual;
+      SNEq = SNEqual;
+    }
+
+    void  Alignment1::Align  ( ivector S, int SLength,
+                               ivector T, int TLength,
+                               ALIGN_METHOD Method )  {
+    int i,j,i0,j0;
+
+      FreeMemory();
+
+      SLen = SLength;
+      TLen = TLength;
+
+      AlignKey = Method;
+
+      switch (Method)  {
+
+        default             :
+        case ALIGN_GLOBAL   : // global pairwise alignment of S and T
+                              BuildGATable ( S,T, false,false );
+                              VAchieved = VT[TLen][SLen];
+                              Backtrace ( S,T,SLen,TLen,false );
+                              if ((AlgnS[0]!=Space) && (AlgnT[0]!=Space))
+                                VAchieved -= Wg;
+                            break;
+
+        case ALIGN_LOCAL    : // local pairwise alignment of S and T
+                              BuildLATable ( S,T );
+                              VAchieved = 0.0;
+                              i0 = -1;
+                              j0 = -1;
+                              for (i=0;i<=TLen;i++)
+                                for (j=0;j<=SLen;j++)
+                                  if (VT[i][j]>VAchieved)  {
+                                    VAchieved = VT[i][j];
+                                    i0 = i;
+                                    j0 = j;
+                                  }
+                              Backtrace ( S,T,j0,i0,true );
+                            break;
+
+        case ALIGN_GLOBLOC  : // global alignment with non-penalized
+                              // end gaps in T
+                              BuildGATable ( S,T,false,true );
+                              VAchieved = -MaxReal;
+                              i0 = -1;
+                              j0 = -1;
+                              for (i=0;i<=TLen;i++)
+                                if (VT[i][SLen]>VAchieved)  {
+                                  VAchieved = VT[i][SLen];
+                                  i0 = i;
+                                  j0 = SLen;
+                                }
+                              Backtrace  ( S,T,j0,i0,false );
+                              AdjustEnds ( S,T,j0,i0 );
+                            break;
+
+        case ALIGN_FREEENDS : // global alignment with non-penalized
+                              // end gaps in both S and T
+                              BuildGATable ( S,T,true,true );
+                              VAchieved = -MaxReal;
+                              i0 = -1;
+                              j0 = -1;
+                              for (i=0;i<=TLen;i++)
+                                if (VT[i][SLen]>VAchieved)  {
+                                  VAchieved = VT[i][SLen];
+                                  i0 = i;
+                                  j0 = SLen;
+                                }
+                              for (j=0;j<=SLen;j++)
+                                if (VT[TLen][j]>VAchieved)  {
+                                  VAchieved = VT[TLen][j];
+                                  i0 = TLen;
+                                  j0 = j;
+                                }
+                              Backtrace  ( S,T,j0,i0,false );
+                              AdjustEnds ( S,T,j0,i0 );
+      }
+
+    }
+
+
+    void  Alignment1::BuildGATable ( ivector S, ivector T,
+                                     bool FreeSEnd, bool FreeTEnd )  {
+    int      i,j;
+    realtype V1;
+
+      GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+      //  Base conditions
+      if (FreeSEnd || FreeTEnd)  VT[0][0] = RMax(0.0,Wg);
+                           else  VT[0][0] = Wg;
+      ET[0][0] = VT[0][0];
+      FT[0][0] = VT[0][0];
+
+      if (FreeTEnd)
+        for (i=1;i<=TLen;i++)  {
+          V1       = RMax ( 0.0,VT[i-1][0]+Ws );
+          VT[i][0] = V1;
+          ET[i][0] = V1;
+        }
+      else
+        for (i=1;i<=TLen;i++)  {
+          V1       = VT[i-1][0] + Ws;
+          VT[i][0] = V1;
+          ET[i][0] = V1;
+        }
+
+      if (FreeSEnd)
+        for (j=1;j<=SLen;j++)  {
+          V1       = RMax ( 0.0,VT[0][j-1]+Ws );
+          VT[0][j] = V1;
+          FT[0][j] = V1;
+        }
+      else
+        for (j=1;j<=SLen;j++)  {
+          V1       = VT[0][j-1] + Ws;
+          VT[0][j] = V1;
+          FT[0][j] = V1;
+        }
+
+      //  Recurrence
+      for (i=1;i<=TLen;i++)
+        for (j=1;j<=SLen;j++)  {
+          V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+          ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+          FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+          VT[i][j] = RMax ( RMax(V1,ET[i][j]),FT[i][j] );
+        }
+
+      FreeMatrixMemory ( ET,TLen+1,0,0 );
+      FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+    //  PrintVT ( S,T );
+
+    }
+
+
+    void  Alignment1::BuildLATable ( ivector S, ivector T )  {
+    int      i,j;
+    realtype V1;
+
+      GetMatrixMemory ( VT,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( ET,TLen+1,SLen+1,0,0 );
+      GetMatrixMemory ( FT,TLen+1,SLen+1,0,0 );
+
+      //  Base conditions
+      VT[0][0] = RMax ( 0.0,Wg );
+      ET[0][0] = VT[0][0];
+      FT[0][0] = VT[0][0];
+      for (i=1;i<=TLen;i++)  {
+        V1       = RMax ( 0.0,VT[i-1][0]+Ws );
+        VT[i][0] = V1;
+        ET[i][0] = V1;
+      }
+      for (j=1;j<=SLen;j++)  {
+        V1       = RMax ( 0.0,VT[0][j-1]+Ws );
+        VT[0][j] = V1;
+        FT[0][j] = V1;
+      }
+
+      //  Recurrence
+      for (i=1;i<=TLen;i++)
+        for (j=1;j<=SLen;j++)  {
+          V1       = VT[i-1][j-1] + Score(T[i-1],S[j-1]);
+          ET[i][j] = RMax ( ET[i][j-1]+Ws,VT[i][j-1]+Wg+Ws );
+          FT[i][j] = RMax ( FT[i-1][j]+Ws,VT[i-1][j]+Wg+Ws );
+          VT[i][j] = RMax ( RMax(V1,ET[i][j]),RMax(0.0,FT[i][j]) );
+        }
+
+      FreeMatrixMemory ( ET,TLen+1,0,0 );
+      FreeMatrixMemory ( FT,TLen+1,0,0 );
+
+    //  PrintVT ( S,T );
+
+    }
+
+    void  Alignment1::PrintVT ( ivector S, ivector T )  {
+    int i,j;
+      printf ( "\n       " );
+      for (j=0;j<=SLen;j++)
+        printf ( " %2i",j );
+      printf ( " \n           " );
+      for (j=1;j<=SLen;j++)
+        printf ( " %3i ",S[j-1] );
+      printf ( " \n\n " );
+      for (i=0;i<=TLen;i++)  {
+        if (i>0)  printf ( " %2i %3i ",i,T[i-1] );
+            else  printf ( " %2i   ",i );
+        for (j=0;j<=SLen;j++)
+          printf ( " %2i",mround(VT[i][j]) );
+        printf ( " \n " );
+      }
+      printf ( " \n" );
+    }
+
+
+    void  Alignment1::Backtrace ( ivector S, ivector T, int J, int I,
+                                  bool StopAtZero )  {
+    int       i,j,k, i1,j1, sk,tk;
+    int       C;
+    realtype  V,SV,TV;
+    bool      Stop;
+
+      //  1. Allocate memory
+
+      FreeVectorMemory ( AlgnS,0 );
+      FreeVectorMemory ( AlgnT,0 );
+      AlgnLen = 0;
+
+      k = SLen+TLen+1;
+      GetVectorMemory  ( AlgnS,k,0 );
+      GetVectorMemory  ( AlgnT,k,0 );
+      for (i=0;i<k;i++)  {
+        AlgnS[i] = Space;
+        AlgnT[i] = Space;
+      }
+
+      //  2. Initialize backtracing
+      i = I;   // backtracing
+      j = J;   //    indices
+
+      k  = 0;   // alignment index
+      SV = 0.0;  sk = -1;   // alignment indices and leading elements
+      TV = 0.0;  tk = -1;   //   for vertical and horizontal sections
+
+
+      //  3. Backtracing
+      Stop = false;
+      while ((!Stop) && (i>0) && (j>0))  {
+
+        V = VT[i][j];
+
+        // find next leading element
+        if (VT[i][j-1]>VT[i-1][j])  {
+          i1 = i;    j1 = j-1;
+        } else  {
+          i1 = i-1;  j1 = j;
+        }
+        if (VT[i-1][j-1]>=VT[i1][j1]) {
+          i1 = i-1;  j1 = j-1;
+        }
+
+        Stop = StopAtZero && (VT[i1][j1]<=0.0);  // used at local alignment
+
+        // treat horizontal section
+        if ((sk<0) || (V>SV))  {
+          sk = k;
+          SV = V;
+        }
+        if ((j1!=j) || Stop)  {  // end of horizontal section
+          AlgnS[sk] = S[j-1];
+          sk = -1;
+        }
+
+        // treat vertical section
+        if ((tk<0) || (V>TV))  {
+          tk = k;
+          TV = V;
+        }
+        if ((i1!=i) || Stop)  {  // end of vertical section
+          AlgnT[tk] = T[i-1];
+          tk = -1;
+        }
+
+        i = i1;
+        j = j1;
+        k++;
+
+      }
+
+      if (!StopAtZero)  {
+        //  4. Finish the last horizontal section
+        sk = k;
+        while (j>0)  AlgnS[k++] = S[--j];
+        //  5. Finish the last vertical section
+        while (i>0)  AlgnT[sk++] = T[--i];
+        k = IMax ( k,sk );
+      }
+
+      //  6. Put the termination character
+      AlgnLen  = k;
+
+      //  7. Reverse the strings
+      i = 0;
+      j = k-1;
+      if (StopAtZero)  {
+        // should work only for local alignment
+        while ((j>0) && ((AlgnS[j]==Space) || (AlgnT[j]==Space)))  j--;
+        AlgnLen = j+1;
+      }
+      while (j>i)  {
+        C = AlgnS[i];  AlgnS[i] = AlgnS[j];  AlgnS[j] = C;
+        C = AlgnT[i];  AlgnT[i] = AlgnT[j];  AlgnT[j] = C;
+        i++;
+        j--;
+      }
+
+      //  8. Filter out parasite spaces
+      k = 0;
+      i = 0;
+      while (k<AlgnLen) {
+        while ((k<AlgnLen) && (AlgnS[k]==Space) && (AlgnT[k]==Space))  k++;
+        if (k<AlgnLen) {
+          AlgnS[i] = AlgnS[k];
+          AlgnT[i] = AlgnT[k];
+          k++;
+          i++;
+        }
+      }
+
+      AlgnLen = i;
+
+      //  9. Collapse the alternating spaces
+      do  {
+
+        k = 0;
+        i = 0;
+        while (k<AlgnLen)  {
+          if ((AlgnS[k]==Space) && (AlgnT[k]==Space))  k++;
+          else if ((k+1<AlgnLen) &&
+                   (AlgnS[k]==Space) && (AlgnS[k+1]!=Space) &&
+                   (AlgnT[k]!=Space) && (AlgnT[k+1]==Space))  {
+            AlgnS[i] = AlgnS[k+1];
+            AlgnT[i] = AlgnT[k];
+            k++;
+          } else if ((k+1<AlgnLen) &&
+                     (AlgnS[k]!=Space) && (AlgnS[k+1]==Space) &&
+                     (AlgnT[k]==Space) && (AlgnT[k+1]!=Space))  {
+            AlgnS[i] = AlgnS[k];
+            AlgnT[i] = AlgnT[k+1];
+            k++;
+          } else if (i!=k)  {
+            AlgnS[i] = AlgnS[k];
+            AlgnT[i] = AlgnT[k];
+          }
+          if (k<AlgnLen)  {
+            k++;
+            i++;
+          }
+        }
+
+        AlgnLen = i;
+
+      } while (k>i);
+
+
+    }
+
+
+    void  Alignment1::AdjustEnds ( ivector S, ivector T, int J, int I )  {
+    int is,it;
+      is = J;
+      it = I;
+      while ((is<SLen) || (it<TLen))  {
+        if (is<SLen)  AlgnS[AlgnLen] = S[is];
+                else  AlgnS[AlgnLen] = Space;
+        if (it<TLen)  AlgnT[AlgnLen] = T[it];
+                else  AlgnT[AlgnLen] = Space;
+        is++;
+        it++;
+        AlgnLen++;
+      }
+    }
+
+    realtype Alignment1::Score ( int A, int B )  {
+      if (A==B)  {
+        if (A==Space)  return 0.0;
+                 else  return SEq;
+      }
+      if ((A==Space) || (B==Space))  return Ws;
+      return SNEq;
+    }
+
+
+    realtype Alignment1::GetSimilarity()  {
+    realtype s,a;
+    int      i;
+
+      s = 0.0;
+      a = 0.0;
+
+      for (i=0;i<AlgnLen;i++)
+        if ((AlgnS[i]!=Space) || (AlgnT[i]!=Space))  {
+          a += RMax ( Score(AlgnS[i],AlgnS[i]),Score(AlgnT[i],AlgnT[i]) );
+          s += Score ( AlgnS[i],AlgnT[i] );
+        }
+
+      if ((s>0.0) && (a>0.0))  return s/a;
+      return 0.0;
+
+    }
+
+
+    void  Alignment1::OutputResults ( io::RFile  f, ivector S, int lenS,
+                                      ivector T, int lenT )  {
+    int   k,l,n;
+    char  P[10];
+
+      if ((!AlgnS) || (!AlgnT))  {
+        f.LF();
+        f.WriteLine ( pstr(" NO ALIGNMENT HAS BEEN DONE.") );
+        f.shut();
+        return;
+      }
+      f.LF();
+      f.WriteLine ( pstr(" ========  INPUT DATA") );
+      f.LF();
+      f.WriteLine ( pstr(" String S:") );
+      f.Write ( pstr(" ") );
+      l = 1;
+      k = 0;
+      while (k<lenS)  {
+        sprintf ( P,"%4i ",S[k++] );
+        f.Write ( P );
+        l += 5;
+        if (l>=WrapPeriod)  {
+          f.LF();  f.Write ( pstr(" ") );  l = 1;
+        }
+      }
+      f.LF();
+      f.LF();
+      f.WriteLine ( pstr(" String T:") );
+      f.Write ( pstr(" ") );
+      l = 1;
+      k = 0;
+      while (k<lenT)  {
+        sprintf ( P,"%4i ",T[k++] );
+        f.Write ( P );
+        l += 5;
+        if (l>=WrapPeriod)  {
+          f.LF();  f.Write ( pstr(" ") );  l = 1;
+        }
+      }
+      f.LF();
+      f.LF();
+      f.WriteParameter ( pstr(" Score equal")  ,SEq ,20,10 );
+      f.WriteParameter ( pstr(" Score unequal"),SNEq,20,10 );
+      f.LF();
+      f.WriteParameter ( pstr(" Gap weight")   ,Wg  ,20,10 );
+      f.WriteParameter ( pstr(" Space weight") ,Ws  ,20,10 );
+      f.LF();
+      f.LF();
+      f.Write ( pstr(" ========  RESULT OF ") );
+      switch (AlignKey)  {
+        default             :
+        case ALIGN_GLOBAL   : f.Write ( pstr("GLOBAL")       );  break;
+        case ALIGN_LOCAL    : f.Write ( pstr("LOCAL")        );  break;
+        case ALIGN_GLOBLOC  : f.Write ( pstr("GLOBAL/LOCAL") );  break;
+        case ALIGN_FREEENDS : f.Write ( pstr("FREE-ENDS")    );
+      }
+      f.WriteLine ( pstr(" ALIGNMENT") );
+      f.LF();
+      if (AlignKey==ALIGN_GLOBLOC)  {
+        f.WriteLine ( pstr(" End gaps in T-string were not penalized") );
+        f.LF();
+      }
+      f.WriteParameter ( pstr(" Highest score achieved:"),
+                         VAchieved,26,10 );
+      f.LF();
+      f.WriteLine ( pstr(" Aligned S (upper string) and T "
+                         "(lower string):") );
+      f.LF();
+      k = 0;
+      n = 0;
+      l = 1;  f.Write ( pstr(" ") );
+      while (k<AlgnLen)  {
+        sprintf ( P,"%4i ",AlgnS[k++] );
+        f.Write ( P );
+        l += 5;
+        if ((l>=WrapPeriod) || (!AlgnS[k]))  {
+          f.LF();  f.Write ( pstr(" ") );  l = 1;
+          while ((n<AlgnLen) && (l<WrapPeriod))  {
+            sprintf ( P,"%4i ",AlgnT[n++] );
+            f.Write ( P );
+            l += 5;
+          }
+          f.LF(); f.LF(); f.Write ( pstr(" ") );  l = 1;
+        }
+      }
+
+    }
+
+
+    //  -----------------  Streaming  -----------------------------
+
+    void  Alignment1::write ( io::RFile f )  {
+    int Version=1;
+      f.WriteFile ( &Version,sizeof(Version) );
+      Stream::write ( f );
+    }
+
+    void  Alignment1::read ( io::RFile f )  {
+    int Version;
+      f.ReadFile ( &Version,sizeof(Version) );
+      Stream::write ( f );
+    }
+
+
+  }  // namespace math
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_math_align.h b/mmdb2/mmdb_math_align.h
new file mode 100644
index 0000000..fca7bc6
--- /dev/null
+++ b/mmdb2/mmdb_math_align.h
@@ -0,0 +1,195 @@
+//  $Id: mmdb_math_align.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :     Align <interface>
+//       ~~~~~~~~~
+//  **** Classes    :  mmdb::math::Alignment  (char strings alignment)
+//       ~~~~~~~~~~~~  mmdb::math::Alignment1 (int  vectors alignment)
+//
+//  (C) E.Krissinel  2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_MATH_Align__
+#define __MMDB_MATH_Align__
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  =====================   AlignParams   ======================
+
+    DefineClass(AlignParams);
+    DefineStreamFunctions(AlignParams);
+
+    class AlignParams : public io::Stream  {
+
+      public :
+
+        realtype  gapWeight,spaceWeight;
+        realtype  equalScore,nequalScore;
+        int       method;
+
+        AlignParams();
+        AlignParams ( io::RPStream Object );
+
+        void write ( io::RFile f );
+        void read  ( io::RFile f );
+
+      protected :
+        void InitAlignParams();
+
+    };
+
+
+    //  ======================   Alignment   =======================
+
+    DefineClass(Alignment);
+
+    enum ALIGN_METHOD  {
+      ALIGN_GLOBAL   = 0,
+      ALIGN_LOCAL    = 1,
+      ALIGN_GLOBLOC  = 2,
+      ALIGN_FREEENDS = 3
+    };
+
+    class  Alignment : public io::Stream  {
+
+      public :
+
+        Alignment  ();
+        Alignment  ( io::RPStream Object );
+        ~Alignment ();
+
+        void SetAffineModel ( realtype WGap,   realtype WSpace  );
+        void SetScores      ( realtype SEqual, realtype SNEqual );
+
+        void Align          ( cpstr S, cpstr T,
+                              ALIGN_METHOD Method=ALIGN_GLOBAL );
+
+        inline pstr     GetAlignedS()  {  return AlgnS;      }
+        inline pstr     GetAlignedT()  {  return AlgnT;      }
+        inline realtype GetScore   ()  {  return VAchieved;  }
+        inline char     GetSpace   ()  {  return Space;      }
+
+        realtype GetSimilarity(); // Score-weighted sequence id
+        realtype GetSeqId     (); // Primitive sequence id
+
+        virtual void OutputResults ( io::RFile f, cpstr S, cpstr T  );
+
+        void read  ( io::RFile f );
+        void write ( io::RFile f );
+
+      protected :
+
+        char     Space;
+        int      AlignKey, SLen,TLen;
+        rmatrix  VT,ET,FT;
+        pstr     AlgnS,AlgnT;
+        realtype VAchieved;
+        realtype SEq,SNEq, Wg,Ws;
+
+        virtual void  InitAlignment();
+        virtual void  FreeMemory   ();
+        virtual realtype  Score    ( char A, char B );
+
+        void    BuildGATable ( cpstr S, cpstr T,
+                               bool FreeSEnd, bool FreeTEnd );
+        void    BuildLATable ( cpstr S, cpstr T );
+        void    Backtrace    ( cpstr S, cpstr T, int J, int I,
+                               bool StopAtZero );
+        void    AdjustEnds   ( cpstr S, cpstr T, int J, int I );
+        void    PrintVT      ( cpstr S, cpstr T );
+
+    };
+
+
+
+    //  ======================   Alignment1   =======================
+
+    DefineClass(Alignment1);
+
+    class  Alignment1 : public io::Stream  {
+
+      public :
+
+        Alignment1 ();
+        Alignment1 ( io::RPStream Object );
+        ~Alignment1();
+
+        void SetAffineModel ( realtype WGap,   realtype WSpace  );
+        void SetScores      ( realtype SEqual, realtype SNEqual );
+
+        void Align          ( ivector S, int SLength,
+                              ivector T, int TLength,
+                              ALIGN_METHOD Method=ALIGN_GLOBAL );
+
+        inline ivector  GetAlignedS   ()  { return AlgnS;     }
+        inline ivector  GetAlignedT   ()  { return AlgnT;     }
+        inline int      GetAlignLength()  { return AlgnLen;   }
+        inline realtype GetScore      ()  { return VAchieved; }
+
+        realtype GetSimilarity(); // Score-weighted sequence id
+
+        virtual void OutputResults ( io::RFile f, ivector S, int lenS,
+                                                  ivector T, int lenT );
+
+        void read  ( io::RFile f );
+        void write ( io::RFile f );
+
+      protected :
+
+        int      Space;
+        int      AlignKey, SLen,TLen, AlgnLen;
+        rmatrix  VT,ET,FT;
+        ivector  AlgnS,AlgnT;
+        realtype VAchieved;
+        realtype SEq,SNEq, Wg,Ws;
+
+        virtual void  InitAlignment1();
+        virtual void  FreeMemory    ();
+        virtual realtype  Score     ( int A, int B );
+
+        void    BuildGATable ( ivector S, ivector T,
+                               bool FreeSEnds, bool FreeTEnds );
+        void    BuildLATable ( ivector S, ivector T );
+        void    Backtrace    ( ivector S, ivector T, int J, int I,
+                               bool StopAtZero );
+        void    AdjustEnds   ( ivector S, ivector T, int J, int I );
+        void    PrintVT      ( ivector S, ivector T );
+
+    };
+
+  }  // namespace math
+
+}  // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_math_bfgsmin.cpp b/mmdb2/mmdb_math_bfgsmin.cpp
new file mode 100644
index 0000000..989608a
--- /dev/null
+++ b/mmdb2/mmdb_math_bfgsmin.cpp
@@ -0,0 +1,938 @@
+//  $Id: mmdb_math_bfgsmin.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  BFGSMin  <implementation>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::math::BFGSMin  ( minimization driver )
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_bfgsmin.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  ==============================================================
+
+    BFGSMin::BFGSMin()  {
+
+      MFunc       = NULL;
+      MFuncData   = NULL;
+      PFunc       = NULL;
+      PFuncData   = NULL;
+
+      N           = 0;
+      NAlloc      = 0;
+
+      Hsn         = NULL;
+      TL          = NULL;
+      LL          = NULL;
+      XOpt        = NULL;
+      XPlus       = NULL;
+      Sx          = NULL;
+      SN          = NULL;
+      HDiag       = NULL;
+      GradX       = NULL;
+      GPlus       = NULL;
+      StepSize    = NULL;
+      FNeighbor   = NULL;
+      us          = NULL;
+      uy          = NULL;
+      ut          = NULL;
+      Freese      = NULL;
+      Func        = 0.0;
+      FPlus       = 0.0;
+      FOpt        = 0.0;
+      TakenLambda = 0.0;
+      ForDiff     = false;
+      CalcHess    = false;
+
+      Etha        = 0.0;
+      SqrtEtha    = 0.0;
+      CubertEtha  = 0.0;
+      TpF         = 1.0;
+      GrdEps      = 0.0;
+      StpEps      = 0.0;
+      MxStep      = MaxReal;
+      CnsMax      = 0;
+      MaxItn      = 100;
+      TermCode    = BFGS_NoTermination;
+      ModF        = false;
+
+    }
+
+    BFGSMin::~BFGSMin()  {
+      FreeMemory();
+    }
+
+    void  BFGSMin::MinFunc ( rvector X, realtype & F )  {
+      if (MFunc)  (*MFunc)(MFuncData,N,X,F);
+            else  F = 0.0;
+    }
+
+    void  BFGSMin::MinFunc1 ( rvector X, realtype & F )  {
+    int i;
+      MinFunc ( X,F );
+      if (ModF && (F<FOpt))  {
+        for (i=1;i<=N;i++)
+          XOpt[i] = X[i];
+        FOpt = F;
+      }
+    }
+
+    void  BFGSMin::Print ( int Itn, rvector X, rvector G, realtype F )  {
+      if (PFunc)  (*PFunc)(PFuncData,N,Itn,X,G,F);
+    }
+
+    void  BFGSMin::SetMinFunction ( void * UserData, PBFGSMinFunc Fnc )  {
+      MFuncData = UserData;
+      MFunc     = Fnc;
+    }
+
+    void  BFGSMin::SetPrintFunction ( void * UserData, PBFGSPrintFunc Fnc )  {
+      PFuncData = UserData;
+      PFunc     = Fnc;
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::UMInCk ( rvector  x0,      rvector  TypX,
+                            int      Digits,  realtype TypF,
+                            realtype GrdTol,  realtype StpTol,
+                            realtype MaxStp,  int      ItnLmt )  {
+    int      i;
+    realtype S0,S1,S2;
+
+      SqrtEps = sqrt(MachEps);
+
+      if (N<1)  {
+        TermCode = BFGS_WrongSpaceDim;
+        return;
+      }
+
+      for (i=1;i<=N;i++)
+        if (fabs(TypX[i])!=0.0)  Sx[i] = 1.0/fabs(TypX[i]);
+                           else  Sx[i] = 1.0;
+
+      if (Digits<=0)  Etha = MachEps;
+      else  {
+        Etha = Exp((-Digits)*log(10.0));
+        if (MachEps>Etha)  Etha = MachEps;
+      }
+      SqrtEtha   = sqrt(Etha);
+      CubertEtha = Exp ( log(Etha)/3.0 );
+
+      if (Etha>0.01)  {
+        TermCode = BFGS_TooFewDigits;
+        return;
+      }
+
+      if (TypF<=0.0)  TpF = 1.0;
+                else  TpF = TypF;
+
+      S1 = Exp(log(MachEps)/3.0);
+      if (GrdTol>0.0)  GrdEps = GrdTol;
+      else  {
+        GrdEps = sqrt(Etha);
+        if (S1>GrdEps)  GrdEps = S1;
+      }
+
+      if (StpTol>0.0)  StpEps = StpTol;
+                 else  StpEps = Exp ( log(MachEps)*2.0/3.0 );
+
+      if (MaxStp>0.0)  MxStep = MaxStp;
+      else  {
+        S1 = 0.0;
+        S2 = 0.0;
+        for (i=1;i<=N;i++)  {
+          S0  = Sx[i];
+          S0 *= Sx[i];
+          S2 += S0;
+          S0 *= x0[i];
+          S1 += S0*x0[i];
+        }
+        S1 = sqrt(S1);
+        S2 = sqrt(S2);
+        if (S2>S1)  MxStep = S2;
+              else  MxStep = S1;
+        MxStep *= 1000.0;
+      }
+
+      if (ItnLmt>0)  MaxItn = ItnLmt;
+               else  MaxItn = 100;
+
+      TermCode = BFGS_NoTermination;
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::UMStop0 ( rvector x0, rvector Grad )  {
+    int      i;
+    realtype S,Fmax,St;
+
+      CnsMax = 0;
+      if (TpF>fabs(Func))  Fmax = TpF;
+                     else  Fmax = fabs(Func);
+      S = 0.0;
+      for (i=1;i<=N;i++)  {
+        St = fabs(x0[i]);
+        if (1.0/Sx[i]>St)  St = 1.0/Sx[i];
+        St = fabs(Grad[i])*St/Fmax;
+        if (St>S)  S = St;
+      }
+      if (S>=0.001*GrdEps)  TermCode = BFGS_NoTermination;
+                      else  TermCode = BFGS_SmallGradient;
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::UMStop ( rvector  x0, rvector Grad,
+                            int RetCode, int  ItnCnt,
+                            bool MaxTkn )  {
+
+    //  A7.2.1   :  Checking the Stop Conditions
+
+    int      i;
+    realtype Max1,Max2,MaxGrad,MaxStep, BB1,BB2;
+
+      TermCode = BFGS_NoTermination;
+      if (RetCode==1)  TermCode = BFGS_LineSearchComplete;
+      else  {
+        if (fabs(FPlus)>TpF)  Max2 = fabs(FPlus);
+                        else  Max2 = TpF;
+        MaxGrad = 0.0;
+        MaxStep = 0.0;
+        for (i=1;i<=N;i++)  {
+          BB1 = fabs(XPlus[i]);
+          BB2 = 1.0/Sx[i];
+          if (BB1>BB2)  Max1 = BB1;
+                  else  Max1 = BB2;
+          BB1 = fabs(Grad[i])*Max1/Max2;
+          if (BB1>MaxGrad) MaxGrad = BB1;
+          BB2 = fabs(XPlus[i]-x0[i])/Max1;
+          if (BB2>MaxStep)  MaxStep = BB2;
+        }
+        if      (MaxGrad<GrdEps)  TermCode = BFGS_SmallGradient;
+        else if (MaxStep<StpEps)  TermCode = BFGS_SmallStep;
+        else if (ItnCnt>MaxItn)   TermCode = BFGS_IterationLimit;
+        else if (MaxTkn)  {
+          CnsMax++;
+          if (CnsMax==5)  TermCode = BFGS_LargeSteps;
+        } else
+          CnsMax = 0;
+      }
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::MdHess ( rmatrix H, rvector HDg )  {
+
+    //  A5.5.1   :  Setting up the hessian of model
+
+    int       i,j;
+    realtype  MaxDiag,MaxOff, MinEv,Mue,MaxPosDiag;
+    realtype  MaxOffl,MinDiag,MaxEv,MaxAdd,Sdd,OffRow;
+    realtype  BB;
+
+      //  Scaling
+      for (i=1;i<=N;i++)
+        for (j=i;j<=N;j++)
+          H[i][j] /= (Sx[i]*Sx[j]);
+
+      MaxDiag = H[1][1];
+      MinDiag = H[1][1];
+      MaxOff  = 0.0;
+      for (i=1;i<=N;i++)  {
+        if (H[i][i]>MaxDiag)  MaxDiag = H[i][i];
+        if (H[i][i]<MinDiag)  MinDiag = H[i][i];
+        if (i<N)
+          for (j=i+1;j<=N;j++)  {
+            BB = fabs(H[i][j]);
+            if (BB>MaxOff)  MaxOff = BB;
+          }
+      }
+      MaxPosDiag = 0.0;
+      if (MaxDiag>MaxPosDiag)  MaxPosDiag = MaxDiag;
+
+      //  Computing the shift of the spectra (the  Mue)
+      if (MinDiag>SqrtEps*MaxPosDiag)  Mue = 0.0;
+      else  {
+        Mue      = 2.0*(MaxPosDiag-MinDiag)*SqrtEps-MinDiag;
+        MaxDiag += Mue;
+      }
+      BB = MaxOff*(1.0+2.0*SqrtEps);
+      if (BB>MaxDiag)  {
+        Mue     = Mue+(MaxOff-MaxDiag)+2.0*SqrtEps*MaxOff;
+        MaxDiag = BB;
+      }
+      if (MaxDiag==0.0)  {  //  H = 0
+        Mue     = 1.0;
+        MaxDiag = 1.0;
+      }
+      if (Mue>0.0)
+        for (i=1;i<=N;i++)
+          Hsn[i][i] += Mue;
+
+      MaxOffl = MaxOff/N;
+      if (MaxDiag>MaxOffl)  MaxOffl = MaxDiag;
+      MaxOffl = sqrt(MaxOffl);
+      for (i=1;i<=N;i++)
+        HDg[i] = H[i][i];
+
+      PbCholDecomp ( N,HDg,MaxOffl,MachEps,H,MaxAdd );
+
+      if (MaxAdd>0.0)  {
+        MaxEv = HDg[1];
+        MinEv = HDg[1];
+        for (i=1;i<=N;i++)  {
+          OffRow = 0.0;
+          if (i>1)
+            for (j=1;j<i;j++)
+              OffRow += fabs(H[j][i]);
+          if (i<N)
+            for (j=i+1;j<=N;j++)
+              OffRow += fabs(H[i][j]);
+          BB = HDg[i]+OffRow;
+          if (BB>MaxEv)  MaxEv = BB;
+          BB = HDg[i]-OffRow;
+          if (BB<MinEv)  MinEv = BB;
+        }
+        Sdd = (MaxEv-MinEv)*SqrtEps-MinEv;
+        if (Sdd<0.0)  Sdd = 0.0;
+        if (MaxAdd<Sdd)  Mue = MaxAdd;
+                   else  Mue = Sdd;
+        for (i=1;i<=N;i++)
+          HDg[i] += Mue;
+
+        PbCholDecomp ( N,HDg,0.0,MachEps,H,MaxAdd );
+
+      }
+
+      //  Scaling back
+      for (i=1;i<=N;i++)  {
+        if (i<N)
+          for (j=i+1;j<=N;j++)
+            H[i][j] *= (Sx[i]*Sx[j]);
+        HDg[i] *= Sx[i]*Sx[i];
+        for (j=1;j<=i;j++)
+          H[i][j] *= Sx[i];
+      }
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::FDGrad ( rvector X, rvector G, realtype Fc )  {
+
+    //  A5.6.4  :  Forward Finite-Differencies Approximation of
+    //             the Gradient
+
+    realtype StepSizeJ,TempJ,Fj, BB1,BB2;
+    int      j;
+
+      for (j=1;j<=N;j++)  {
+        BB1 = fabs(X[j]);
+        BB2 = 1.0/Sx[j];
+        if (BB1>BB2)  StepSizeJ = BB1;
+                else  StepSizeJ = BB2;
+        if (X[j]<0.0) StepSizeJ = -StepSizeJ;
+        StepSizeJ *= SqrtEtha;
+        TempJ      = X[j];
+        X[j]      += StepSizeJ;
+        StepSizeJ  = X[j]-TempJ;
+        MinFunc1 ( X,Fj );
+        if (TermCode!=BFGS_NoTermination)  return;
+        G[j]       = (Fj-Fc)/StepSizeJ;
+        X[j]       = TempJ;
+        Freese[j]  = false;
+        if (TL)  {
+          if ((fabs(X[j]-TL[j])<=StepSizeJ) && (G[j]<0.0))  {
+            G[j] = 0.0;   Freese[j] = true;
+          }
+        }
+        if (LL)  {
+          if ((fabs(X[j]-LL[j])<=StepSizeJ) && (G[j]>0.0))  {
+            G[j] = 0.0;   Freese[j] = true;
+          }
+        }
+      }
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::CDGrad ( rvector X, rvector G  )  {
+
+    //  A5.6.4  :  Central Differencies Approximation of
+    //             Gradient
+
+    realtype  StepSizeJ,TempJ,Fp,Fm, BB1,BB2;
+    int       j;
+
+      for (j=1;j<=N;j++)  {
+        BB1 = fabs(X[j]);
+        BB2 = 1.0/Sx[j];
+        if (BB1>BB2)  StepSizeJ = BB1;
+                else  StepSizeJ = BB2;
+        if (X[j]<0.0) StepSizeJ = -StepSizeJ;
+        StepSizeJ *= CubertEtha;
+        TempJ      = X[j];
+        X[j]      += StepSizeJ;
+        StepSizeJ  = X[j]-TempJ;
+        MinFunc1 ( X,Fp );
+        if (TermCode!=BFGS_NoTermination)  return;
+        X[j]       = TempJ-StepSizeJ;
+        MinFunc1 ( X,Fm );
+        if (TermCode!=BFGS_NoTermination)  return;
+        G[j]       = (Fp-Fm)/(2.0*StepSizeJ);
+        X[j]       = TempJ;
+      }
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::Gradient ( rvector X, rvector G, realtype Fc )  {
+      if (ForDiff)  FDGrad ( X,G,Fc );
+              else  CDGrad ( X,G );
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::FDHessF ( realtype Fc, rvector X )  {
+
+    //   A5.6.2   :  Finite-Difference Approximation of
+    //               the Hessian employing only the
+    //               function's  values
+
+    int       i,j;
+    realtype  S,TempI,Fii,TempJ,Fij, BB1,BB2;
+
+
+      for (i=1;i<=N;i++)
+        if (!Freese[i])  {
+          BB1 = fabs(X[i]);
+          BB2 = 1.0/Sx[i];
+          if (BB1>BB2)  S = BB1;
+                  else  S = BB2;
+          if (X[i]<0.0) S = -S;
+          StepSize[i] = S*CubertEtha;
+          TempI       = X[i];
+          X[i]       += StepSize[i];
+          StepSize[i] = X[i]-TempI;
+          MinFunc1 ( X,FNeighbor[i] );
+          X[i]        = TempI;
+          if (TermCode!=BFGS_NoTermination)  return;
+        }
+      for (i=1;i<=N;i++)
+        if (!Freese[i])  {
+          TempI = X[i];
+          X[i] += 2.0*StepSize[i];
+          MinFunc1 ( X,Fii );
+          if (TermCode!=BFGS_NoTermination)  return;
+          Hsn[i][i] = (( Fc -FNeighbor[i] ) +
+                       ( Fii-FNeighbor[i] )) /
+                      (StepSize[i]*StepSize[i]);
+          X[i]      = TempI+StepSize[i];
+          if (i<N)
+            for (j=i+1;j<=N;j++)
+              if (!Freese[j])  {
+                TempJ = X[j];
+                X[j] += StepSize[j];
+                MinFunc1 ( X,Fij );
+                if (TermCode!=BFGS_NoTermination)  return;
+                Hsn[i][j] = (( Fc -FNeighbor[i] ) +
+                             ( Fij-FNeighbor[j] )) /
+                            (StepSize[i]*StepSize[j]);
+                X[j]      = TempJ;
+              } else
+                Hsn[i][j] = 0.0;
+          X[i] = TempI;
+        } else
+          for (j=i;j<=N;j++)
+            Hsn[i][j] = 0.0;
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::InitHessUnFac ( realtype F, rmatrix H )  {
+
+    //  A9.4.3  -  Initialization of the unfactorized BFGS
+
+    realtype Temp;
+    int      i,j;
+
+      Temp = fabs(F);
+      if (TpF>Temp)  Temp = TpF;
+      for (i=1;i<=N;i++)  {
+        H[i][i] = Temp*Sx[i]*Sx[i];
+        if (i<N)
+          for (j=i+1;j<=N;j++)
+            H[i][j] = 0.0;
+      }
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::BFGSUnFac (  rvector  Xc,     rvector  Xp,
+                                rvector  Gc,     rvector  Gp,
+                                bool  AnalGrad,  rvector  HDg,
+                                rmatrix  H )  {
+
+    //  A9.4.1  -  Calculation of the Hessian by the
+    //             unfactorized BFGS
+
+    int      i,j;
+    realtype Temp1,Temp2, NormS,NormY,Tol,tt, BB;
+    bool     SkipUpdate;
+
+      Temp1 = 0.0;
+      NormS = 0.0;
+      NormY = 0.0;
+      for (i=1;i<=N;i++)  {
+        H[i][i] = HDg[i];
+        us[i]   = Xp[i] - Xc[i];
+        uy[i]   = Gp[i] - Gc[i];
+        Temp1  += us[i]*uy[i];
+        NormS  += us[i]*us[i];
+        NormY  += uy[i]*uy[i];
+      }
+
+      if (Temp1>sqrt(MachEps*NormS*NormY))  {
+        if (AnalGrad)  Tol = Etha;
+                 else  Tol = sqrt(Etha);
+        SkipUpdate = true;
+        for (i=1;i<=N;i++)  {
+          tt = 0.0;
+          for (j=1;j<=i;j++)
+            tt += H[j][i]*us[j];
+          if (i<N)
+            for (j=i+1;j<=N;j++)
+              tt += H[i][j]*us[j];
+          ut[i] = tt;
+          tt    = fabs(Gc[i]);
+          BB    = fabs(Gp[i]);
+          if (BB>tt)  tt = BB;
+          if (fabs(uy[i]-ut[i])>=Tol*tt)
+            SkipUpdate = false;
+        }
+
+        if (!SkipUpdate)  {
+          Temp2 = 0.0;
+          for (i=1;i<=N;i++)
+            Temp2 += us[i]*ut[i];
+          for (i=1;i<=N;i++)
+            for (j=i;j<=N;j++)
+              H[i][j] += uy[i]*uy[j]/Temp1 -
+                         ut[i]*ut[j]/Temp2;
+        }
+
+      }
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::Choose_Lambda ( rvector X, rvector S,
+                                   realtype & Lambda0 )  {
+    int      i;
+    realtype SS;
+
+      for (i=1;i<=N;i++)
+        if  ((S[i]!=0.0) && (!Freese[i]))  {
+          SS = X[i] + Lambda0*S[i];
+          if (TL)  {
+            if (SS>TL[i])  Lambda0 = (TL[i]-X[i])/S[i]/(1.0+MachEps);
+          }
+          if (LL)  {
+            if (SS<LL[i])  Lambda0 = (LL[i]-X[i])/S[i]/(1.0+MachEps);
+          }
+        } else if (Freese[i])  S[i] = 0.0;
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::Stop()  {
+      TermCode = BFGS_Stopped;
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::LineSearch (  rvector   px0,   rvector   G,
+                                 rvector   P,     realtype  pFunc,
+                                 int  & RetCode,  bool & MaxTkn )  {
+
+    //  A6.3.1   :   Linear  Search
+
+    int      i;
+    realtype Alpha, NewtLn, S, InitSp, RelLng, MinLam;
+    realtype Lambda,LamTem, LamPre, FplPre, A, B;
+    realtype Disc,  B1, B2, Lambda0;
+
+      LamPre = 1.0;  // only to keep compiler happy
+      FplPre = 1.0;  // only to keep compiler happy
+
+      MaxTkn  = false;
+      RetCode = 2;
+      Alpha   = 1.0e-4;
+      NewtLn  = 0.0;
+      for (i=1;i<=N;i++)  {   //  calculate Newtonian step along the -gradient
+        B1      = Sx[i]*P[i];
+        NewtLn += B1*B1;
+      }
+      NewtLn = sqrt(NewtLn);
+
+      if (NewtLn>MxStep)  {   //  restrict Newtonian step to MxStep
+        S = MxStep/NewtLn;
+        for (i=1;i<=N;i++)
+          P[i] *= S;
+        NewtLn = MxStep;
+      }
+
+      InitSp  = 0.0;
+      RelLng  = 0.0;
+      Lambda0 = 1.0;
+      Choose_Lambda ( px0,P,Lambda0 );
+      for (i=1;i<=N;i++)  {
+        InitSp += G[i]*P[i];
+        B1      = fabs(px0[i]);
+        B2      = 1.0/Sx[i];
+        if (B1>B2)  S = B1;
+              else  S = B2;
+        S       = fabs(P[i])/S;
+        if (S>RelLng)  RelLng = S;
+      }
+      InitSp *= Lambda0;
+
+      MinLam = StpEps/RelLng;
+      Lambda = Lambda0;
+      do {
+        for (i=1;i<=N;i++)
+          XPlus[i] = px0[i] + Lambda*P[i];
+
+        MinFunc1 ( XPlus,FPlus );
+        if (TermCode!=BFGS_NoTermination)  return;
+        if (FPlus<=pFunc+Alpha*Lambda*InitSp)  {
+          RetCode = 0;
+          MaxTkn  = (Lambda==Lambda0) && (NewtLn>0.99*MxStep);
+        } else if (Lambda<MinLam)  {
+          RetCode = 1;
+          for (i=1;i<=N;i++)
+            XPlus[i] = px0[i];
+        } else if (Lambda==Lambda0)  {
+          LamTem = -InitSp/(2.0*(FPlus-pFunc-InitSp));
+          LamTem = LamTem*Lambda;
+          LamPre = Lambda;
+          FplPre = FPlus;
+          if (LamTem>0.1*Lambda)  Lambda = LamTem;
+          else  {
+            Lambda *= 0.1;
+            Lambda0 = Lambda;
+          }
+          if (Lambda>Lambda0)  {
+            Lambda  = Lambda0;
+            RetCode = 0;
+            for (i=1;i<=N;i++)
+              XPlus[i] = px0[i] + Lambda*P[i];
+          }
+        } else  {
+          B1 = FPlus  - pFunc - Lambda*InitSp;
+          B2 = FplPre - pFunc - LamPre*InitSp;
+          A  = ( B1/(Lambda*Lambda) - B2/(LamPre*LamPre) ) /
+               ( Lambda - LamPre );
+          B  = ( -LamPre*B1/(Lambda*Lambda) +
+                 Lambda*B2/(LamPre*LamPre) ) /
+               ( Lambda - LamPre );
+          Disc = B*B - 3.0*A*InitSp;
+          if (A==0.0)  LamTem = -InitSp/(2.0*B);
+                 else  LamTem = (-B+sqrt(RMax(Disc,0.0)))/(3.0*A);
+          B1 = 0.5*Lambda;
+          if (B1<LamTem)  LamTem = B1;
+          LamPre = Lambda;
+          FplPre = FPlus;
+          if (LamTem>0.1*Lambda)  Lambda = LamTem;
+          else  {
+            Lambda *= 0.1;
+            Lambda0 = Lambda;
+          }
+          if (Lambda>Lambda0)  {
+            Lambda  = Lambda0;
+            RetCode = 0;
+            for (i=1;i<=N;i++)
+              XPlus[i] = px0[i] + Lambda*P[i];
+          }
+        }
+
+      } while (RetCode>=2);
+
+      TakenLambda = Lambda;
+
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::GetMemory()  {
+      if (N!=NAlloc)  {
+        FreeMemory();
+        GetMatrixMemory ( Hsn   , N,N, 1,1 );
+        GetVectorMemory ( GPlus , N, 1 );
+        GetVectorMemory ( GradX , N, 1 );
+        GetVectorMemory ( HDiag , N, 1 );
+        GetVectorMemory ( SN    , N, 1 );
+        GetVectorMemory ( Sx    , N, 1 );
+        GetVectorMemory ( XPlus , N, 1 );
+        GetVectorMemory ( XOpt  , N, 1 );
+        GetVectorMemory ( Freese, N, 1 );
+        if (CalcHess)  {
+          GetVectorMemory ( StepSize , N, 1 );
+          GetVectorMemory ( FNeighbor, N, 1 );
+        } else  {
+          GetVectorMemory ( us       , N, 1 );
+          GetVectorMemory ( uy       , N, 1 );
+          GetVectorMemory ( ut       , N, 1 );
+        }
+        NAlloc = N;
+      }
+    }
+
+    void  BFGSMin::FreeMemory()  {
+      if (NAlloc>0)  {
+        FreeVectorMemory ( us       , 1 );
+        FreeVectorMemory ( uy       , 1 );
+        FreeVectorMemory ( ut       , 1 );
+        FreeVectorMemory ( Freese   , 1 );
+        FreeVectorMemory ( StepSize , 1 );
+        FreeVectorMemory ( FNeighbor, 1 );
+        FreeVectorMemory ( XOpt     , 1 );
+        FreeVectorMemory ( XPlus    , 1 );
+        FreeVectorMemory ( Sx       , 1 );
+        FreeVectorMemory ( SN       , 1 );
+        FreeVectorMemory ( HDiag    , 1 );
+        FreeVectorMemory ( GradX    , 1 );
+        FreeVectorMemory ( GPlus    , 1 );
+        FreeMatrixMemory ( Hsn      , NAlloc, 1,1 );
+      }
+      NAlloc = 0;
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::Relax()  {
+    int i;
+      if (FPlus>FOpt)  {
+        for (i=1;i<=N;i++)
+          XPlus[i] = XOpt[i];
+        FPlus = FOpt;
+      } else  {
+        for (i=1;i<=N;i++)
+          XOpt[i] = XPlus[i];
+        FOpt = FPlus;
+      }
+    }
+
+    void  BFGSMin::CopyPlus ( rvector x0 )  {
+    int i;
+      for (i=1;i<=N;i++)  {
+        x0   [i] = XPlus[i];
+        GradX[i] = GPlus[i];
+      }
+      Func = FPlus;
+    }
+
+
+    //  -------------------------------------------------------------------
+
+    void  BFGSMin::BFGS_Driver (  int        MinN,
+                                  rvector    x0,
+                                  rvector    TypX,
+                                  realtype & FuncValue,
+                                  int      & TerminationCode,
+                                  int        Digits,
+                                  int        ItnLmt,
+                                  realtype   TypF,
+                                  realtype   GrdTol,
+                                  realtype   StpTol,
+                                  realtype   MaxStp,
+                                  bool       Hess,
+                                  rvector    LowLimit,
+                                  rvector    TopLimit )  {
+
+    //  D6.1.1   :  Unconstrained Minimization Driver
+
+    int   i,RetCode;
+    int   ItnCnt;
+    bool  MaxTkn;
+
+      TL       = TopLimit;
+      LL       = LowLimit;
+      ForDiff  = true;
+      N        = MinN;
+      CalcHess = Hess;
+
+      ModF     = false;
+
+      GetMemory();
+
+      UMInCk ( x0,TypX,Digits,TypF,
+               GrdTol,StpTol,MaxStp,
+               ItnLmt );
+      if (TermCode!=BFGS_NoTermination)  {
+        FreeMemory();
+        FuncValue       = Func;
+        TerminationCode = TermCode;
+        return;
+      }
+
+      ItnCnt = 0;
+
+      MinFunc1 ( x0,Func );
+      if (TermCode!=BFGS_NoTermination)  {
+        FreeMemory();
+        FuncValue       = Func;
+        TerminationCode = TermCode;
+        return;
+      }
+      FOpt  = Func;
+      FPlus = Func;
+      for (i=1;i<=N;i++)  {
+        XOpt [i] = x0[i];
+        XPlus[i] = x0[i];
+      }
+      ModF = true;
+      Gradient ( x0,GradX,Func );
+      Print    ( ItnCnt,x0,GradX,Func );
+      for (i=1;i<=N;i++)
+        GPlus[i] = GradX[i];
+      if (TermCode!=BFGS_NoTermination)  {
+        Relax     ();
+        CopyPlus  ( x0 );
+        FreeMemory();
+        FuncValue       = Func;
+        TerminationCode = TermCode;
+        return;
+      }
+
+      UMStop0 ( x0,GradX );
+      if  (TermCode!=BFGS_NoTermination)  {
+        FreeMemory();
+        FuncValue       = Func;
+        TerminationCode = TermCode;
+        return;
+      }
+
+      if (!CalcHess)  InitHessUnFac ( Func,Hsn );
+
+      RetCode = 0;
+      while (TermCode==BFGS_NoTermination)  {
+        ItnCnt++;
+        if (RetCode>=0)  {
+          if (CalcHess)  {
+            FDHessF ( Func,x0 );
+            if (TermCode!=BFGS_NoTermination)  {
+              Relax     ();
+              CopyPlus  ( x0 );
+              FreeMemory();
+              FuncValue       = Func;
+              TerminationCode = TermCode;
+              return;
+            }
+          }
+          MdHess ( Hsn,HDiag );
+        }
+        ChSolve    ( N,Hsn,GradX,SN );
+        LineSearch ( x0,GradX,SN,Func,RetCode,MaxTkn );
+        if ((RetCode==1) && ForDiff)  {
+          RetCode = -1;
+          ForDiff = false;
+        } else
+          Relax();
+        if (TermCode!=BFGS_NoTermination)  {
+          Relax     ();
+          CopyPlus  ( x0 );
+          FreeMemory();
+          FuncValue       = Func;
+          TerminationCode = TermCode;
+          return;
+        } else
+          Gradient ( XPlus,GPlus,FPlus );
+        if (TermCode!=BFGS_NoTermination)  {
+          Relax     ();
+          CopyPlus  ( x0 );
+          FreeMemory();
+          FuncValue       = Func;
+          TerminationCode = TermCode;
+          return;
+        }
+        if (RetCode>=0)  {
+          UMStop ( x0,GPlus,RetCode,ItnCnt,MaxTkn );
+          if ((!CalcHess) && (TermCode==BFGS_NoTermination))
+            BFGSUnFac ( x0,XPlus,GradX,GPlus,false,HDiag,Hsn );
+        }
+        CopyPlus ( x0 );
+        Print    ( ItnCnt, x0,GradX,Func );
+      }
+
+      Relax     ();
+      FreeMemory();
+      FuncValue       = Func;
+      TerminationCode = TermCode;
+
+    }
+
+  }  // namespace math
+
+}  // namespace mmdb
+
diff --git a/mmdb2/mmdb_math_bfgsmin.h b/mmdb2/mmdb_math_bfgsmin.h
new file mode 100644
index 0000000..389ebe4
--- /dev/null
+++ b/mmdb2/mmdb_math_bfgsmin.h
@@ -0,0 +1,260 @@
+//  $Id: mmdb_math_bfgsmin.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  BFGSMin  <interface>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::math::BFGSMin  ( minimization driver )
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef  __MMDB_MATH_BFGSMin__
+#define  __MMDB_MATH_BFGSMin__
+
+#include <stdlib.h>
+
+#include "mmdb_mattype.h"
+#include "mmdb_math_linalg.h"
+
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  ==============================================================
+
+    enum BFGS_RC  {
+      BFGS_TooFewDigits       = -2,
+      BFGS_WrongSpaceDim      = -1,
+      BFGS_NoTermination      =  0,
+      BFGS_SmallGradient      =  1,
+      BFGS_SmallStep          =  2,
+      BFGS_LineSearchComplete =  3,
+      BFGS_IterationLimit     =  4,
+      BFGS_LargeSteps         =  5,
+      BFGS_Stopped            =  6
+    };
+
+    typedef void BFGSMinFunc ( void * UserData, int N, rvector X,
+                               realtype & F );
+    typedef BFGSMinFunc * PBFGSMinFunc;
+
+    typedef void BFGSPrintFunc ( void * UserData, int N, int Itn,
+                                 rvector X, rvector G, realtype F );
+    typedef BFGSPrintFunc * PBFGSPrintFunc;
+
+    DefineClass(BFGSMin);
+
+    class BFGSMin  {
+
+      public :
+
+        BFGSMin ();
+        virtual ~BFGSMin();
+
+        virtual void  MinFunc  ( rvector X, realtype & F );
+        virtual void  Print    ( int Itn, rvector X, rvector G,
+                                 realtype F );
+
+        void  SetMinFunction   ( void * UserData, PBFGSMinFunc   Fnc );
+        void  SetPrintFunction ( void * UserData, PBFGSPrintFunc Fnc );
+
+
+        // ======================================================
+        //
+        //    .--------------------------------------------.
+        //    |                                            |
+        //    |     UNCONSTRAINED MINIMIZATION DRIVER      |
+        //    |                                            |
+        //    `--------------------------------------------'
+        //
+        //    Finds a minimum of function F(X), X is vector [1..N],
+        //  defined by virtual MinFunc. Virtual Print provides
+        //  information on every iteration step.
+        //
+        //
+        //               Input  parameters  :
+        //             -----------------------
+        //
+        //    N        is the dimension the minimization space
+        //
+        //    x0       [1..N] is the initial point for minimization
+        //
+        //    TypX     [1..N] is the array of the typical ranges of
+        //          X - components,  which are used for the scaling.
+        //          If  TypX<=0.0  then  1.0  will be substituted
+        //
+        //    Digits   is the number of valid decimal digits in
+        //          the calculated value of minimizing function ( F ).
+        //          If  Digits<=0  then the Driver will consider
+        //          that the  F  is computed with usual machine's
+        //          noise
+        //
+        //    ItnLmt   is the maximum available number of iterations.
+        //          If  ItnLmt=0  then  100  will be substituted
+        //
+        //    TypF     is the expected absolute value of  F  in the
+        //          minimum,  which is used in the stop criterion.
+        //          If  TypF<=0.0  then  1.0  will be substituted
+        //
+        //    GrdTol   is the desired absolute value of the gradient
+        //          vector in the minimum of  F .  If  GrdTol<=0.0
+        //          then the some value correlated with machine's
+        //          noise will be substituted
+        //
+        //    StpTol   is the minimum available step for the minimi-
+        //          zation.  The execution stops if the distance
+        //          between two consequential approximation will be
+        //          less then  StpTol .  If  StpTol<=0.0  then the
+        //          some value correlated with machine's  noise
+        //          will be substituted
+        //
+        //    MaxStp   is the maximum available step for then minimi-
+        //          zation.  This parameter only prevents the appea-
+        //          rance of the too large steps,  but the execution
+        //          stops if more than  5  steps with length of MaxStep
+        //          will consequently appear.
+        //
+        //
+        //
+        //               Outpute  parameters  :
+        //             --------------------------
+        //
+        //    x0        will be the point at which the minimisation
+        //          had stopped
+        //
+        //    Func      will be the function's value at  x0
+        //
+        //    TermCode  will be the reason of stopping :
+        //
+        //         1 <=>  the norm of gradient vector at  x0  is
+        //               less than  GrdTol ;  the  x0  is probable
+        //               point of the minimum
+        //         2 <=>  the distance between two last approxima-
+        //               tions was less than  StpTol ;  the  x0
+        //               may be the point of minimum
+        //         3 <=>  the gradient length is greater than
+        //               GrdTol ,  but future minimization fails ;
+        //               it may be the consequence of the errors
+        //               at the computing of gradient, but also
+        //               x0 could be the point of minimum
+        //         4 <=>  the iteration limit had been exchausted
+        //         5 <=>  more than  5  steps with length of
+        //               MaxStp  had been made
+        //         6 <=>  the termination key ( Esc or End )
+        //               had been pressed.
+        //
+        //
+        // ========================================================
+
+        void  BFGS_Driver      ( int        MinN,
+                                 rvector    x0,
+                                 rvector    TypX,
+                                 realtype & FuncValue,
+                                 int      & TerminationCode,
+                                 int        Digits   = 0,
+                                 int        ItnLmt   = 0,
+                                 realtype   TypF     = 0.0,
+                                 realtype   GrdTol   = 0.0,
+                                 realtype   StpTol   = 0.0,
+                                 realtype   MaxStp   = MaxReal,
+                                 bool       Hess     = false,
+                                 rvector    LowLimit = NULL,
+                                 rvector    TopLimit = NULL );
+
+        void  Stop();  // generates stop signal to stop optimization
+
+
+      protected :
+
+        PBFGSMinFunc    MFunc;
+        void *          MFuncData;
+        PBFGSPrintFunc  PFunc;
+        void *          PFuncData;
+
+        int             N,NAlloc;
+        rmatrix         Hsn;
+        rvector         TL,LL,XOpt,XPlus,Sx,SN,HDiag,GradX,GPlus;
+        rvector         StepSize,FNeighbor;
+        rvector         us,uy,ut;
+        bvector         Freese;
+        realtype        Func,FPlus,FOpt;
+        realtype        TakenLambda;
+        bool            ForDiff;  // if True then forward differences are
+                                  // used for the 1st estimation of the
+                                  // Hessian (which is less expensive),
+                                  // otherwise central differences will
+                                  // be employed (which is more expensive).
+        bool            CalcHess;
+
+        realtype        Etha,SqrtEtha,CubertEtha,TpF,GrdEps,StpEps,MxStep;
+        realtype        SqrtEps;
+        int             CnsMax,MaxItn,TermCode;
+        bool            ModF;
+
+        void  MinFunc1      ( rvector X, realtype & F );
+        void  UMInCk        ( rvector  x0,     rvector  TypX,
+                              int      Digits, realtype TypF,
+                              realtype GrdTol, realtype StpTol,
+                              realtype MaxStp, int      ItnLmt );
+        void  UMStop0       ( rvector x0, rvector Grad );
+        void  UMStop        ( rvector x0, rvector Grad, int RetCode,
+                              int ItnCnt, bool MaxTkn );
+
+        virtual void Gradient ( rvector X, rvector G, realtype Fc );
+        virtual void FDHessF  ( realtype Fc, rvector X );
+
+        void  FDGrad        ( rvector X, rvector G, realtype Fc );
+        void  CDGrad        ( rvector X, rvector G );
+        void  MdHess        ( rmatrix H, rvector HDg );
+        void  InitHessUnFac ( realtype F,  rmatrix H );
+        void  BFGSUnFac     ( rvector  Xc,      rvector Xp,
+                              rvector  Gc,      rvector Gp,
+                              bool     AnalGrad, rvector HDg,
+                              rmatrix  H );
+        void  Choose_Lambda ( rvector X, rvector S, realtype & Lambda0 );
+        void  LineSearch    ( rvector    px0,       rvector   G,
+                              rvector    P,         realtype pFunc,
+                              int     & RetCode,    bool & MaxTkn );
+        void  GetMemory     ();
+        void  FreeMemory    ();
+        void  Relax         ();
+        void  CopyPlus      ( rvector x0 );
+
+    };
+
+  }
+
+}
+
+#endif
+
+
diff --git a/mmdb2/mmdb_math_fft.cpp b/mmdb2/mmdb_math_fft.cpp
new file mode 100755
index 0000000..bf449b3
--- /dev/null
+++ b/mmdb2/mmdb_math_fft.cpp
@@ -0,0 +1,338 @@
+//  $Id: mmdb_math_fft.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2005-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   FFT <implementation>
+//       ~~~~~~~~~
+//  **** Functions:  mmdb::math::FFT
+//       ~~~~~~~~~   mmdb::math::RealFFT
+//                   mmdb::math::TwoFFT
+//                   mmdb::math::Convolve
+//                   mmdb::math::mConvolve
+//
+//  (C) E.Krissinel  2005-2013
+//
+//  =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_fft.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    void  FFT ( rvector data, int nn, bool Forward )  {
+    //  Replaces data[1:2*nn] by its discrete Fourier transform,
+    //  if Forward is true; or replaces data[1:2*nn] by nn times its
+    //  inverse discrete Fourier transform if Forward is false.
+    //    On call,
+    //  data[i], i=1,3,5 ... nn-1 are real parts of function,
+    //  data[i], i=2,4,6 ... nn   are imaginary parts.
+    //    nn MUST be an integer power of 2 (this is not checked for!).
+    //    User should allocate data with GetVectorMemory and deallocate
+    //  it with FreeVectorMemory to assure correct managing of indices
+    //  1..2*nn (not 0..2*nn-1).
+    //    On return,
+    //  data[i], i=1,3,5 ... nn-1 are real parts, and
+    //  data[i], i=2,4,6 ... nn   are imaginary parts of positive part
+    //           of spectra, with frequences
+    //            0,1/(nn*D),2/(nn*D) ... (nn/2-1)/(nn*D);
+    //  data[nn+1] and data[nn+2] are real and imaginary parts for
+    //           the frequances +/-1/(2*D)
+    //  data[i], i=nn+3,nn+5,nn+7 ... 2*nn-1  are real parts, and
+    //  data[i], i=nn+4,nn+6,nn+8 ... 2*nn    are imaginary parts of
+    //           negative part of the spectra with frequences
+    //            -(nn/2-1)/(nn*D), -(nn/2-2)/(nn*D), -1/(nn*D)
+    //
+    int         i,istep,j,m,mmax,n;
+    realtype    tempi,tempr;
+    long double theta,wi,wpi,wpr,wr,wtemp;  // this should be of
+                                            // maximal precision
+      n = 2*nn;
+      j = 1;
+      for (i=1;i<=n;i+=2)  {
+        if (j>i)  {
+          tempr     = data[j];
+          tempi     = data[j+1];
+          data[j]   = data[i];
+          data[j+1] = data[i+1];
+          data[i]   = tempr;
+          data[i+1] = tempi;
+        }
+        m = n/2;
+        while ((m>=2) && (j>m)) {
+          j -= m;
+          m /= 2;
+        }
+        j += m;
+      }
+      mmax = 2;
+      while (n>mmax)  {
+        istep = 2*mmax;
+        theta = 2.0*Pi/mmax;
+        if (!Forward)  theta = -theta;
+        wpr = sin(0.5*theta);
+        wpr = -2.0*wpr*wpr;
+        wpi = sin(theta);
+        wr  = 1.0;
+        wi  = 0.0;
+        for (m=1;m<=mmax;m+=2)  {
+          for (i=m;i<=n;i+=istep)  {
+            j     = i + mmax;
+            tempr = wr*data[j]   - wi*data[j+1];
+            tempi = wr*data[j+1] + wi*data[j];
+            data[j]   = data[i]   - tempr;
+            data[j+1] = data[i+1] - tempi;
+            data[i]   = data[i]   + tempr;
+            data[i+1] = data[i+1] + tempi;
+          }
+          wtemp = wr;
+          wr    = wr*wpr - wi*wpi + wr;
+          wi    = wi*wpr + wtemp*wpi + wi;
+        }
+        mmax = istep;
+      }
+    }
+
+    void  RealFFT ( rvector data, int n, bool Forward )  {
+    //    Calculates the Fourier transform of a set of n real-valued data
+    //  points. Replaces this data (which is stored in array data[1:n])
+    //  by the positive frequency half of its complex Fourier transform.
+    //  The real-valued first and last components of the complex transform
+    //  are returned as elements data[1] and data[2], respectively.
+    //  n MUST be a power of 2. This routine also calculates the
+    //  inverse transform of a complex data array if it is the transform
+    //  of real data (Result in this case must be multiplied by 2/n).
+    //    Array data should be allocated with GetVectorMemory.
+    //
+    int         i,i1,i2,i3,i4,n2p3;
+    realtype    c1,c2,h1i,h1r,h2i,h2r;
+    long double theta,wi,wpi,wpr,wr,wtemp;
+
+      theta = 2.0*Pi/n;
+      c1    = 0.5;
+      if (Forward) {
+        c2 = -0.5;
+        FFT ( data,n/2,true );
+      } else  {
+        c2    = 0.5;
+        theta = -theta;
+      }
+      wpr  = sin(0.5*theta);
+      wpr  = -2.0*wpr*wpr;
+      wpi  = sin(theta);
+      wr   = 1.0 + wpr;
+      wi   = wpi;
+      n2p3 = n + 3;
+      for (i=2;i<=n/4;i++)  {
+        i1 = 2*i - 1;
+        i2 = i1  + 1;
+        i3 = n2p3 - i2;
+        i4 = i3 + 1;
+        h1r = c1*(data[i1] + data[i3]);
+        h1i = c1*(data[i2] - data[i4]);
+        h2r = -c2*(data[i2] + data[i4]);
+        h2i = c2*(data[i1] - data[i3]);
+        data[i1] = h1r + wr*h2r - wi*h2i;
+        data[i2] = h1i + wr*h2i + wi*h2r;
+        data[i3] = h1r - wr*h2r + wi*h2i;
+        data[i4] = -h1i + wr*h2i + wi*h2r;
+        wtemp = wr;
+        wr = wr*wpr - wi*wpi + wr;
+        wi = wi*wpr + wtemp*wpi + wi;
+      }
+      if (Forward)  {
+        h1r = data[1];
+        data[1] = h1r + data[2];
+        data[2] = h1r - data[2];
+      } else  {
+        h1r = data[1];
+        data[1] = c1*(h1r+data[2]);
+        data[2] = c1*(h1r-data[2]);
+        FFT ( data,n/2,false );
+      }
+    }
+
+    void TwoFFT ( rvector data1, rvector data2,
+                  rvector fft1,  rvector fft2, int n )  {
+    //  Given two real input arrays data1[1:n] and data2[1:n],
+    // this routine calls FFT and returns two "complex" output
+    // arrays fft1[1:2*n] and fft2[1:2*n] (2*i-1 ith real,
+    // 2*i ith imaginary), which contain the discrete Fourier
+    // transforms of the respective data arrays.  n MUST be
+    // an integer power of 2.
+    int      i,j,n2, bj,bn;
+    realtype h1r,h1i,h2r,h2i;
+      i = 1;
+      for (j=1;j<=n;j++)  {
+        fft1[i++] = data1[j];
+        fft1[i++] = data2[j];
+      }
+      FFT ( fft1,n,true );
+      fft2[1] = fft1[2];    fft2[2] = 0.0;
+      fft1[2] = 0.0;
+      n2 = n + 2;
+      for (j=2;j<=n/2+1;j++)  {
+        bj = 2*j-1;    bn = 2*(n2-j)-1;
+        h1r = 0.5*(fft1[bj]   + fft1[bn]);
+        h1i = 0.5*(fft1[bj+1] - fft1[bn+1]);
+        h2r = 0.5*(fft1[bj+1] + fft1[bn+1]);
+        h2i = 0.5*(fft1[bn]   - fft1[bj]);
+        fft1[bj] = h1r;    fft1[bj+1] = h1i;
+        fft1[bn] = h1r;    fft1[bn+1] = -h1i;
+        fft2[bj] = h2r;    fft2[bj+1] = h2i;
+        fft2[bn] = h2r;    fft2[bn+1] = -h2i;
+      }
+    }
+
+    void Convolve ( rvector data, int n, rvector respns, int m,
+                    rvector ans,  bool Conv )  {
+    //  Convolves or Deconvolves a real data set data[1:n] (including
+    // any user-supplied zero padding) with a response function
+    // respns[1..n], stored in wrap-around order in a real array of
+    // length m<n (m should be an odd (3,5,7...) integer).  Wrap-around
+    // order means that the first half of the array contains the impulse
+    // response function at positive times, while the second half of
+    // the array contains the impulse response function at negative
+    // times, counting down from the highest element respns[m]. On
+    // input Conv=true for convolution, false for deconvolution.
+    // The answer is returned in the first n component of ans.
+    // However, ans must be supplied in the calling program with
+    // length at least 2*n, for consistency with TwoFFT.  n MUST
+    // be an integer power of 2.
+    //
+    int      i,no2,rp,ip;
+    rvector  fft;
+    realtype B,D;
+
+      GetVectorMemory ( fft,2*n,1 );
+      for (i=1;i<=(m-1)/2;i++)
+        respns[n+1-i] = respns[m+1-i];
+      for (i=(m+3)/2;i<=n-(m-1)/2;i++)
+        respns[i] = 0.0;
+
+      TwoFFT ( data,respns,fft,ans,n );
+
+      no2 = n/2;
+      rp  = 1;   // pointer to real part
+      ip  = 2;   // pointer to imaginary part
+      for (i=1;i<=no2+1;i++)  {
+        if (Conv) {
+          B       = (fft[rp]*ans[rp] - fft[ip]*ans[ip])/no2;
+          ans[ip] = (fft[ip]*ans[rp] + fft[rp]*ans[ip])/no2;
+          ans[rp] = B;
+        } else  {
+          D = (ans[rp]*ans[rp] + ans[ip]*ans[ip])*no2;
+          if (D==0.0)  {
+            //  poor deconvolve at zero response
+            ans[rp] = 0.0;
+            ans[ip] = 0.0;
+          } else  {
+            B       = (fft[rp]*ans[rp] + fft[ip]*ans[ip])/D;
+            ans[ip] = (fft[ip]*ans[rp] - fft[rp]*ans[ip])/D;
+            ans[rp] = B;
+          }
+        }
+        rp += 2;
+        ip += 2;
+      }
+
+      ans[2] = ans[2*no2+1];
+      FreeVectorMemory ( fft,1 );
+
+      RealFFT ( ans,n,false );
+
+    }
+
+
+    void mConvolve ( rvector data, int n, int m )  {
+    //
+    //   Replaces array data[0..n-1] with the result of m recursive
+    // convolutions (m>1) defined as
+    //
+    //      data_m = data (*) data_{m-1}
+    //
+    // where data_m is the result of mth convolution, data_0=data.
+    // The definition of the convolution is
+    //
+    //      [a (*) b]_i = Sum_j { a_j * b_{i-j} }
+    //
+    //   On input, data[] is considered as containing the signal
+    // sampled at both positive and negative times in the wrap-around
+    // order, that is
+    //
+    //    data[i], 0<=i<n/2   signal sampled at times  dt*i
+    //    data[i], n/2<=i<n   signal sampled at times -dt*(n-i)
+    //
+    // and the same wrap-around order is used to interprete the output
+    // data. This means that if only m positive sampling times are
+    // used, the length of data must be at least n=2*m, the rest being
+    // padded with zeroes.
+    //
+    //   The number of sampling nodes n *must* be an integer power of
+    // two, i.e. 2,4,8,16 ... .
+    //
+    realtype R,G,phi,B,m2,n2,d1;
+    int      i,m1;
+
+      if (m<1)  return;
+
+      RealFFT ( data-1,n,true );
+
+      m1 = m+1;
+      m2 = m1/2.0;
+      n2 = 2.0/n;
+      d1 = data[1];
+      for (i=0;i<=n;i+=2)  {
+        if (i<n)  {
+          R = data[i];
+          if (i>1) G = data[i+1];
+              else G = 0.0;
+        } else  {
+          R = d1;
+          G = 0.0;
+        }
+        phi = atan2(G,R) * m1;
+        B   = pow(R*R+G*G,m2);
+        R   = B*cos(phi);
+        G   = B*sin(phi);
+        if (i<n)  {
+          data[i]   = R*n2;
+          data[i+1] = G*n2;
+        } else
+          data[1] = R*n2;
+      }
+
+      RealFFT ( data-1,n,false );
+
+    }
+
+  }  // namespace math
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_math_fft.h b/mmdb2/mmdb_math_fft.h
new file mode 100755
index 0000000..6d91380
--- /dev/null
+++ b/mmdb2/mmdb_math_fft.h
@@ -0,0 +1,93 @@
+//  $Id: mmdb_math_fft.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2005-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   FFT <interface>
+//       ~~~~~~~~~
+//  **** Functions:  mmdb::math::FFT
+//       ~~~~~~~~~   mmdb::math::RealFFT
+//                   mmdb::math::TwoFFT
+//                   mmdb::math::Convolve
+//                   mmdb::math::mConvolve
+//
+//  (C) E.Krissinel  2005-2013
+//
+//  =================================================================
+//
+
+#ifndef  __FFT__
+#define  __FFT__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    extern void FFT      ( rvector data, int nn, bool Forward=true );
+
+    extern void RealFFT  ( rvector data, int n,  bool Forward=true );
+
+    extern void TwoFFT   ( rvector data1, rvector data2,
+                           rvector fft1,  rvector fft2, int n );
+
+    extern void Convolve ( rvector data, int n, rvector respns, int m,
+                           rvector ans,  bool Conv=true );
+
+
+    //   mConvolve ( data,n,m ) replaces array data[0..n-1] with the result
+    // of m recursive convolutions (m>1) defined as
+    //
+    //      data_m = data (*) data_{m-1}
+    //
+    // where data_m is the result of mth convolution, data_0=data.
+    // The definition of the convolution is
+    //
+    //      [a (*) b]_i = Sum_j { a_j * b_{i-j} }
+    //
+    //   On input, data[] is considered as containing the signal
+    // sampled at both positive and negative times in the wrap-around
+    // order, that is
+    //
+    //    data[i], 0<=i<n/2   signal sampled at times  dt*i
+    //    data[i], n/2<=i<n   signal sampled at times -dt*(n-i)
+    //
+    // and the same wrap-around order is used to interprete the output
+    // data. This means that if only m positive sampling times are
+    // used, the length of data must be at least n=2*m, the rest being
+    // padded with zeroes.
+    //
+    //   The number of sampling nodes n *must* be an integer power of
+    // two, i.e. 2,4,8,16 ... .
+    //
+    extern void mConvolve ( rvector data, int n, int m );
+
+  }  // namespace math
+
+}  // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_math_graph.cpp b/mmdb2/mmdb_math_graph.cpp
new file mode 100644
index 0000000..b927665
--- /dev/null
+++ b/mmdb2/mmdb_math_graph.cpp
@@ -0,0 +1,2461 @@
+//  $Id: mmdb_math_graph.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_math_graph  <implementation>
+//       ~~~~~~~~~
+//  **** Namespace: mmdb::math::
+//       ~~~~~~~~~~
+//  **** Classes :  Vertex     ( graph vertex                        )
+//       ~~~~~~~~~  Edge       ( graph edge                          )
+//                  Graph      ( structural graph                    )
+//                  GMatch      ( GMatch of structural graphs          )
+//                  GraphMatch ( CSIA algorithms for graphs GMatching )
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  When used, please cite:
+//
+//   Krissinel, E. and Henrick, K. (2004)
+//   Common subgraph isomorphism detection by backtracking search.
+//   Software - Practice and Experience, 34, 591-607.
+//
+//  =================================================================
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mmdb_math_graph.h"
+#include "mmdb_tables.h"
+
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  =========================  Vertex  ==========================
+
+    Vertex::Vertex() : io::Stream()  {
+      InitVertex();
+    }
+
+    Vertex::Vertex ( io::RPStream Object ) : io::Stream(Object)  {
+      InitVertex();
+    }
+
+    Vertex::Vertex ( cpstr chem_elem ) : io::Stream()  {
+      InitVertex();
+      SetVertex ( chem_elem );
+    }
+
+    Vertex::Vertex ( int vtype ) : io::Stream()  {
+      InitVertex();
+      SetVertex ( vtype );
+    }
+
+    Vertex::Vertex ( int vtype, cpstr vname ) : io::Stream()  {
+      InitVertex();
+      SetVertex ( vtype,vname );
+    }
+
+    Vertex::Vertex ( cpstr chem_elem, cpstr vname ) : io::Stream()  {
+      InitVertex ();
+      SetVertex  ( chem_elem  );
+      CreateCopy ( name,vname );
+    }
+
+    Vertex::~Vertex() {
+      if (name) delete[] name;
+    }
+
+    void  Vertex::InitVertex()  {
+      name     = NULL;
+      type     = 0;
+      type_ext = 0;
+      property = 0;
+      id       = 0;
+      user_id  = 0;
+    }
+
+
+    void  Vertex::SetVertex ( cpstr chem_elem )  {
+    //   This function generates vertex type according to a chemical
+    // element name passed in chem_elem.
+    //
+    //   The element type has the following meaning:
+    //
+    //     0xCHSSTTTT
+    //
+    // where
+    //        T - resreved for elemenmt type
+    //        S - resreved for symmetry relief
+    //        H - reserved for hydrogen bonds
+    //        C - resreved for chirality flags
+    //
+    // Note that when more than 2 symbols are used for chemical element
+    // name (custom use), fields S may be reallocated for element type
+    // and then symmetry relief becomes impossible.
+    //
+      CreateCopy ( name,chem_elem );
+      type = getElementNo ( chem_elem );
+      if (type==ELEMENT_UNKNOWN)  {
+        type = 0;
+        if (name[0])  {
+          type = (int)name[0];
+          if (name[1])  {
+            type = type*256+(int)name[1];
+            if (name[2])  type = type*256+(int)name[2];
+          }
+        }
+        type += nElementNames;
+      }
+    }
+
+    void  Vertex::SetVertex ( int vtype )  {
+    //  This function sets vertex type. See comments above for
+    // the general rule for vertex types implied by this code.
+    char N[50];
+    int  type0;
+      type  = vtype;
+      type0 = vtype & TYPE_MASK;
+      if ((type0>=1) && (type0<=nElementNames))
+        CreateCopy ( name,ElementName[type0-1] );
+      else  {
+        sprintf    ( N,"%i",type );
+        CreateCopy ( name,N );
+      }
+    }
+
+    void  Vertex::SetType ( int vtype )  {
+      type = vtype;
+    }
+
+    void  Vertex::SetTypeExt  ( int typeExt )  {
+      type_ext = typeExt;
+    }
+
+    void  Vertex::SetVertex ( int vtype, cpstr vname )  {
+      type = vtype;
+      CreateCopy ( name,vname );
+    }
+
+    void  Vertex::SetName ( cpstr vname )  {
+      CreateCopy ( name,vname );
+    }
+
+    void  Vertex::SetID ( int vid )  {
+      id = vid;
+    }
+
+    void  Vertex::SetProperty ( int vprop )  {
+      property = vprop;
+    }
+
+    int   Vertex::GetNBonds()  {
+      return  ((type & HYDROGEN_BOND) >> 24);
+    }
+
+    void  Vertex::AddBond()  {
+    int nb = GetNBonds()+1;
+      type &= ~HYDROGEN_BOND;
+      type |= nb << 24;
+    }
+
+    void  Vertex::CopyNBonds ( PVertex V )  {
+    int nb = V->GetNBonds();
+      type &= ~HYDROGEN_BOND;
+      type |= nb << 24;
+    }
+
+    void  Vertex::RemoveChirality()  {
+      type &= CHIRAL_MASK;
+    }
+
+    void  Vertex::LeaveChirality ( int eltype )  {
+    // leaves chirality only on specified elements
+    int vtype;
+      vtype = type & CHIRAL_MASK;
+      if (vtype!=eltype)  type = vtype;
+    }
+
+    void  Vertex::SaveType()  {
+      user_id = type;
+    }
+
+    void  Vertex::RestoreType()  {
+      type = user_id;
+    }
+
+    void  Vertex::CopyType ( PVertex V )  {
+      type = V->type;
+    }
+
+
+    void  Vertex::Print ( int PKey )  {
+      if (PKey!=0)
+            printf ( "    name    type" );
+      else  printf ( " %10s  %5i",name,type );
+    }
+
+    void  Vertex::Copy ( PVertex V )  {
+      CreateCopy ( name,V->name );
+      type     = V->type;
+      type_ext = V->type_ext;
+      property = V->property;
+      id       = V->id;
+      user_id  = V->user_id;
+    }
+
+    void  Vertex::write ( io::RFile f )  {
+    int Version=2;
+      f.WriteInt    ( &Version  );
+      f.CreateWrite ( name      );
+      f.WriteInt    ( &type     );
+      f.WriteInt    ( &property );
+      f.WriteInt    ( &id       );
+      f.WriteInt    ( &user_id  );
+      f.WriteInt    ( &type_ext );
+    }
+
+    void  Vertex::read  ( io::RFile f )  {
+    int Version;
+      f.ReadInt    ( &Version  );
+      f.CreateRead ( name      );
+      f.ReadInt    ( &type     );
+      f.ReadInt    ( &property );
+      f.ReadInt    ( &id       );
+      f.ReadInt    ( &user_id  );
+      if (Version>1)  f.ReadInt ( &type_ext );
+                else  type_ext = 0;
+    }
+
+    void  Vertex::mem_write ( pstr S, int & l )  {
+    byte Version=2;
+      mmdb::mem_write_byte ( Version,S,l );
+      mmdb::mem_write ( name    ,S,l );
+      mmdb::mem_write ( type    ,S,l );
+      mmdb::mem_write ( property,S,l );
+      mmdb::mem_write ( id      ,S,l );
+      mmdb::mem_write ( user_id ,S,l );
+      mmdb::mem_write ( type_ext,S,l );
+    }
+
+    void  Vertex::mem_read ( cpstr S, int & l )  {
+    byte Version;
+      mmdb::mem_read_byte ( Version,S,l );
+      mmdb::mem_read ( name    ,S,l );
+      mmdb::mem_read ( type    ,S,l );
+      mmdb::mem_read ( property,S,l );
+      mmdb::mem_read ( id      ,S,l );
+      mmdb::mem_read ( user_id ,S,l );
+      mmdb::mem_read ( type_ext,S,l );
+    }
+
+    MakeStreamFunctions(Vertex)
+
+
+
+    //  ===========================  Edge  =============================
+
+    Edge::Edge() : io::Stream()  {
+      InitEdge();
+    }
+
+    Edge::Edge ( io::RPStream Object ) : io::Stream(Object)  {
+      InitEdge();
+    }
+
+    Edge::Edge ( int vx1, int vx2, int btype )  {
+      InitEdge();
+      SetEdge ( vx1,vx2,btype );
+    }
+
+    Edge::~Edge()  {}
+
+    void  Edge::InitEdge()  {
+      v1       = 0;
+      v2       = 0;
+      type     = 0;
+      property = 0;
+    }
+
+
+    #define NofBondTypes  4
+
+    static pstr BondType[NofBondTypes+1] = {
+      pstr("SING"), pstr("DOUB"), pstr("AROM"), pstr("TRIP"),
+      pstr("")  // should be here for safety
+    };
+
+
+    void  Edge::SetEdge ( int vx1, int vx2, cpstr btype )  {
+      v1   = vx1;
+      v2   = vx2;
+      type = 0;
+      while (type<NofBondTypes)
+        if (!strncasecmp(btype,BondType[type],4))  break;
+                                             else  type++;
+      if (type>=NofBondTypes)  {
+        type = 0;
+        if (btype[0])  type = (int)btype[0];
+        if (btype[1])  type = type*16+(int)btype[1];
+        if (btype[2])  type = type*16+(int)btype[2];
+        type += NofBondTypes;
+      }
+      type++;
+    }
+
+    void  Edge::SetEdge ( int vx1, int vx2, int btype )  {
+      v1   = vx1;
+      v2   = vx2;
+      type = btype;
+    }
+
+    void  Edge::SetType ( int btype )  {
+      type = btype;
+    }
+
+    void  Edge::SetProperty ( int eprop )  {
+      property = eprop;
+    }
+
+    void  Edge::SaveType()  {
+      property = type;
+    }
+
+    void  Edge::RestoreType()  {
+      type = property;
+    }
+
+    void  Edge::Print ( int PKey )  {
+      if (PKey!=0)
+            printf ( "   v1  v2  type" );
+      else  printf ( " %5i %5i  %5i",v1,v2,type );
+    }
+
+    void  Edge::Copy ( PEdge G )  {
+      v1       = G->v1;
+      v2       = G->v2;
+      type     = G->type;
+      property = G->property;
+    }
+
+    void  Edge::write ( io::RFile f )  {
+    int Version=1;
+      f.WriteInt ( &Version  );
+      f.WriteInt ( &v1       );
+      f.WriteInt ( &v2       );
+      f.WriteInt ( &type     );
+      f.WriteInt ( &property );
+    }
+
+    void  Edge::read  ( io::RFile f )  {
+    int Version;
+      f.ReadInt ( &Version  );
+      f.ReadInt ( &v1       );
+      f.ReadInt ( &v2       );
+      f.ReadInt ( &type     );
+      f.ReadInt ( &property );
+    }
+
+    void  Edge::mem_write ( pstr S, int & l )  {
+    byte Version=1;
+      mmdb::mem_write_byte ( Version,S,l );
+      mmdb::mem_write ( v1      ,S,l );
+      mmdb::mem_write ( v2      ,S,l );
+      mmdb::mem_write ( type    ,S,l );
+      mmdb::mem_write ( property,S,l );
+    }
+
+    void  Edge::mem_read ( cpstr S, int & l )  {
+    byte Version;
+      mmdb::mem_read_byte ( Version,S,l );
+      mmdb::mem_read ( v1      ,S,l );
+      mmdb::mem_read ( v2      ,S,l );
+      mmdb::mem_read ( type    ,S,l );
+      mmdb::mem_read ( property,S,l );
+    }
+
+    MakeStreamFunctions(Edge)
+
+
+    //  ==========================  Graph  ============================
+
+    Graph::Graph() : io::Stream()  {
+      InitGraph();
+    }
+
+    Graph::Graph ( PResidue R, cpstr altLoc ) : io::Stream()  {
+      InitGraph();
+      MakeGraph ( R,altLoc );
+    }
+
+    Graph::Graph ( io::RPStream Object ) : io::Stream(Object)  {
+      InitGraph();
+    }
+
+    Graph::~Graph()  {
+      FreeMemory();
+    }
+
+    void Graph::InitGraph()  {
+      nVAlloc      = 0;
+      nEAlloc      = 0;
+      nGAlloc      = 0;
+      nVertices    = 0;
+      nEdges       = 0;
+      nAllVertices = 0;
+      nAllEdges    = 0;
+      vertex       = NULL;
+      edge         = NULL;
+      graph        = NULL;
+      name         = NULL;
+      CreateCopy ( name,pstr("UNNAMED") );
+    }
+
+    void Graph::FreeMemory()  {
+    int i;
+
+      if (vertex)  {
+        for (i=0;i<nVAlloc;i++)
+          if (vertex[i])
+            delete vertex[i];
+        delete[] vertex;
+      }
+      nVAlloc      = 0;
+      nVertices    = 0;
+      nAllVertices = 0;
+      vertex       = NULL;
+
+      if (edge)  {
+        for (i=0;i<nEAlloc;i++)
+          if (edge[i])
+            delete edge[i];
+        delete[] edge;
+      }
+      nEAlloc   = 0;
+      nEdges    = 0;
+      nAllEdges = 0;
+      edge      = NULL;
+
+      FreeMatrixMemory ( graph,nGAlloc,1,1 );
+      nGAlloc = 0;
+
+      if (name)  delete[] name;
+      name = NULL;
+
+    }
+
+    void  Graph::Reset()  {
+      FreeMemory();
+      CreateCopy ( name,pstr("UNNAMED") );
+    }
+
+    void  Graph::SetName ( cpstr gname )  {
+      CreateCopy ( name,gname );
+    }
+
+
+    static int AllocPortion = 100;
+
+    void  SetGraphAllocPortion ( int alloc_portion )  {
+      AllocPortion = alloc_portion;
+    }
+
+    void  Graph::AddVertex ( PVertex V )  {
+    int        i;
+    PVertex * V1;
+
+      if (nAllVertices>=nVAlloc)  {
+        nVAlloc += AllocPortion;
+        V1       = new PVertex[nVAlloc];
+        for (i=0;i<nAllVertices;i++)
+          V1[i] = vertex[i];
+        for (i=nAllVertices;i<nVAlloc;i++)
+          V1[i] = NULL;
+        if (vertex)  delete[] vertex;
+        vertex = V1;
+      }
+      if (vertex[nAllVertices])
+        delete vertex[nAllVertices];
+      vertex[nAllVertices] = V;
+      nAllVertices++;
+      nVertices = nAllVertices;
+
+    }
+
+    void  Graph::SetVertices ( PPVertex V, int vlen )  {
+      if (nVAlloc>0)  FreeMemory();
+      vertex       = V;
+      nVertices    = vlen;
+      nAllVertices = vlen;
+      nVAlloc      = vlen;
+    }
+
+    int  Graph::GetVertexID ( int vertexNo )  {
+      if ((vertexNo>0) && (vertexNo<=nAllVertices))
+            return vertex[vertexNo-1]->GetID();
+      else  return MinInt4;
+    }
+
+    int  Graph::GetNBondedVertices ( int vertexNo )  {
+      if ((vertexNo>0) && (vertexNo<=nAllVertices))  {
+        if (vertex[vertexNo-1])
+          return vertex[vertexNo-1]->GetNBonds();
+      }
+      return 0;
+    }
+
+    int  Graph::GetBondedVertexID ( int vertexNo, int bond_vx_type,
+                                    int bondNo )  {
+    int i,k, v1,v2;
+      if ((vertexNo>0) && (vertexNo<=nAllVertices))  {
+        if (vertex[vertexNo-1])  {
+          if (vertex[vertexNo-1]->GetNBonds()>=bondNo)  {
+            k = 0;
+            for (i=0;(i<nAllEdges) && (!k);i++)
+              if (edge[i])  {
+                v1 = edge[i]->v1;
+                v2 = edge[i]->v2;
+                if ((v1==vertexNo) &&
+                    ((vertex[v2-1]->type & (int)TYPE_MASK) ==
+                                                       bond_vx_type) &&
+                     (vertex[v2-1]->GetNBonds()==bondNo))
+                   k = v2;
+                if ((v2==vertexNo) &&
+                    ((vertex[v1-1]->type & (int)TYPE_MASK) ==
+                                                       bond_vx_type) &&
+                     (vertex[v2-1]->GetNBonds()==bondNo))
+                   k = v1;
+              }
+            if (k)  return vertex[k-1]->GetID();
+          }
+        }
+      }
+      return MinInt4;
+    }
+
+    PVertex Graph::GetVertex ( int vertexNo )  {
+      if ((vertexNo>0) && (vertexNo<=nAllVertices))
+            return vertex[vertexNo-1];
+      else  return NULL;
+    }
+
+    int  Graph::GetVertexNo ( cpstr vname )  {
+    int  i,k;
+      k = 0;
+      if (vname)
+        for (i=0;(i<nAllVertices) && (!k);i++)
+          if (!strcmp(vname,vertex[i]->name))
+            k = i+1;
+      return k;
+    }
+
+    PEdge Graph::GetEdge ( int edgeNo )  {
+      if ((edgeNo>0) && (edgeNo<=nAllEdges))
+            return edge[edgeNo-1];
+      else  return NULL;
+    }
+
+    void  Graph::AddEdge ( PEdge G )  {
+    int    i;
+    PPEdge G1;
+
+      if (nAllEdges>=nEAlloc)  {
+        nEAlloc += AllocPortion;
+        G1       = new PEdge[nEAlloc];
+        for (i=0;i<nAllEdges;i++)
+          G1[i] = edge[i];
+        for (i=nAllEdges;i<nEAlloc;i++)
+          G1[i] = NULL;
+        if (edge)  delete[] edge;
+        edge = G1;
+      }
+      if (edge[nAllEdges])
+        delete edge[nAllEdges];
+      edge[nAllEdges] = G;
+      nAllEdges++;
+      nEdges = nAllEdges;
+
+    }
+
+    void  Graph::SetEdges ( PPEdge G, int glen )  {
+      if (nEAlloc>0)  FreeMemory();
+      edge      = G;
+      nEdges    = glen;
+      nAllEdges = glen;
+      nEAlloc   = glen;
+    }
+
+    void  Graph::GetVertices ( PPVertex & V, int & nV )  {
+      V  = vertex;
+      nV = nVertices;
+    }
+
+    void  Graph::GetEdges ( PPEdge & E, int & nE )  {
+      E  = edge;
+      nE = nEdges;
+    }
+
+
+    int  Graph::MakeGraph ( PResidue R, cpstr altLoc )  {
+    int      i,j, a1,a2,e1,e2, nAltLocs,alflag, rc;
+    bool     B;
+    rvector  occupancy;
+    AltLoc   aLoc;
+    PAltLoc  aL;
+    realtype dx,dy,dz, sr;
+    PEdge    G;
+
+      rc = MKGRAPH_Ok;
+      //  reset graph
+      FreeMemory();
+
+      occupancy = NULL;
+      aL        = NULL;
+      R->GetAltLocations ( nAltLocs,aL,occupancy,alflag );
+      if (nAltLocs<=0)  return MKGRAPH_NoAtoms;
+
+      if (altLoc)  strcpy ( aLoc,altLoc );
+             else  aLoc[0] = char(0);
+      if (nAltLocs<=1)  {
+        // Only one alt code is there, check if it is what was ordered
+        if (strcmp(aLoc,aL[0]))  {
+          rc = MKGRAPH_ChangedAltLoc;
+          strcpy ( aLoc,aL[0] );
+        }
+      } else if ((alflag & ALF_Mess) ||
+                 ((alflag & ALF_NoEmptyAltLoc) && (!aLoc[0])))  {
+        // There is a mess in the residue alt codes, or empty alt code
+        // does not designate a conformation but ordered. In this
+        // situation build graph for maximal-occupancy conformation
+        // and store its altLoc in aLoc.
+        rc = MKGRAPH_MaxOccupancy;
+        dx = -2.0;
+        for (i=0;i<nAltLocs;i++)
+          if ((aL[i][0]) && (occupancy[i]>dx))  {
+            dx = occupancy[i];
+            strcpy ( aLoc,aL[i] );
+          }
+      }
+
+      SetName ( R->name );
+
+      nVAlloc = R->nAtoms;  // upper estimate for vertices to allocate
+      if (nVAlloc<=0)  {
+        if (aL)  delete[] aL;
+        FreeVectorMemory ( occupancy,0 );
+        return MKGRAPH_NoAtoms;
+      }
+
+      //  allocate vertex array
+      vertex = new PVertex[nVAlloc];
+      for (i=0;i<nVAlloc;i++)
+        vertex[i] = NULL;
+
+      //  make vertices
+      for (i=0;i<R->nAtoms;i++)
+        if (R->atom[i])  {
+          if (!R->atom[i]->Ter)  {
+            if (nAltLocs>1)  {
+              // This is a many-altcode residue. aLoc contains the altcode
+              // that has to be included. Check on it:
+              B = !strcmp(aLoc,R->atom[i]->altLoc);
+              if ((!B) && (!R->atom[i]->altLoc[0]))  {
+                // We got a non-aLoc code that is an "empty-altcode".
+                // Check if this atom has the altcode that we need.
+                for (j=i+1;(j<R->nAtoms) && (!B);j++)
+                  if (R->atom[j])  {
+                    if ((!R->atom[j]->Ter) &&
+                        (!strcmp(R->atom[j]->name,R->atom[i]->name)))
+                      B = !strcmp(aLoc,R->atom[j]->altLoc);
+                  }
+                // if altcode=aLoc is not there for the atom (B is set
+                // false) then we take its "empty-code" location
+                B = !B;
+              }
+            } else
+              B = true;
+            if (B)  {
+              vertex[nVertices] = new Vertex ( R->atom[i]->element,
+                                               R->atom[i]->name );
+              vertex[nVertices]->id      = nVertices;
+              vertex[nVertices]->user_id = i;
+              nVertices++;
+            }
+          }
+        }
+
+      if (nVertices<=0)  {
+        if (aL)  delete[] aL;
+        FreeVectorMemory ( occupancy,0 );
+        return MKGRAPH_NoAtoms;
+      }
+
+      //  make edges
+      nEAlloc = 3*nVertices;
+      edge    = new PEdge[nEAlloc];
+      for (i=0;i<nEAlloc;i++)
+        edge[i] = NULL;
+
+      for (i=0;i<nVertices;i++)  {
+        a1 = vertex[i]->user_id;
+        e1 = vertex[i]->type;
+        if (e1>nElementNames)  e1 = 6;
+        e1--;
+        for (j=i+1;j<nVertices;j++)  {
+          a2 = vertex[j]->user_id;
+          e2 = vertex[j]->type;
+          if (e2>nElementNames)  e2 = 6;
+          e2--;
+          dx = R->atom[a2]->x - R->atom[a1]->x;
+          dy = R->atom[a2]->y - R->atom[a1]->y;
+          dz = R->atom[a2]->z - R->atom[a1]->z;
+    //      sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.15;
+          sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.25;
+          if (dx*dx+dy*dy+dz*dz<sr*sr)  {  // it's a bond
+            G = new Edge(i+1,j+1,1);
+            AddEdge ( G );
+          }
+        }
+        vertex[i]->id = i+1;
+      }
+
+      if (aL)  delete[] aL;
+      FreeVectorMemory ( occupancy,0 );
+
+      nAllVertices = nVertices;
+      nAllEdges    = nEdges;
+
+      return rc;
+
+    }
+
+    int  Graph::MakeGraph ( PPAtom atom, int nAtoms )  {
+    PEdge    G;
+    char     atomID[100];
+    realtype dx,dy,dz, sr;
+    int      i,j, a1,a2,e1,e2, rc;
+
+      rc = MKGRAPH_Ok;
+      //  reset graph
+      FreeMemory();
+
+      nVAlloc = nAtoms;  // upper estimate for vertices to allocate
+      if (nVAlloc<=0)  return MKGRAPH_NoAtoms;
+
+      //  allocate vertex array
+      vertex = new PVertex[nVAlloc];
+      for (i=0;i<nVAlloc;i++)
+        vertex[i] = NULL;
+
+      //  make vertices
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)  {
+            vertex[nVertices] = new Vertex ( atom[i]->element,
+                                     atom[i]->GetAtomIDfmt(atomID) );
+            vertex[nVertices]->user_id = i;
+            nVertices++;
+          }
+        }
+
+      if (nVertices<=0)  {
+        FreeMemory();
+        return MKGRAPH_NoAtoms;
+      }
+
+      //  make edges
+      nEAlloc = 3*nVertices;  // just an inital guess
+      edge    = new PEdge[nEAlloc];
+      for (i=0;i<nEAlloc;i++)
+        edge[i] = NULL;
+
+      for (i=0;i<nVertices;i++)  {
+        a1 = vertex[i]->user_id;
+        e1 = vertex[i]->type;
+        if (e1>nElementNames)  e1 = 6;
+        e1--;
+        for (j=i+1;j<nVertices;j++)  {
+          a2 = vertex[j]->user_id;
+          e2 = vertex[j]->type;
+          if (e2>nElementNames)  e2 = 6;
+          e2--;
+          dx = atom[a2]->x - atom[a1]->x;
+          dy = atom[a2]->y - atom[a1]->y;
+          dz = atom[a2]->z - atom[a1]->z;
+          sr = CovalentRadius[e1] + CovalentRadius[e2] + 0.25;
+          if (dx*dx+dy*dy+dz*dz<sr*sr)  {  // it's a bond
+            G = new Edge(i+1,j+1,1); // don't guess on bond order here
+            AddEdge ( G );
+          }
+        }
+        vertex[i]->id = i+1;
+      }
+
+      nAllVertices = nVertices;
+      nAllEdges    = nEdges;
+
+      return rc;
+
+    }
+
+
+    void  Graph::MakeVertexIDs()  {
+    int i;
+      for (i=0;i<nAllVertices;i++)
+        vertex[i]->id = i+1;
+    }
+
+    void  Graph::HideType ( int bond_vx_type )  {
+    //  1. Moves vertices bond_vx_type to the end of vertex array
+    //  2. Moves edges to bond_vx_type vertices to the end of edge array
+    //  3. Saves lengths of full vertex and edge arrays, and redefines
+    //     lengths to initial parts of the arrays not containing
+    //     bond_vx_type vertices.
+    PPEdge   Edge1;
+    PPVertex Vertex1;
+    int       i,k,v1,v2, nEdges1,nVertices1;
+    ivector   iv;
+
+      Edge1   = new PEdge[nEdges];
+      Vertex1 = new PVertex[nVertices];
+      GetVectorMemory ( iv,nVertices,1 );
+
+      for (i=0;i<nEdges;i++)
+        if (edge[i])  {
+          v1 = edge[i]->v1-1;
+          v2 = edge[i]->v2-1;
+          if (vertex[v1] && vertex[v2])  {
+            if ((vertex[v1]->type & (int)TYPE_MASK)==bond_vx_type)  {
+              vertex[v2]->AddBond();
+              vertex[v1]->CopyNBonds ( vertex[v2] );
+            }
+            if ((vertex[v2]->type & (int)TYPE_MASK)==bond_vx_type)  {
+              vertex[v1]->AddBond();
+              vertex[v2]->CopyNBonds ( vertex[v1] );
+            }
+          }
+        }
+
+      nVertices1 = 0;
+      for (i=0;i<nVertices;i++)
+        if (vertex[i])  {
+          if ((vertex[i]->type & (int)TYPE_MASK)!=bond_vx_type)  {
+            Vertex1[nVertices1++] = vertex[i];
+            iv[i+1] = nVertices1;
+          }
+        }
+      k = nVertices1;
+      for (i=0;i<nVertices;i++)
+        if (vertex[i])  {
+          if ((vertex[i]->type & (int)TYPE_MASK)==bond_vx_type)  {
+            Vertex1[k++] = vertex[i];
+            iv[i+1] = k;
+          }
+        }
+
+      nEdges1 = 0;
+      for (i=0;i<nEdges;i++)
+        if (edge[i])  {
+          edge[i]->v1 = iv[edge[i]->v1];
+          edge[i]->v2 = iv[edge[i]->v2];
+          if (((Vertex1[edge[i]->v1-1]->type & (int)TYPE_MASK) !=
+                                                       bond_vx_type) &&
+              ((Vertex1[edge[i]->v2-1]->type & (int)TYPE_MASK) !=
+                                                       bond_vx_type))
+            Edge1[nEdges1++] = edge[i];
+        }
+      k = nEdges1;
+      for (i=0;i<nEdges;i++)
+        if (edge[i])  {
+          if (((Vertex1[edge[i]->v1-1]->type & (int)TYPE_MASK) ==
+                                                       bond_vx_type) ||
+              ((Vertex1[edge[i]->v2-1]->type & (int)TYPE_MASK) ==
+                                                       bond_vx_type))
+            Edge1[k++] = edge[i];
+        }
+
+      nAllVertices = nVertices;
+      nAllEdges    = nEdges;
+      nVAlloc      = nVertices;
+      nEAlloc      = nEdges;
+      nVertices    = nVertices1;
+      nEdges       = nEdges1;
+
+      if (vertex)  delete[] vertex;
+      if (edge)    delete[] edge;
+      FreeVectorMemory ( iv,1 );
+
+      vertex = Vertex1;
+      edge   = Edge1;
+
+    }
+
+    void  Graph::ExcludeType ( int type )  {
+    int     i,k;
+    ivector iv;
+      GetVectorMemory ( iv,nAllVertices,1 );
+      k = 0;
+      for (i=0;i<nAllVertices;i++)
+        if ((vertex[i]->type & (int)TYPE_MASK)!=type)  {
+          if (k<i)  {
+            vertex[k] = vertex[i];
+            vertex[i] = NULL;
+          }
+          k++;
+          iv[i+1] = k;
+        } else  {
+          delete vertex[i];
+          vertex[i] = NULL;
+          iv[i+1]   = 0;
+        }
+      nAllVertices = k;
+      nVertices = nAllVertices;
+      k = 0;
+      for (i=0;i<nAllEdges;i++)
+        if ((iv[edge[i]->v1]!=0) && (iv[edge[i]->v2]!=0))  {
+          if (k<i)  {
+            edge[k] = edge[i];
+            edge[i] = NULL;
+          }
+          edge[k]->v1 = iv[edge[k]->v1];
+          edge[k]->v2 = iv[edge[k]->v2];
+          k++;
+        } else  {
+          delete edge[i];
+          edge[i] = NULL;
+        }
+      nAllEdges = k;
+      nEdges = nAllEdges;
+      FreeVectorMemory ( iv,1 );
+    }
+
+    void Graph::RemoveChirality()  {
+    int i;
+      for (i=0;i<nAllVertices;i++)
+        if (vertex[i])  vertex[i]->RemoveChirality();
+    }
+
+    void Graph::LeaveChirality ( int eltype )  {
+    // leaves chirality for specified atom types
+    int i;
+      for (i=0;i<nAllVertices;i++)
+        if (vertex[i])  vertex[i]->LeaveChirality ( eltype );
+    }
+
+    void Graph::MakeSymmetryRelief ( bool noCO2 )  {
+    //  This function looks for groups of equivalent vertices
+    // attached to a single vertice (e.g. chemical SO3 or
+    // PO3 groups), and re-lables them by adding a unique
+    // symmetry-relief number. This eliminates equivalent
+    // GMatches (3! for each SO3/PO3 group), and increases
+    // vertex diversity, which considerably speeds up GMatching.
+    // The function is cheap and harmless even if such groups
+    // of vertices are not found.
+    //  If noCO2 is true then CO2 symmetry is not releaved.
+    ivector v,vc;
+    int     i,j,k,n,m,almask,vjtype, ctype,otype;
+    bool noOxygens;
+
+      otype = 0;
+      ctype = 0;
+
+      GetVectorMemory ( v ,nVertices,0 );
+      GetVectorMemory ( vc,nVertices,1 );
+
+      for (i=1;i<=nVertices;i++)
+        vc[i] = 0;
+
+      for (j=0;j<nEdges;j++)  {
+        if ((edge[j]->v1>0) && (edge[j]->v1<=nVertices))
+          vc[edge[j]->v1]++;
+        if ((edge[j]->v2>0) && (edge[j]->v2<=nVertices))
+          vc[edge[j]->v2]++;
+      }
+
+      almask = ~ATOM_LEAVING;
+
+      if (noCO2)  {
+        ctype = getElementNo ( "C" );
+        otype = getElementNo ( "O" );
+      }
+
+      noOxygens = false;
+
+      for (i=1;i<=nVertices;i++)
+        if (vc[i]>1)  {  // vertex at more than 1 edge
+          // v[] will list connected vertices, k will be their number
+          k = 0;
+          for (j=0;j<nEdges;j++)  {
+            if ((edge[j]->v1==i) && (vc[edge[j]->v2]==1) && (k<nVertices))
+              v[k++] = edge[j]->v2-1;
+            if ((edge[j]->v2==i) && (vc[edge[j]->v1]==1) && (k<nVertices))
+              v[k++] = edge[j]->v1-1;
+          }
+          if (k>1)  {
+            if (noCO2) noOxygens = ((vertex[i-1]->type & almask)==ctype);
+            // A group of vertices with single connection is
+            // identified. Assign symmetry relief modifiers
+            // to *equivalent* vertices in the group
+            for (j=0;j<k;j++)
+              if ((v[j]>=0) && (v[j]<nVertices))  {
+                vjtype = vertex[v[j]]->type & almask;
+                if ((!noOxygens) || (vjtype!=otype))  {
+                  n = 1; // symmetry relief modifier
+                  for (m=j+1;m<k;m++)
+                    if ((v[m]>=0) && (v[m]<nVertices))  {
+                      if (vertex[v[j]]->type==
+                          (vertex[v[m]]->type & almask))  {
+                        vertex[v[m]]->type |= (n << 16);
+                        n++;
+                        v[m] = -1;
+                      }
+                    }
+                }
+              }
+          }
+        }
+
+      FreeVectorMemory ( v ,0 );
+      FreeVectorMemory ( vc,1 );
+
+    }
+
+    int  Graph::Build ( bool bondOrder )  {
+    int i,j, rc;
+
+      if (nVertices<=0)  return 2;
+
+      if (nGAlloc<nVertices)  {
+        FreeMatrixMemory ( graph,nGAlloc,1,1 );
+        nGAlloc = nVertices;
+        GetMatrixMemory ( graph,nGAlloc,nGAlloc,1,1 );
+      }
+
+      for (i=1;i<=nVertices;i++)
+        for (j=1;j<=nVertices;j++)
+          graph[i][j] = 0;
+
+      rc = 0;
+      if (bondOrder)  {
+
+        for (i=0;(i<nEdges) && (!rc);i++)
+          if ((edge[i]->v1>=1) && (edge[i]->v1<=nVertices) &&
+              (edge[i]->v2>=1) && (edge[i]->v2<=nVertices))  {
+            graph[edge[i]->v1][edge[i]->v2] = edge[i]->type;
+            graph[edge[i]->v2][edge[i]->v1] = edge[i]->type;
+          } else
+            rc = 1;
+
+      } else  {
+
+        for (i=0;i<nEdges;i++)
+          if ((edge[i]->v1>=1) && (edge[i]->v1<=nVertices) &&
+              (edge[i]->v2>=1) && (edge[i]->v2<=nVertices))  {
+            graph[edge[i]->v1][edge[i]->v2] = 1;
+            graph[edge[i]->v2][edge[i]->v1] = 1;
+          } else
+            rc = 1;
+
+      }
+
+      return rc;
+
+    }
+
+
+    const int ring_mask[] = {
+      0x00000000,
+      0x00000000,
+      0x00000000,
+      0x00000001,
+      0x00000002,
+      0x00000004,
+      0x00000008,
+      0x00000010,
+      0x00000020,
+      0x00000040,
+      0x00000080
+    };
+
+    void Graph::IdentifyRings()  {
+    GraphMatch GM;
+    Graph      ring;
+    ivector    F1,F2;
+    AtomName   aname;
+    realtype   p1,p2;
+    int        i,j,n,nrings,nv;
+
+      Build ( false );
+
+      for (i=0;i<nVertices;i++)
+        vertex[i]->type_ext = 0;
+
+      GM.SetFlag ( GMF_UniqueMatch );
+
+      for (n=3;n<=10;n++)  {
+
+        ring.Reset();
+
+        for (i=1;i<=n;i++)  {
+          sprintf ( aname,"C%i",i );
+          ring.AddVertex ( new Vertex("C",aname) );
+        }
+
+        ring.MakeVertexIDs();
+
+        for (i=1;i<=n;i++)  {
+          j = i+1;
+          if (j>n) j = 1;
+          ring.AddEdge ( new Edge(i,j,1) );
+        }
+
+        ring.Build ( false );
+
+        GM.MatchGraphs ( this,&ring,n,false,EXTTYPE_Ignore );
+
+        nrings = GM.GetNofMatches();
+        for (i=0;i<nrings;i++)  {
+          GM.GetMatch ( i,F1,F2,nv,p1,p2 );
+          for (j=1;j<nv;j++)
+            vertex[F1[j]-1]->type_ext |= ring_mask[n];
+        }
+
+      }
+
+    }
+
+    void Graph::markConnected ( int vno, int cno )  {
+    int i;
+
+      vertex[vno]->type_ext = cno;
+      for (i=0;i<nVertices;i++)
+        if (graph[vno+1][i+1] && (!vertex[i]->type_ext))
+          markConnected ( i,cno );
+
+    }
+
+
+    int  Graph::IdentifyConnectedComponents()  {
+    // Returns the number of connected components and sets
+    // vertex[]->type_ext equal to component number >=1.
+    int nComponents,i;
+
+      nComponents = 0;
+
+      Build ( false );
+
+      for (i=0;i<nVertices;i++)
+        vertex[i]->type_ext = 0;
+
+      i = 0;
+      while (i<nVertices)  {
+        while (i<nVertices)
+          if (vertex[i]->type_ext)  i++;
+                              else  break;
+        if (i<nVertices)  {
+          nComponents++;
+          markConnected ( i,nComponents );
+        }
+      }
+
+      return nComponents;
+
+    }
+
+
+
+    void  Graph::Print()  {
+    int i;
+
+      printf ( " =====  Graph %s \n\n",name );
+
+      if (nVertices>0) {
+        printf ( "  Vertices:\n""  ##   " );
+        vertex[0]->Print(1);
+        printf ( "\n" );
+        for (i=0;i<nVertices;i++) {
+          printf ( " %4i  ",i+1 );
+          vertex[i]->Print(0);
+          printf ( "\n" );
+        }
+      }
+
+      if (nEdges>0) {
+        printf ( "  Edges:\n""  ##   " );
+        edge[0]->Print(1);
+        printf ( "\n" );
+        for (i=0;i<nEdges;i++) {
+          printf ( " %4i  ",i+1 );
+          edge[i]->Print(0);
+          printf ( "\n" );
+        }
+      }
+
+
+    }
+
+    void  Graph::Print1()  {
+    int i,j;
+      for (i=0;i<nVertices;i++)  {
+        printf ( " %4i %5i %3i %7s ",
+                 i+1,vertex[i]->id,vertex[i]->type,vertex[i]->name );
+        for (j=0;j<nEdges;j++)
+          if (edge[j]->v1==i+1)
+            printf ( " %4i(%i)",edge[j]->v2,edge[j]->type );
+          else if (edge[j]->v2==i+1)
+            printf ( " %4i(%i)",edge[j]->v1,edge[j]->type );
+        printf ( "\n" );
+      }
+    }
+
+
+    void  Graph::Copy ( PGraph G )  {
+    int     i;
+
+      FreeMemory();
+
+      CreateCopy ( name,G->name );
+      nVertices    = G->nVertices;
+      nEdges       = G->nEdges;
+      nAllVertices = G->nAllVertices;
+      nAllEdges    = G->nAllEdges;
+      if (nAllVertices>0)  {
+        nVAlloc = nAllVertices;
+        vertex  = new PVertex[nVAlloc];
+        for (i=0;i<nAllVertices;i++)  {
+          vertex[i] = new Vertex();
+          vertex[i]->Copy ( G->vertex[i] );
+        }
+      }
+      if (nAllEdges>0)  {
+        nEAlloc = nAllEdges;
+        edge    = new PEdge[nEAlloc];
+        for (i=0;i<nAllEdges;i++)  {
+          edge[i] = new Edge();
+          edge[i]->Copy ( G->edge[i] );
+        }
+      }
+
+    }
+
+    void  Graph::write ( io::RFile f )  {
+    int  i;
+    int  Version=2;
+    bool bondOrder=false;
+      f.WriteInt    ( &Version      );
+      f.WriteBool   ( &bondOrder    );
+      f.CreateWrite ( name          );
+      f.WriteInt    ( &nVertices    );
+      f.WriteInt    ( &nEdges       );
+      f.WriteInt    ( &nAllVertices );
+      f.WriteInt    ( &nAllEdges    );
+      for (i=0;i<nAllVertices;i++)
+        StreamWrite ( f,vertex[i] );
+      for (i=0;i<nAllEdges;i++)
+        StreamWrite ( f,edge[i] );
+    }
+
+    void  Graph::read ( io::RFile f )  {
+    int     i,Version;
+    bool bondOrder;
+
+      FreeMemory();
+
+      f.ReadInt    ( &Version   );
+      f.ReadBool   ( &bondOrder );
+      f.CreateRead ( name       );
+      f.ReadInt    ( &nVertices );
+      f.ReadInt    ( &nEdges    );
+      if (Version>1)  {
+        f.ReadInt  ( &nAllVertices );
+        f.ReadInt  ( &nAllEdges    );
+      } else  {
+        nAllVertices = nVertices;
+        nAllEdges    = nEdges;
+      }
+      if (nAllVertices>0)  {
+        nVAlloc = nAllVertices;
+        vertex  = new PVertex[nVAlloc];
+        for (i=0;i<nAllVertices;i++)  {
+          vertex[i] = NULL;
+          StreamRead ( f,vertex[i] );
+        }
+      }
+      if (nAllEdges>0)  {
+        nEAlloc = nAllEdges;
+        edge    = new PEdge[nEAlloc];
+        for (i=0;i<nAllEdges;i++)  {
+          edge[i] = NULL;
+          StreamRead ( f,edge[i] );
+        }
+      }
+
+    //  Build ( bondOrder );
+
+    }
+
+    void  Graph::mem_write ( pstr S, int & l )  {
+    int     i,k;
+    byte    Version=2;
+    bool bondOrder=false;
+
+      mmdb::mem_write_byte ( Version,S,l );
+      mmdb::mem_write ( bondOrder   ,S,l );
+      mmdb::mem_write ( name        ,S,l );
+      mmdb::mem_write ( nVertices   ,S,l );
+      mmdb::mem_write ( nEdges      ,S,l );
+      mmdb::mem_write ( nAllVertices,S,l );
+      mmdb::mem_write ( nAllEdges   ,S,l );
+      for (i=0;i<nAllVertices;i++)
+        if (vertex[i])  {
+          k = 1;
+          mmdb::mem_write ( k,S,l );
+          vertex[i]->mem_write ( S,l );
+        } else  {
+          k = 0;
+          mmdb::mem_write ( k,S,l );
+        }
+      for (i=0;i<nAllEdges;i++)
+        if (edge[i])  {
+          k = 1;
+          mmdb::mem_write ( k,S,l );
+          edge[i]->mem_write ( S,l );
+        } else  {
+          k = 0;
+          mmdb::mem_write ( k,S,l );
+        }
+
+    }
+
+    void  Graph::mem_read ( cpstr S, int & l )  {
+    int     i,k;
+    byte    Version;
+    bool bondOrder;
+
+      FreeMemory();
+
+      mmdb::mem_read_byte ( Version,S,l );
+      mmdb::mem_read ( bondOrder   ,S,l );
+      mmdb::mem_read ( name        ,S,l );
+      mmdb::mem_read ( nVertices   ,S,l );
+      mmdb::mem_read ( nEdges      ,S,l );
+      mmdb::mem_read ( nAllVertices,S,l );
+      mmdb::mem_read ( nAllEdges   ,S,l );
+      if (nAllVertices>0)  {
+        nVAlloc = nAllVertices;
+        vertex  = new PVertex[nVAlloc];
+        for (i=0;i<nAllVertices;i++)  {
+          mmdb::mem_read ( k,S,l );
+          if (k)  {
+            vertex[i] = new Vertex();
+            vertex[i]->mem_read ( S,l );
+          } else
+            vertex[i] = NULL;
+        }
+      }
+      if (nAllEdges>0)  {
+        nEAlloc = nAllEdges;
+        edge    = new PEdge[nEAlloc];
+        for (i=0;i<nAllEdges;i++)  {
+          mmdb::mem_read ( k,S,l );
+          if (k)  {
+            edge[i] = new Edge();
+            edge[i]->mem_read ( S,l );
+          } else  {
+            edge[i] = NULL;
+          }
+        }
+      }
+
+    //  Build ( bondOrder );
+
+    }
+
+    MakeStreamFunctions(Graph)
+
+
+    //  ==========================  GMatch  ============================
+
+    GMatch::GMatch() : io::Stream()  {
+      InitGMatch();
+    }
+
+    GMatch::GMatch ( io::RPStream Object ) : io::Stream ( Object )  {
+      InitGMatch();
+    }
+
+    GMatch::GMatch ( ivector FV1, ivector FV2, int nv, int n, int m )  {
+    int i;
+      if (FV1 && FV2)  {
+        n1     = n;
+        n2     = m;
+        nAlloc = n;
+        GetVectorMemory ( F1,nAlloc,1 );
+        GetVectorMemory ( F2,nAlloc,1 );
+        mlength = nv;
+        for (i=1;i<=mlength;i++)  {
+          F1[i] = FV1[i];
+          F2[i] = FV2[i];
+        }
+      } else
+        InitGMatch();
+    }
+
+    void  GMatch::InitGMatch()  {
+      mlength = 0;
+      n1      = 0;
+      n2      = 0;
+      nAlloc  = 0;
+      F1      = NULL;
+      F2      = NULL;
+    }
+
+    GMatch::~GMatch()  {
+      FreeVectorMemory ( F1,1 );
+      FreeVectorMemory ( F2,1 );
+    }
+
+    void GMatch::SetMatch ( ivector FV1, ivector FV2,
+                            int nv, int n, int m )  {
+    int i;
+      if (FV1 && FV2)  {
+        if (nv>nAlloc)  {
+          FreeVectorMemory ( F1,1 );
+          FreeVectorMemory ( F2,1 );
+          nAlloc = n;
+          GetVectorMemory  ( F1,nAlloc,1 );
+          GetVectorMemory  ( F2,nAlloc,1 );
+        }
+        n1 = n;
+        n2 = m;
+        mlength = nv;
+        for (i=1;i<=mlength;i++)  {
+          F1[i] = FV1[i];
+          F2[i] = FV2[i];
+        }
+      } else  {
+        FreeVectorMemory ( F1,1 );
+        FreeVectorMemory ( F2,1 );
+        mlength = 0;
+        n1 = 0;
+        n2 = 0;
+      }
+    }
+
+
+    bool GMatch::isMatch ( ivector FV1, ivector FV2, int nv )  {
+    int     i,j;
+    bool B;
+      if (FV1 && FV2 && (nv<=mlength))  {
+        B = true;
+        for (i=1;(i<=nv) && B;i++)  {
+          B = false;
+          for (j=1;(j<=mlength) && (!B);j++)
+            B = (FV1[i]==F1[j]) && (FV2[i]==F2[j]);
+        }
+        return B;
+      }
+      return false;
+    }
+
+    bool GMatch::isCombination ( ivector FV1, ivector FV2, int nv )  {
+    int     i,j;
+    bool B;
+      if (FV1 && FV2 && (nv==mlength))  {
+        B = true;
+        for (i=1;(i<=nv) && B;i++)  {
+          B = false;
+          for (j=1;(j<=mlength) && (!B);j++)
+            B = (FV1[i]==F1[j]);
+          if (B)  {
+            B = false;
+            for (j=1;(j<=mlength) && (!B);j++)
+              B = (FV2[i]==F2[j]);
+          }
+        }
+        return B;
+      }
+      return false;
+    }
+
+
+    void GMatch::GetMatch ( ivector  & FV1, ivector  & FV2, int & nv,
+                            realtype & p1,  realtype & p2 )  {
+      FV1 = F1;
+      FV2 = F2;
+      nv  = mlength;
+      p1  = mlength;
+      if (p1>0.0)  p1 /= n1;
+      p2  = mlength;
+      if (p2>0.0)  p2 /= n2;
+    }
+
+    void GMatch::write ( io::RFile f )  {
+    int i;
+    int Version=1;
+      f.WriteInt ( &Version );
+      f.WriteInt ( &mlength );
+      f.WriteInt ( &n1      );
+      f.WriteInt ( &n2      );
+      for (i=1;i<=mlength;i++)  {
+        f.WriteInt ( &(F1[i]) );
+        f.WriteInt ( &(F2[i]) );
+      }
+    }
+
+    void GMatch::read ( io::RFile f )  {
+    int i,Version;
+      FreeVectorMemory ( F1,1 );
+      FreeVectorMemory ( F2,1 );
+      f.ReadInt ( &Version );
+      f.ReadInt ( &mlength );
+      f.ReadInt ( &n1      );
+      f.ReadInt ( &n2      );
+      if (mlength>0)  {
+        nAlloc = n1;
+        GetVectorMemory ( F1,nAlloc,1 );
+        GetVectorMemory ( F2,nAlloc,1 );
+        for (i=1;i<=mlength;i++)  {
+          f.ReadInt ( &(F1[i]) );
+          f.ReadInt ( &(F2[i]) );
+        }
+      }
+    }
+
+    void GMatch::mem_write ( pstr S, int & l )  {
+    int i;
+      mmdb::mem_write ( mlength,S,l );
+      mmdb::mem_write ( n1     ,S,l );
+      mmdb::mem_write ( n2     ,S,l );
+      for (i=1;i<=mlength;i++)  {
+        mmdb::mem_write ( F1[i],S,l );
+        mmdb::mem_write ( F2[i],S,l );
+      }
+    }
+
+    void GMatch::mem_read ( cpstr S, int & l )  {
+    int i;
+      FreeVectorMemory ( F1,1 );
+      FreeVectorMemory ( F2,1 );
+      mmdb::mem_read ( mlength,S,l );
+      mmdb::mem_read ( n1     ,S,l );
+      mmdb::mem_read ( n2     ,S,l );
+      if (mlength>0)  {
+        nAlloc = n1;
+        GetVectorMemory ( F1,nAlloc,1 );
+        GetVectorMemory ( F2,nAlloc,1 );
+        for (i=1;i<=mlength;i++)  {
+          mmdb::mem_read ( F1[i],S,l );
+          mmdb::mem_read ( F2[i],S,l );
+        }
+      }
+    }
+
+
+    MakeStreamFunctions(GMatch)
+
+
+
+    //  ========================  GraphMatch  ==========================
+
+    GraphMatch::GraphMatch()
+               : io::Stream()  {
+      InitGraphMatch();
+    }
+
+    GraphMatch::GraphMatch ( io::RPStream Object )
+               : io::Stream ( Object )  {
+      InitGraphMatch();
+    }
+
+    GraphMatch::~GraphMatch()  {
+      FreeMemory();
+    }
+
+    void  GraphMatch::InitGraphMatch()  {
+      G1           = NULL;
+      G2           = NULL;
+      n            = 0;
+      m            = 0;
+      P            = NULL;
+      nAlloc       = 0;
+      mAlloc       = 0;
+      nMatches     = 0;
+      maxNMatches  = -1;  // unlimited
+      Match        = NULL;
+      nMAlloc      = 0;
+      flags        = 0;
+      swap         = false;
+      wasFullMatch = false;
+      maxMatch     = 0;
+      timeLimit    = 0;  // no time limit
+      Stop         = false;
+      stopOnMaxNMathches = false;
+      F1           = NULL;
+      F2           = NULL;
+      iF1          = NULL;
+      ix           = NULL;
+    #ifndef _UseRecursion
+      jj           = NULL;
+    #endif
+    }
+
+
+    void  GraphMatch::SetFlag ( word flag )  {
+      flags |= flag;
+    }
+
+    void  GraphMatch::RemoveFlag ( word flag )  {
+      flags &= ~flag;
+    }
+
+    void  GraphMatch::SetMaxNofMatches ( int maxNofGMatches,
+                                         bool stopOnMaxN )  {
+      maxNMatches        = maxNofGMatches;
+      stopOnMaxNMathches = stopOnMaxN;
+    }
+
+    void  GraphMatch::SetTimeLimit ( int maxTimeToRun )  {
+      timeLimit = maxTimeToRun;
+    }
+
+    void  GraphMatch::Reset()  {
+      FreeMemory();
+    }
+
+    void  GraphMatch::FreeMemory()  {
+    int i;
+
+      if (P) {
+        FreeMatrixMemory ( P[1],nAlloc,1,0 );
+        FreeRecHeap      ();
+        P = P + 1;
+        delete[] P;
+        P = NULL;
+      }
+
+      FreeMatrixMemory ( iF1,nAlloc,1,1 );
+
+      FreeVectorMemory ( F1 ,1 );
+      FreeVectorMemory ( F2 ,1 );
+      FreeVectorMemory ( ix ,1 );
+      nAlloc = 0;
+      mAlloc = 0;
+
+      if (Match)  {
+        for (i=0;i<nMAlloc;i++)
+          if (Match[i])  delete Match[i];
+        delete[] Match;
+      }
+      Match    = NULL;
+      nMatches = 0;
+      nMAlloc  = 0;
+
+    #ifndef _UseRecursion
+      FreeVectorMemory ( jj,1 );
+    #endif
+
+    }
+
+    void  GraphMatch::FreeRecHeap()  {
+    int i;
+      if (P)
+        for (i=2;i<=nAlloc;i++)
+          FreeMatrixMemory ( P[i],nAlloc,1,0 );
+    }
+
+
+    void  GraphMatch::GetMemory()  {
+    int i;
+
+      FreeMemory();
+
+      P = new imatrix[n];
+      P = P-1;
+      GetMatrixMemory ( P[1],n,m+1,1,0 );
+      for (i=2;i<=n;i++)
+        P[i] = NULL;
+
+      GetMatrixMemory ( iF1,n,n,1,1 );
+
+      GetVectorMemory ( F1,n,1 );
+      GetVectorMemory ( F2,n,1 );
+      GetVectorMemory ( ix,n,1 );
+
+    #ifndef _UseRecursion
+      GetVectorMemory ( jj,n,1 );
+    #endif
+
+      nAlloc = n;
+      mAlloc = m;
+
+    }
+
+    void  GraphMatch::GetRecHeap()  {
+    int i,j;
+      for (i=2;i<=n;i++)  {
+        P[i] = new ivector[nAlloc];
+        P[i] = P[i]-1;
+        for (j=1;j<=n;j++)
+          GetVectorMemory ( P[i][j],P[1][j][0]+1,0 );
+        for (j=n+1;j<=nAlloc;j++)
+          P[i][j] = NULL;
+      }
+    }
+
+
+    void  GraphMatch::MatchGraphs ( PGraph Gh1, PGraph Gh2,
+                                    int     minMatch,
+                                    bool    vertexType,
+                                    VERTEX_EXT_TYPE vertexExt )  {
+    //  GMatchGraphs looks for maximal common subgraphs of size
+    //  not less than minGMatch. The number of found subgraphs
+    //  is returned by GetNofGMatches(), the subgraph vertices
+    //  are returned by GetGMatch(..). Control parameters:
+    //      vertexType   true if vertex type should be taken
+    //                   into account and false otherwise
+    //      vertexExt    key to use extended vertex types (defined
+    //                   as type_ext in Vertex).
+    int  n1;
+
+      if (Gh1->nVertices<=Gh2->nVertices)  {
+        G1   = Gh1;
+        G2   = Gh2;
+        swap = false;
+      } else  {
+        G1   = Gh2;
+        G2   = Gh1;
+        swap = true;
+      }
+      n  = G1->nVertices;
+      m  = G2->nVertices;
+      V1 = G1->vertex;
+      V2 = G2->vertex;
+      c1 = G1->graph;
+      c2 = G2->graph;
+
+      nMatches = 0;
+
+      if (n<=0)  return;
+
+      if ((n>nAlloc) || (m>mAlloc))  GetMemory();
+                               else  FreeRecHeap();
+
+      n1 = Initialize ( vertexType,vertexExt );
+      if (n1<=0)  return;
+
+      GetRecHeap();
+
+      maxMatch  = IMax(1,IMin(n,minMatch));
+      Stop      = false;
+      startTime = time(NULL);
+
+      //    Use of Backtrack(..) and Ullman() is completely
+      //  equivalent. One of them should be commented.
+
+      if (minMatch<n)  {
+
+        if (n1>=minMatch)  Backtrack1 ( 1,n1 );
+
+      } else if (n1>=n)  {
+
+       #ifdef _UseRecursion
+        Backtrack ( 1 );
+       #else
+        Ullman();
+       #endif
+
+      }
+
+    }
+
+
+    int  GraphMatch::Initialize ( bool vertexType, int vertexExt )  {
+    ivector jF1;
+    int     i,j,v1type,v1type_ext,v2type_ext,almask,iW,pl;
+
+      wasFullMatch = false;
+
+      jF1 = iF1[1];
+      for (i=1;i<=n;i++)
+        jF1[i] = i;
+
+      almask = ~ATOM_LEAVING;
+
+    /*  -- experiment for symmetry reliefs
+    int v2type,v1type_sr,srmask;
+      srmask = ~SYMREL_MASK;
+
+      for (i=1;i<=n;i++)  {
+        if (vertexType) {
+          ix[i]  = 0;
+          v1type = V1[i-1]->type & almask;
+          v1type_sr = v1type & srmask;
+          pl     = 0;
+          for (j=1;j<=m;j++)  {
+            v2type = V2[j-1]->type & almask;
+            if ((v1type==v2type) ||
+                (v1type_sr==v2type) ||
+                (v1type==(v2type & srmask)))
+              P[1][i][++pl] = j;
+          }
+          P[1][i][0] = pl;
+          if (pl)  ix[i] = i;
+        } else {
+          ix[i] = i;
+          for (j=1;j<=m;j++)
+            P[1][i][j] = j;
+          P[1][i][0] = m;
+        }
+        F1[i] = 0;
+        F2[i] = 0;
+      }
+     */
+
+      for (i=1;i<=n;i++)  {
+        ix[i]      = 0;
+        v1type     = V1[i-1]->type & almask;
+        v1type_ext = V1[i-1]->type_ext;
+        pl         = 0;
+        for (j=1;j<=m;j++)
+          if ((v1type==(V2[j-1]->type & almask)) || (!vertexType))  {
+            if (vertexExt==EXTTYPE_Ignore)
+              P[1][i][++pl] = j;
+            else  {
+              v2type_ext = V2[j-1]->type_ext;
+              if ((!v1type_ext) && (!v2type_ext))
+                P[1][i][++pl] = j;
+              else
+                switch (vertexExt)  {
+                  default :
+                  case EXTTYPE_Ignore   : P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_Equal    : if (v1type_ext==v2type_ext)
+                                            P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_AND      : if (v1type_ext & v2type_ext)
+                                            P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_OR       : if (v1type_ext | v2type_ext)
+                                            P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_XOR      : if (v1type_ext ^ v2type_ext)
+                                            P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_NotEqual : if (v1type_ext!=v2type_ext)
+                                            P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_NotAND   : if ((v1type_ext & v2type_ext)
+                                                  ==0)
+                                            P[1][i][++pl] = j;
+                                      break;
+                  case EXTTYPE_NotOR    : if ((v1type_ext | v2type_ext)
+                                                  ==0)
+                                            P[1][i][++pl] = j;
+                }
+            }
+          }
+        P[1][i][0] = pl;
+        if (pl)  ix[i] = i;
+        F1[i] = 0;
+        F2[i] = 0;
+      }
+      /*
+      } else  {
+        for (i=1;i<=n;i++)  {
+          ix[i] = i;
+          for (j=1;j<=m;j++)
+            P[1][i][j] = j;
+          P[1][i][0] = m;
+          F1[i] = 0;
+          F2[i] = 0;
+        }
+      }
+      */
+
+      i = 1;
+      j = n;
+      while (i<j)
+        if (ix[j]==0)  // make sure that j points on a true-containing
+          j--;         // row of P[1]
+        else  {
+          if (ix[i]==0)  {        // swap lower empty row of P[1]
+            iW     = ix[i];       // with the lth one, which
+            ix[i]  = ix[j];       // is surely not empty
+            ix[j]  = iW;
+            iW     = jF1[i];
+            jF1[i] = jF1[j];
+            jF1[j] = iW;
+          }
+          i++;
+        }
+
+      if (ix[i]==0)  return i-1;
+               else  return i;
+
+    }
+
+
+    #ifdef _UseRecursion
+
+    void  GraphMatch::Backtrack ( int i )  {
+    //   Recursive version of Ullman's algorithm for exact
+    // (structure-to-structure or substructure-to-structure)
+    // GMatching
+    int     i1,pli,cntj,j,k,pl1,pl2,cntl,l,c1ik;
+    ivector c1i,c2j;
+    ivector p1,p2;
+
+      if (Stop)  return;
+      if (timeLimit>0)
+        Stop = (difftime(time(NULL),startTime)>timeLimit);
+
+      F1[i] = i;
+      pli   = P[i][i][0];
+
+      if (i>=n)  {
+
+        for (cntj=1;(cntj<=pli) && (!Stop);cntj++)  {
+          F2[n] = P[n][n][cntj];
+          CollectMatch ( n );
+        }
+
+      } else  {
+
+        i1  = i+1;
+        c1i = c1[i];
+
+        for (cntj=1;(cntj<=pli) && (!Stop);cntj++)  {
+          j     = P[i][i][cntj];
+          F2[i] = j;  // mapped F1[i]:F2[i], i.e. i:j
+          // Forward checking
+          c2j   = c2[j];
+          pl2   = 1;
+          for (k=i1;(k<=n) && (pl2>0);k++)  {
+            p1   = P[i][k];
+            p2   = P[i1][k];
+            c1ik = c1i[k];
+            pl1  = p1[0];
+            pl2  = 0;
+            for (cntl=1;cntl<=pl1;cntl++)  {
+              l = p1[cntl];
+              if ((c1ik==c2j[l]) && // check that bonds are compatible
+                  (l!=j))           // and make sure jth vertex is excluded
+                p2[++pl2] = l;
+            }
+            p2[0] = pl2;  //  new length of P-row
+          }
+          if (pl2>0)  Backtrack ( i1 );
+        }
+
+      }
+
+    }
+
+    #else
+
+    void  GraphMatch::Ullman()  {
+    //   A non-recursive translation of Ullman's Backtrack.
+    // It might give some gain in performance, although tests
+    // on SGI machine show that the gain is negligible, (if
+    // there is any at all) if compiler's optimization is
+    // switched on.
+    int     i,pl,i1,pli,cntj,j,pl1,pl2,k,cntl,l,l1,cik;
+    ivector ci,cj;
+    ivector p1,p2;
+
+      if (Stop)  return;
+      if (timeLimit>0)
+        Stop = (difftime(time(NULL),startTime)>timeLimit);
+
+      i     = 1;
+      jj[1] = 1;
+      pl    = P[1][1][0];
+
+      do  {
+
+        F1[i] = i;
+        pli   = P[i][i][0];
+
+        if (i>=n)  {
+
+          for (cntj=jj[n];(cntj<=pli) && (!Stop);cntj++)  {
+            jj[n]++;
+            F2[n] = P[n][n][cntj];
+            CollectGMatch ( n );
+          }
+
+        } else  {
+
+          i1  = i+1;
+          ci  = c1[i];
+          for (cntj=jj[i];(cntj<=pli) && (!Stop);cntj++)  {
+            jj[i]++;
+            j     = P[i][i][cntj];
+            F2[i] = j;
+            // Forward checking
+            cj    = c2[j];
+            pl2   = 1;
+            for (k=i1;(k<=n) && (pl2>0);k++)  {
+              p1  = P[i][k];
+              p2  = P[i1][k];
+              cik = ci[k];
+              pl1 = p1[0];
+              pl2 = 0;
+              for (cntl=1;cntl<=pl1;cntl++)  {
+                l = p1[cntl];
+                if ((cik==cj[l]) && // check that bonds are compatible
+                    (l!=j))         // and make sure jth vertex is excluded
+                  p2[++pl2] = l;
+              }
+              p2[0] = pl2;  //  new length of P-row
+            }
+            if (pl2>0)  {
+              i++;
+              jj[i] = 1;
+              i++;        // in order to compensate the following decrement
+              break;
+            }
+          }
+
+        }
+        i--;
+
+      } while ((!Stop) && ((jj[1]<=pl) || (i>1)));
+
+    }
+
+    #endif
+
+    void  GraphMatch::Backtrack1 ( int i, int k0 )  {
+    //   Recursive version of CSIA algorithm for partial
+    // (substructure-to-substructure) GMatching
+    int     i1,pl0,cntj,j,k,pl1,pl2,cntl,l,c1ik,ii,iW,k1;
+    ivector jF1,c1i,c2j;
+    ivector p0,p1,p2;
+
+      if (Stop)  return;
+      if (timeLimit>0)
+        Stop = (difftime(time(NULL),startTime)>timeLimit);
+
+      jF1 = iF1[i];
+
+      if (i>=k0)  {
+
+        F1[i] = jF1[i];
+        p0    = P[i][jF1[i]];
+        pl0   = p0[0];
+
+        // collect GMatches of k0-th (the upmost) level
+        if (pl0>0)  {
+          maxMatch = k0;
+          for (cntj=1;cntj<=pl0;cntj++)  {
+            F2[k0] = p0[cntj];
+            CollectMatch ( k0 );
+          }
+        }
+
+      } else  {
+
+        i1  = i+1;
+
+        pl0 = P[i][jF1[i]][0];
+        j   = i;
+        for (k=i1;k<=k0;k++)
+          if (P[i][jF1[k]][0]<pl0)  {
+            pl0 = P[i][jF1[k]][0];
+            j   = k;
+          }
+        if (j>i)  {
+          iW     = jF1[i];
+          jF1[i] = jF1[j];
+          jF1[j] = iW;
+        }
+
+        F1[i] = jF1[i];
+        p0    = P[i][jF1[i]];
+        pl0   = p0[0];
+
+        c1i   = c1[jF1[i]];
+
+        //  1. Find all GMatches that include jF1[i]th vertex of graph G1
+
+        for (cntj=1;(cntj<=pl0) && (!Stop);cntj++)  {
+          j = p0[cntj];
+          F2[i] = j;   // mapped F1[i]:F2[i], i.e. iF1[i][i]:j
+          // Forward checking
+          c2j = c2[j];
+          k1  = k0;   // k1 is the limit for GMatch size
+          for (k=i1;(k<=k0) && (k1>=maxMatch);k++)  {
+            ix[k] = 0;
+            p1    = P[i] [jF1[k]];
+            p2    = P[i1][jF1[k]];
+            c1ik  = c1i  [jF1[k]];
+            pl1   = p1[0];
+            pl2   = 0;
+            for (cntl=1;cntl<=pl1;cntl++)  {
+              l = p1[cntl];
+              if ((c1ik==c2j[l]) && // check that bonds are compatible
+                  (l!=j))           // and make sure jth vertex is excluded
+                p2[++pl2] = l;
+            }
+            p2[0] = pl2;  //  new length of P-row
+            if (pl2>0)  {
+              ix[k] = k;
+            } else if (wasFullMatch)  {
+              k1 = maxMatch-1;  // we are not interested in partial
+            } else  {           //   GMatch anymore
+              k1--;
+            }
+          }
+          if (k1>=maxMatch)  {
+            // shift unGMatching vertices to the end
+            for (ii=1;ii<=n;ii++)
+              iF1[i1][ii] = jF1[ii];
+            k = i1;
+            l = k0;
+            while (k<l)
+              if (ix[l]==0) // make sure that l points on a true-containing
+                l--;        // row of P[i1]
+              else  {
+                if (ix[k]==0)  {         // swap lower empty row of P[i1]
+                  iW         = ix[k];    // with the lth one, which
+                  ix[k]      = ix[l];    // is surely not empty
+                  ix[l]      = iW;
+                  iW         = iF1[i1][k];
+                  iF1[i1][k] = iF1[i1][l];
+                  iF1[i1][l] = iW;
+                }
+                k++;
+              }
+            if (ix[i1])  Backtrack1 ( i1,k1 );
+            else if (i>=maxMatch)  {
+              CollectMatch ( i );  // collect GMatch of ith level
+              maxMatch = i;
+            }
+          }
+        }
+
+        //  2. Find all GMatches that do not include jF1[i]th vertex
+        //     of graph G1
+
+        if (k0>maxMatch)  {
+          //   Shift jF1[i]th vertex to the end
+          iW      = jF1[i];
+          jF1[i]  = jF1[k0];
+          jF1[k0] = iW;
+          Backtrack1 ( i,k0-1 );
+        }
+
+      }
+
+    }
+
+
+    void  GraphMatch::CollectMatch ( int nm )  {
+    int      i;
+    bool  B;
+    PPGMatch M1;
+
+      if (maxNMatches==0)  return;
+
+      // find out if this should be a new GMatch
+      if (nMatches>0)  {
+        // a GMatch is already found; check with it
+        if (nm<Match[0]->mlength)  return;
+        if (nm>Match[0]->mlength)  {
+          nMatches = 0;
+        } else if (flags & GMF_UniqueMatch)  {
+          // check if such a GMatch was already found
+          B = false;
+          for (i=0;(i<nMatches) && (!B);i++)
+            B = Match[i]->isMatch(F1,F2,nm);
+          if (B)  return;  // repeating GMatch -- just quit.
+        } else if (flags & GMF_NoCombinations)  {
+          // check if such a GMatch was already found
+          B = false;
+          for (i=0;(i<nMatches) && (!B);i++)
+            B = Match[i]->isCombination(F1,F2,nm);
+          if (B)  return;  // repeating GMatch -- just quit.
+        }
+      }
+
+      if (nMatches>=nMAlloc)  {
+        if ((nMAlloc<maxNMatches) || (maxNMatches<=0))  {
+          if (maxNMatches>0)  nMAlloc  = IMin(maxNMatches,nMAlloc+100);
+                        else  nMAlloc += 100;
+          M1 = new PGMatch[nMAlloc];
+          for (i=0;i<nMatches;i++)
+            M1[i] = Match[i];
+          for (i=nMatches;i<nMAlloc;i++)
+            M1[i] = NULL;
+          if (Match)  delete[] Match;
+          Match = M1;
+        } else
+          nMatches--;
+      }
+
+      if (!Match[nMatches])
+            Match[nMatches] = new GMatch ( F1,F2,nm,n,m );
+      else  Match[nMatches]->SetMatch ( F1,F2,nm,n,m );
+
+      if (nm==n)  wasFullMatch = true;
+
+      if (nm>maxMatch)  maxMatch = nm;
+
+      nMatches++;
+
+      if (stopOnMaxNMathches && (maxNMatches>0) &&
+          (nMatches>=maxNMatches))
+        Stop = true;
+
+    }
+
+    void  GraphMatch::PrintMatches()  {
+    int i,j,k;
+      if (nMatches<=0)
+        printf ( "\n\n *** NO GMatchES FOUND\n\n" );
+      else  {
+        if (flags & GMF_UniqueMatch)
+              printf ( "\n\n *** FOUND Unique GMatches\n\n" );
+        else  printf ( "\n\n *** FOUND GMatches\n\n" );
+        printf ( "    ##     Vertices\n" );
+        for (i=0;i<nMatches;i++)  {
+          printf ( " %5i  ",i+1 );
+          k = 8;
+          for (j=1;j<=Match[i]->mlength;j++)  {
+            if (swap)
+                 printf ( " (%i,%i)",Match[i]->F2[j],Match[i]->F1[j] );
+            else printf ( " (%i,%i)",Match[i]->F1[j],Match[i]->F2[j] );
+            k += 8;
+            if (k>70)  {
+              printf ( "\n" );
+              k = 8;
+            }
+          }
+          printf ( "\n" );
+        }
+      }
+      printf ( "\n **************************\n" );
+    }
+
+    void  GraphMatch::GetMatch ( int MatchNo, ivector  & FV1,
+                                 ivector  & FV2, int & nv,
+                                 realtype & p1, realtype & p2 ) {
+    // do not allocate or dispose FV1 and FV2 in application!
+    // FV1/p1 will always correspond to Gh1, and FV2/p2 -
+    // to Gh2 as specified in GMatchGraphs(..)
+      if ((MatchNo<0) || (MatchNo>=nMatches))  {
+        FV1 = NULL;
+        FV2 = NULL;
+        nv  = 0;
+        p1  = 0.0;
+        p2  = 0.0;
+      } else if (swap)
+           Match[MatchNo]->GetMatch ( FV2,FV1,nv,p2,p1 );
+      else Match[MatchNo]->GetMatch ( FV1,FV2,nv,p1,p2 );
+
+    }
+
+
+    void  GraphMatch::write ( io::RFile f )  {
+    int i;
+    int Version=1;
+      f.WriteInt  ( &Version  );
+      f.WriteInt  ( &nMatches );
+      f.WriteWord ( &flags    );
+      f.WriteBool ( &swap     );
+      for (i=0;i<nMatches;i++)
+        Match[i]->write ( f );
+    }
+
+    void  GraphMatch::read ( io::RFile f )  {
+    int i,Version;
+      FreeMemory ();
+      f.ReadInt  ( &Version  );
+      f.ReadInt  ( &nMatches );
+      f.ReadWord ( &flags    );
+      f.ReadBool ( &swap     );
+      if (nMatches>0)  {
+        nMAlloc = nMatches;
+        Match   = new PGMatch[nMatches];
+        for (i=0;i<nMatches;i++)  {
+          Match[i] = new GMatch();
+          Match[i]->read ( f );
+        }
+      }
+    }
+
+
+    void  GraphMatch::mem_write ( pstr S, int & l )  {
+    int i;
+      mmdb::mem_write ( nMatches,S,l );
+      mmdb::mem_write ( flags   ,S,l );
+      mmdb::mem_write ( swap    ,S,l );
+      for (i=0;i<nMatches;i++)
+        Match[i]->mem_write ( S,l );
+    }
+
+    void  GraphMatch::mem_read ( cpstr S, int & l )  {
+    int i;
+      FreeMemory ();
+      mmdb::mem_read ( nMatches,S,l );
+      mmdb::mem_read ( flags   ,S,l );
+      mmdb::mem_read ( swap    ,S,l );
+      if (nMatches>0)  {
+        nMAlloc = nMatches;
+        Match   = new PGMatch[nMatches];
+        for (i=0;i<nMatches;i++)  {
+          Match[i] = new GMatch();
+          Match[i]->mem_read ( S,l );
+        }
+      }
+    }
+
+    MakeStreamFunctions(GraphMatch)
+
+
+  }  // namespace math
+
+}  // namespace mmdb
+
+
+// =============================================================
+
+/*
+static char Mol1[][3] = {
+  "C", "C", "C", "C", "C", "C" };
+
+static int  Bond1[] = {
+  1, 2,
+  1, 6,
+  2, 3,
+  3, 4,
+  4, 5,
+  5, 6
+};
+
+static char Mol2[][3] = {
+  "C", "C", "C", "C", "C", "C",
+  "C", "C", "C", "C", "C", "C" };
+
+static int  Bond2[] = {
+  1, 2,
+  1, 6,
+  2, 3,
+  3, 4,
+  4, 5,
+  5, 6,
+  1, 7,
+  2, 8,
+  3, 9,
+  4, 10,
+  5, 11,
+  6, 12
+};
+
+
+static char Mol1[][3] = {
+  "C", "C", "N", "C" };
+
+static int  Bond1[] = {
+  1, 2,
+  2, 3,
+  3, 4
+};
+
+static char Mol2[][3] = {
+  "C", "C", "N", "C" };
+
+static int  Bond2[] = {
+  1, 2,
+  2, 3,
+  2, 4,
+  3, 4
+};
+
+void  TestGraphMatch()  {
+int         i,k1,k2, nv1,nb1, nv2,nb2;
+PVertex    V;
+PEdge      G;
+Graph      G1,G2;
+GraphMatch U;
+
+  G1.Reset   ();
+  G1.SetName ( "#1" );
+
+  nv1 = sizeof(Mol1)/3;
+  for (i=0;i<nv1;i++)  {
+    V = new Vertex();
+    V->SetVertex ( Mol1[i] );
+    G1.AddVertex ( V );
+  }
+  nb1 = sizeof(Bond1)/(2*sizeof(int));
+  k1  = 0;
+  k2  = 1;
+  for (i=0;i<nb1;i++)  {
+    G = new Edge();
+    G->SetEdge ( Bond1[k1],Bond1[k2],1 );
+    G1.AddEdge ( G );
+    k1 += 2;
+    k2 += 2;
+  }
+
+  G2.Reset   ();
+  G2.SetName ( "#2" );
+
+  nv2 = sizeof(Mol2)/3;
+  for (i=0;i<nv2;i++)  {
+    V = new Vertex();
+    V->SetVertex ( Mol2[i] );
+    G2.AddVertex ( V );
+  }
+  nb2 = sizeof(Bond2)/(2*sizeof(int));
+  k1  = 0;
+  k2  = 1;
+  for (i=0;i<nb2;i++)  {
+    G = new Edge();
+    G->SetEdge ( Bond2[k1],Bond2[k2],1 );
+    G2.AddEdge ( G );
+    k1 += 2;
+    k2 += 2;
+  }
+
+  G1.Build();
+  G2.Build();
+
+  U.GMatchGraphs ( &G1,&G2,nv1 );
+
+  U.PrintGMatches();
+
+
+}
+*/
+
diff --git a/mmdb2/mmdb_math_graph.h b/mmdb2/mmdb_math_graph.h
new file mode 100644
index 0000000..f30625f
--- /dev/null
+++ b/mmdb2/mmdb_math_graph.h
@@ -0,0 +1,494 @@
+//  $Id: mmdb_math_graph.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_math_graph  <interface>
+//       ~~~~~~~~~
+//  **** Namespace: mmdb::math::
+//       ~~~~~~~~~~
+//  **** Classes :  Vertex     ( graph vertex                        )
+//       ~~~~~~~~~  Edge       ( graph edge                          )
+//                  Graph      ( structural graph                    )
+//                  Match      ( match of structural graphs          )
+//                  GraphMatch ( CSIA algorithms for graphs matching )
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  When used, please cite:
+//
+//   Krissinel, E. and Henrick, K. (2004)
+//   Common subgraph isomorphism detection by backtracking search.
+//   Software - Practice and Experience, 34, 591-607.
+//
+//  =================================================================
+//
+
+#ifndef  __MMDB_MATH_Graph__
+#define  __MMDB_MATH_Graph__
+
+#include <time.h>
+
+#include "mmdb_atom.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  =========================  Vertex  ==========================
+
+    DefineClass(Vertex);
+
+    enum GRAPH_FLAG  {
+      CHIRAL_RIGHT  = 0x10000000,
+      CHIRAL_LEFT   = 0x20000000,
+      ATOM_LEAVING  = 0x40000000,
+      HYDROGEN_BOND = 0x0F000000,
+      SYMREL_MASK   = 0x00FF0000,
+      CHIRAL_MASK   = 0xCFFFFFFF,
+      TYPE_MASK     = 0x00FFFFFF
+    };
+
+    class Vertex : public io::Stream  {
+
+      friend class Graph;
+      friend class GraphMatch;
+
+      public:
+
+        Vertex ();
+        Vertex ( io::RPStream Object );
+        Vertex ( int  vtype, cpstr vname );
+        Vertex ( int  vtype );
+        Vertex ( cpstr chem_elem );
+        Vertex ( cpstr chem_elem, cpstr name );
+        ~Vertex();
+
+        void  SetVertex  ( cpstr chem_elem );
+        void  SetVertex  ( int vtype, cpstr vname );
+        void  SetVertex  ( int vtype   );
+        void  SetType    ( int vtype   );
+        void  SetTypeExt ( int typeExt );
+
+        void  RemoveChirality();
+        void  LeaveChirality ( int eltype );
+
+        void  SetName     ( cpstr vname );
+        void  SetProperty ( int vprop  );
+        void  SetID       ( int vid    );
+        void  AddBond     ();
+        void  CopyNBonds  ( PVertex V );
+        inline void  SetUserID   ( int vid ) { user_id = vid; }
+        inline int   GetProperty () { return property; }
+        inline int   GetID       () { return id;       }
+        inline int   GetUserID   () { return user_id;  }
+        inline cpstr GetName     () { return name;     }
+        inline int   GetType     () { return type;     }
+        inline int   GetTypeExt  () { return type_ext; }
+        int   GetNBonds   ();
+
+        void  SaveType    ();  // in userid
+        void  RestoreType ();  // from userid
+        void  CopyType    ( PVertex V );
+
+        virtual void Print ( int PKey );
+
+        virtual void Copy ( PVertex V );
+
+        void  read  ( io::RFile f );
+        void  write ( io::RFile f );
+
+        void  mem_read  ( cpstr S, int & l );
+        void  mem_write ( pstr S, int & l );
+
+      protected:
+        pstr name;     // name may be general, "C", "Hg", "Cl" etc.
+        int  type;     // type of vertex, see comments in
+                       // mmdb_math_graph.cpp
+        int  type_ext; // vertex type extention
+        int  property; // flagwise properties -- user-defined
+        int  id;       // a graph-defined vertex id
+        int  user_id;  // a user-defined vertex id
+
+        void InitVertex();
+
+    };
+
+    DefineStreamFunctions(Vertex);
+
+
+    //  ==========================  Edge  ===========================
+
+    enum GRAPH_BOND  {
+      BOND_SINGLE   = 1,
+      BOND_DOUBLE   = 2,
+      BOND_AROMATIC = 3,
+      BOND_TRIPLE   = 4
+    };
+
+    DefineClass(Edge);
+
+    class Edge : public io::Stream  {
+
+      friend class Graph;
+      friend class CGMatch;
+
+      public:
+
+        Edge ();
+        Edge ( io::RPStream Object );
+        Edge ( int vx1, int vx2, int btype );  // vx1,vx2 are numbered
+                                               // as 1,2,3 on and refer
+                                               // to vertices in the order
+                                               // as they were added to
+                                               // the graph; btype>0
+        ~Edge();
+
+        void  SetEdge ( int vx1, int vx2, cpstr btype );
+        void  SetEdge ( int vx1, int vx2, int  btype ); // btype>0
+
+        void  SetType     ( int btype );
+        void  SetProperty ( int eprop );
+        void  SaveType    ();  // in property
+        void  RestoreType ();  // from property
+
+        inline int GetVertex1  () { return v1;       }
+        inline int GetVertex2  () { return v2;       }
+        inline int GetType     () { return type;     }
+        inline int GetProperty () { return property; }
+
+        virtual void Print ( int PKey );
+
+        virtual void Copy  ( PEdge G );
+
+        void  read  ( io::RFile f );
+        void  write ( io::RFile f );
+
+        void  mem_read  ( cpstr S, int & l );
+        void  mem_write ( pstr  S, int & l );
+
+      protected:
+        int  v1,v2;  //  >=1
+        int  type;
+        int  property;
+
+        void  InitEdge();
+
+    };
+
+    DefineStreamFunctions(Edge);
+
+
+    //  ==========================  Graph  ============================
+
+    enum GRAPH_RC  {
+      MKGRAPH_Ok            =  0,
+      MKGRAPH_NoAtoms       = -1,
+      MKGRAPH_ChangedAltLoc =  1,
+      MKGRAPH_MaxOccupancy  =  2
+    };
+
+    DefineClass(Graph);
+
+    class Graph : public io::Stream  {
+
+      friend class GraphMatch;
+      friend class CSBase0;
+
+      public :
+
+        Graph ();
+        Graph ( PResidue R, cpstr altLoc=NULL );
+        Graph ( io::RPStream Object );
+        ~Graph();
+
+        void  Reset   ();
+        void  SetName ( cpstr gname );
+        inline pstr GetName() { return name; }
+
+        //   AddVertex(..) and AddEdge(..) do not copy the objects, but
+        // take them over. This means that application should forget
+        // about pointers to V and G once they were given to Graph.
+        // Vertices and edges  must be allocated newly prior each call
+        // to AddVertex(..) and AddEdge(..).
+        void  AddVertex   ( PVertex  V );
+        void  AddEdge     ( PEdge    G );
+        void  SetVertices ( PPVertex V, int vlen );
+        void  SetEdges    ( PPEdge   G, int glen );
+
+        void  RemoveChirality();
+        void  LeaveChirality ( int eltype );
+
+        //   MakeGraph(..) makes a graph corresponding to residue R.
+        // The graphs vertices then correspond to the residue's atoms
+        // (Vertex::userid points to atom R->atom[Vertex::userid]),
+        // edges are calculated as chemical bonds between atoms basing
+        // on the table of cut-off distances.
+        //   altCode specifies a particular conformation that should be
+        // used for making the graph. If it is set to "" or NULL ("empty"
+        // altcode) but the residue does not have conformation which
+        // contains *only* ""-altcode atoms, a conformation corresponding
+        // to maximal occupancy will be used. The same will happen if
+        // altcode information in residue is not correct, whatever altCode
+        // is specified.
+        //   After making the graph, Build(..) should be called as usual
+        // before graph matching.
+        //   Non-negative return means that graph has been made.
+        // MakeGraph(..) may return:
+        //   MKGRAPH_Ok             everything is Ok
+        //   MKGRAPH_NoAtoms        residue does not have atoms, graph
+        //                          is not made
+        //   MKGRAPH_ChangedAltLoc  a different altcode was used because
+        //                          the residue has only one altcode and
+        //                          that is different of
+        //   MKGRAPH_MaxOccupancy   a maximal-occupancy conformation has
+        //                          been chosen because of default
+        //                          ""-altcode supplied or incorrect
+        //                          altcode information in the residue
+        int   MakeGraph   ( PResidue R, cpstr altLoc=NULL );
+
+        int   MakeGraph   ( PPAtom atom, int nAtoms );
+
+        void  HideType    ( int bond_vx_type );
+        void  ExcludeType ( int type );
+
+        void  MakeSymmetryRelief ( bool noCO2 );
+        void  IdentifyRings      ();
+        int   IdentifyConnectedComponents();  // returns their number >= 1
+
+        int   Build       ( bool bondOrder );  // returns 0 if Ok
+
+        void  MakeVertexIDs      ();  // simply numbers vertices as 1.. on
+        int   GetVertexID        ( int vertexNo );
+        int   GetVertexNo        ( cpstr vname  );
+        // GetBondedVertexID(..) works after MoveType(..)
+        int   GetNBondedVertices ( int vertexNo );
+        int   GetBondedVertexID  ( int vertexNo, int bond_vx_type,
+                                   int bondNo );
+
+        PVertex   GetVertex ( int vertexNo );  // 1<=vertexNo<=nVertices
+        inline int GetNofVertices() { return nVertices; }
+
+        PEdge    GetEdge    ( int edgeNo );    // 1<=edgeNo<=nEdges
+        inline int GetNofEdges() { return nEdges;    }
+
+        void  GetVertices ( PPVertex & V, int & nV );
+        void  GetEdges    ( PPEdge   & E, int & nE );
+
+        virtual void Print();
+        void  Print1();
+
+        virtual void Copy ( PGraph G );
+
+        void  read  ( io::RFile f );
+        void  write ( io::RFile f );
+
+        void  mem_read  ( cpstr S, int & l );
+        void  mem_write ( pstr S, int & l );
+
+      protected :
+        pstr     name;
+        int      nVertices,nEdges, nAllVertices,nAllEdges;
+        PPVertex vertex;
+        PPEdge   edge;
+        imatrix  graph;
+
+        void  InitGraph ();
+        void  FreeMemory();
+
+        void  markConnected ( int vno, int cno );
+
+      private :
+        int  nVAlloc,nEAlloc,nGAlloc;
+
+    };
+
+    DefineStreamFunctions(Graph);
+
+
+    //  =========================  GMatch  ==========================
+
+    DefineClass(GMatch);
+    DefineStreamFunctions(GMatch);
+
+    class GMatch : public io::Stream  {
+
+      friend class GraphMatch;
+
+      public :
+
+        GMatch ();
+        GMatch ( io::RPStream Object );
+        GMatch ( ivector FV1, ivector FV2, int nv, int n, int m );
+        ~GMatch();
+
+        // FV1[] and FV2[] are copied into internal buffers
+        void SetMatch ( ivector FV1, ivector FV2, int nv, int n, int m );
+
+        bool isMatch       ( ivector FV1, ivector FV2, int nv );
+        bool isCombination ( ivector FV1, ivector FV2, int nv );
+
+        // do not allocate or dispose FV1 and FV2 in application!
+        void GetMatch ( ivector & FV1, ivector & FV2, int & nv,
+                        realtype & p1, realtype & p2 );
+
+        void read  ( io::RFile f );
+        void write ( io::RFile f );
+
+        void mem_read  ( cpstr S, int & l );
+        void mem_write ( pstr  S, int & l );
+
+      protected :
+        int     n1,n2,mlength;
+        ivector F1,F2;
+
+        void InitGMatch();
+
+      private :
+        int nAlloc;
+
+    };
+
+
+    //  =======================  GraphMatch  =========================
+
+    #define  _UseRecursion
+
+    enum GRAPH_MATCH_FLAG  {
+      GMF_UniqueMatch    = 0x00000001,
+      GMF_NoCombinations = 0x00000002
+    };
+
+    enum VERTEX_EXT_TYPE  {
+      EXTTYPE_Ignore   = 0,
+      EXTTYPE_Equal    = 1,
+      EXTTYPE_AND      = 2,
+      EXTTYPE_OR       = 3,
+      EXTTYPE_XOR      = 4,
+      EXTTYPE_NotEqual = 5,
+      EXTTYPE_NotAND   = 6,
+      EXTTYPE_NotOR    = 7
+    };
+
+    DefineClass(GraphMatch);
+
+    class GraphMatch : public io::Stream  {
+
+      public :
+
+        GraphMatch ();
+        GraphMatch ( io::RPStream Object );
+        ~GraphMatch();
+
+        void SetFlag          ( word flag );
+        void RemoveFlag       ( word flag );
+        void SetMaxNofMatches ( int maxNofMatches, bool stopOnMaxN );
+        void SetTimeLimit     ( int maxTimeToRun=0 );
+        inline bool GetStopSignal() { return Stop; }
+
+        void Reset();
+
+        //  MatchGraphs looks for maximal common subgraphs of size
+        //  not less than minMatch. The number of found subgraphs
+        //  is returned by GetNofMatches(), the subgraph vertices
+        //  are returned by GetMatch(..). Control parameters:
+        //      vertexType   true if vertex type should be taken
+        //                   into account and False otherwise
+        //      vertexExt    key to use extended vertex types (defined
+        //                   as type_ext in Vertex).
+        void MatchGraphs    ( PGraph Gh1, PGraph Gh2, int minMatch,
+                              bool vertexType=true,
+                              VERTEX_EXT_TYPE vertexExt=EXTTYPE_Ignore );
+        void PrintMatches   ();
+        inline int GetNofMatches  () { return nMatches; }
+        inline int GetMaxMatchSize() { return maxMatch; }
+
+        // do not allocate or dispose FV1 and FV2 in application!
+        // FV1/p1 will always correspond to Gh1, and FV2/p2 -
+        // to Gh2 as specified in MatchGraphs(..)
+        void GetMatch ( int MatchNo, ivector & FV1, ivector & FV2,
+                        int & nv, realtype & p1, realtype & p2 );
+
+        void read  ( io::RFile f );
+        void write ( io::RFile f );
+
+        void mem_read  ( cpstr S, int & l );
+        void mem_write ( pstr  S, int & l );
+
+      protected :
+        PGraph   G1,G2;
+        PPVertex V1;
+        PPVertex V2;
+        imatrix  c1,c2;
+        bool     swap;
+    #ifndef _UseRecursion
+        ivector  jj;
+    #endif
+        int      n,m;
+
+        imatrix3 P;
+        imatrix  iF1;
+        ivector  F1,F2,ix;
+
+        int      nMatches,maxNMatches;
+        PPGMatch Match;
+        bool     wasFullMatch,Stop,stopOnMaxNMathches;
+        word     flags;
+        int      maxMatch,timeLimit;
+
+        void  InitGraphMatch();
+        void  FreeMemory    ();
+        void  FreeRecHeap   ();
+        void  GetMemory     ();
+        void  GetRecHeap    ();
+        int   Initialize    ( bool vertexType, int vertexExt );
+    #ifdef _UseRecursion
+        void  Backtrack     ( int i );          // exact matching
+    #else
+        void  Ullman        ();
+    #endif
+        void  Backtrack1    ( int i, int k0 );  // exact/partial matching
+        void  CollectMatch  ( int nm );
+
+      private :
+        int     nAlloc,mAlloc,nMAlloc;
+        time_t  startTime;
+
+    };
+
+    DefineStreamFunctions(GraphMatch);
+
+    extern void  SetGraphAllocPortion ( int alloc_portion );
+
+    /*
+    extern void  TestGraphMatch();
+    */
+
+  }  // namespace math
+
+}  // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_math_linalg.cpp b/mmdb2/mmdb_math_linalg.cpp
new file mode 100644
index 0000000..3709101
--- /dev/null
+++ b/mmdb2/mmdb_math_linalg.cpp
@@ -0,0 +1,990 @@
+//  $Id: mmdb_math_linalg.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  LinAlg  <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MMDB  ( MacroMolecular Data Base )
+//       ~~~~~~~~~
+//
+//  (C) E.Krissinel  2000-2013
+//
+//  =================================================================
+//
+//
+
+#include <stdio.h>
+#include <math.h>
+
+#include "mmdb_math_linalg.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+
+    //  ==========================  Jacobi  =============================
+
+
+    void  Jacobi ( int     N,     // dimension of the matrix
+                   rmatrix A,     // matrix to diagonalize; the lower
+                                  // triangle, except the diagonal,
+                                  // will remain unchanged
+                   rmatrix T,     // eigenvectors placed as columns
+                   rvector Eigen, // vector of eigenvalues, orderd
+                                  // by increasing
+                   rvector Aik,   // working array
+                   int &   Signal // 0 <=> Ok, ItMax <=> iteration limit
+                                  // exchausted.
+                 )  {
+    //  Diagonalization of symmetric matrices  by the method of Jacobi.
+    //  Key  variables:
+    //     ItMax  -  the maximum available number of iterations
+    //     Eps1   -  is used in  SNA  and  CSA  calculations
+    //     Eps2   -  is the level of the elimination of the
+    //               non-diagonal matrix elements
+    //     Eps3   -  the criterion to stop the iterations.
+    //               The iterations stop if (1-Sigma1/Sigma2)<=Eps3
+    //               where  Sigma1 is the dekart norm of the eigenvalues
+    //               at the preceding iteration and  Sigma2 is
+    //               the same for the current iteration.
+
+    realtype Eps1,Eps2,Eps3;
+    realtype Sigma1,Sigma2,OffDsq, SPQ,CSA,SNA,Q,P, HoldIK,HoldKI;
+    int      ItMax;
+    int      i,j,k,Iter;
+
+      Eps1  = 6.0e-9;
+      Eps2  = 9.0e-12;
+      Eps3  = 1.0e-8;
+      ItMax = 9999;
+
+      Signal = 0;
+
+      if (N<=1)  {
+        T[1][1]  = 1.0;
+        Eigen[1] = A[1][1];
+        return;
+      }
+
+      for (i=1;i<=N;i++)  {
+        for (j=1;j<=N;j++)
+          T[i][j] = 0.0;
+        T[i][i]  = 1.0;
+        Eigen[i] = A[i][i];
+      }
+
+      Sigma1 = 0.0;
+      OffDsq = 0.0;
+
+      //  Sigma1  is the Dekart measure of the diagonal elements
+      //  OffDsq  is the Dekart measure of the non-diagonal elements
+
+      for (i=1;i<=N;i++)  {
+        Sigma1 += A[i][i]*A[i][i];
+        if (i<N)
+          for (j=i+1;j<=N;j++)
+            OffDsq += A[i][j]*A[i][j];
+      }
+
+      if (OffDsq<Eps2*Eps2)  return;
+
+      //  S      = OffDsq*2.0+Sigma1;
+      Iter   = 1;
+      HoldIK = 1.0;
+
+      while ((Iter<=ItMax) && (HoldIK>Eps3))  {
+
+        for (i=1;i<N;i++)
+          for (j=i+1;j<=N;j++)  {
+
+            Q = fabs(A[i][i]-A[j][j]);
+
+            if ((Q<=Eps1) || (fabs(A[i][j])>Eps2))  {
+              if (Q>Eps1)  {
+                P   = 2.0*A[i][j]*(Q/(A[i][i]-A[j][j]));
+                SPQ = sqrt(P*P+Q*Q);
+                CSA = sqrt((1.0+Q/SPQ)/2.0);
+                SNA = P/(SPQ*CSA*2.0);
+              } else  {
+                CSA = sqrt(0.5);
+                SNA = CSA;
+              }
+              for (k=1;k<=N;k++)  {
+                HoldKI  = T[k][i];
+                T[k][i] = HoldKI*CSA + T[k][j]*SNA;
+                T[k][j] = HoldKI*SNA - T[k][j]*CSA;
+              }
+
+              for (k=i;k<=N;k++)
+                if (k<=j)  {
+                  Aik[k]  = A[i][k];
+                  A[i][k] = CSA*Aik[k] + SNA*A[k][j];
+                  if (k==j)  {
+                    A[j][k] = SNA*Aik[k] - CSA*A[j][k];
+                    Aik[j]  = SNA*Aik[i] - CSA*Aik[j];
+                  }
+                } else  {
+                  HoldIK  = A[i][k];
+                  A[i][k] = CSA*HoldIK + SNA*A[j][k];
+                  A[j][k] = SNA*HoldIK - CSA*A[j][k];
+                }
+
+              for (k=1;k<=j;k++)
+                if (k>i)
+                  A[k][j] = SNA*Aik[k] - CSA*A[k][j];
+                else  {
+                  HoldKI  = A[k][i];
+                  A[k][i] = CSA*HoldKI + SNA*A[k][j];
+                  A[k][j] = SNA*HoldKI - CSA*A[k][j];
+                }
+
+            }
+
+          }
+
+        Sigma2 = 0.0;
+        for (i=1;i<=N;i++)  {
+          Eigen[i] = A[i][i];
+          Sigma2  += Eigen[i]*Eigen[i];
+        }
+
+        HoldIK = fabs(1.0-Sigma1/Sigma2);
+        Sigma1 = Sigma2;
+        Iter++;
+
+      }
+
+      if (Iter>ItMax)  Signal = ItMax;
+
+      for (i=1;i<=N;i++)  {
+        k = i;
+        for (j=i;j<=N;j++)
+          if (Eigen[j]<Eigen[k])  k = j;
+        if (k!=i)  {
+          P = Eigen[k];
+          Eigen[k] = Eigen[i];
+          Eigen[i] = P;
+          for (j=1;j<=N;j++)  {
+            P = T[j][k];
+            T[j][k] = T[j][i];
+            T[j][i] = P;
+          }
+        }
+      }
+
+
+    }
+
+
+    // -----------------------------------------------------
+
+    void  PbCholDecomp ( int        N,
+                         rvector    HDiag,
+                         realtype   MaxOff,
+                         realtype   MachEps,
+                         rmatrix    L,
+                         realtype & MaxAdd )  {
+
+    //  A5.5.2  :  Perturbed Cholesky Decomposition
+    // Part of the modular software system from
+    // the appendix of the book "Numerical Methods for Unconstrained
+    // Optimization and Nonlinear Equations" by Dennis & Schnabel 1983.
+
+    int      i,j,k;
+    realtype MinL,MinL2,S,MinLjj,MaxOffl, BB;
+
+      MaxOffl = MaxOff;
+      MinL    = sqrt(sqrt(MachEps))*MaxOffl;
+      if (MaxOffl==0.0)  {
+        for (i=1;i<=N;i++)  {
+          BB = fabs(HDiag[i]);
+          if (BB>MaxOffl)  MaxOffl = BB;
+        }
+        MaxOffl = sqrt(MaxOffl);
+      }
+
+      MinL2  = sqrt(MachEps)*MaxOffl;
+      MaxAdd = 0.0;
+      for (j=1;j<=N;j++)  {
+        S = 0.0;
+        if (j>1)
+          for (i=1;i<j;i++)
+            S += L[j][i]*L[j][i];
+        L[j][j] = HDiag[j] - S;
+        MinLjj  = 0.0;
+        if (j<N)
+          for (i=j+1;i<=N;i++)  {
+            S = 0.0;
+            if (j>1)
+              for (k=1;k<j;k++)
+                S += L[i][k]*L[j][k];
+            L[i][j] = L[j][i] - S;
+            BB = fabs(L[i][j]);
+            if (BB>MinLjj)  MinLjj = BB;
+          }
+        BB = MinLjj/MaxOffl;
+        if (BB>MinL)  MinLjj = BB;
+                else  MinLjj = MinL;
+        if (L[j][j]>MinLjj*MinLjj) L[j][j] = sqrt(L[j][j]);
+        else  {
+          if (MinL2>MinLjj)  MinLjj = MinL2;
+          BB = MinLjj*MinLjj-L[j][j];
+          if (BB>MaxAdd)  MaxAdd = BB;
+          L[j][j] = MinLjj;
+        }
+        if (j<N)
+          for (i=j+1;i<=N;i++)
+            L[i][j] /= L[j][j];
+      }
+
+    }
+
+
+
+    // -----------------------------------------------------
+
+    void  LSolve ( int N, rmatrix L, rvector B, rvector Y )  {
+    //  A3.2.3a  :  Cholesky's   L - Solution  of
+    //              L*Y  =  B  ( given  B )
+    int  i,j;
+      Y[1] = B[1]/L[1][1];
+      if (N>1)
+        for (i=2;i<=N;i++)  {
+          Y[i] = B[i];
+          for (j=1;j<i;j++)
+            Y[i] -= L[i][j]*Y[j];
+          Y[i] /= L[i][i];
+        }
+    }
+
+
+    // -----------------------------------------------------
+
+    void  LTSolve ( int N, rmatrix L, rvector Y, rvector X )  {
+    //  A3.2.3b  :   Cholesky's   LT - Solution  of
+    //               LT*X  =  Y  ( given  Y )
+    int  i,j;
+      X[N] = Y[N]/L[N][N];
+      if (N>1)
+        for (i=N-1;i>=1;i--)  {
+          X[i] = Y[i];
+          for (j=i+1;j<=N;j++)
+            X[i] -= L[j][i]*X[j];
+          X[i] /= L[i][i];
+        }
+    }
+
+
+    // -----------------------------------------------------
+
+    void  ChSolve ( int N, rmatrix L, rvector G, rvector S )  {
+    //  A3.2.3  :  Solution of the equation    L*LT*S = G
+    //             by the  Cholesky's  method
+    //int i;
+      LSolve  ( N,L,G,S );
+      LTSolve ( N,L,S,S );
+    //  for (i=1;i<=N;i++)
+    //    S[i] = -S[i];
+    }
+
+
+
+    //  ----------------------------------------------------
+
+    void  FastInverse (  int N, rmatrix A, ivector J0,
+    //#D                     realtype & Det,
+                         int & Signal )  {
+    //
+    //      17.01.91  <--  Last Date of Modification.
+    //                    ----------------------------
+    //
+    // ================================================
+    //
+    //        Fast Inversion of the matrix  A
+    //      by the method of  GAUSS - JOIRDAN  .
+    //
+    // ------------------------------------------------
+    //
+    //          Input  parameters  are  :
+    //
+    //     N   -   dimension of the matrix
+    //     A   -   the matrix [1..N][1..N] to be inverted.
+    //
+    // ------------------------------------------------
+    //
+    //     J0  -   integer vector [1..N] for temporal storage
+    //
+    //
+    // ------------------------------------------------
+    //
+    //          Output parameters  are  :
+    //
+    //     A   -   the inverted matrix
+    //     Signal - the error key :
+    //            = 0   <=>   O'K
+    //              else
+    //           degeneration was found, and
+    //           the rang of matrix is  Signal-1.
+    //
+    //        Variable  Det  may return the determinant
+    //     of matrix A.  To obtain it, remove all comments
+    //     of form  //#D .
+    //
+    // ------------------------------------------------
+    //
+    //          Key  Variables  are  :
+    //
+    //     Eps   -  is the level for the degeneration
+    //              detection.  Keep in mind,  that
+    //              this routine does not norm the
+    //              matrix given,  and thus Eps1
+    //              is the  ABSOLUTE  value.
+    //
+    // ================================================
+    //
+
+    realtype  Eps = 1.0e-16;
+
+    int       i,j,k,i0;
+    realtype  A0,B;
+    rvector   Ai,Ai0;
+
+      Signal = 0;
+      if  (N<=1)   {
+        if (fabs(A[1][1])<Eps)  {
+          Signal = 1;
+          return;
+        }
+        A[1][1] = 1.0/A[1][1];
+    //#D   Det      = A[1][1];
+        return;
+      }
+
+      if (N==2)  {
+        A0 = A[1][1];
+        B  = A0*A[2][2] - A[1][2]*A[2][1];
+    //#D   Det = B;
+        if (fabs(B)<Eps)  {
+          Signal = 1;
+          return;
+        }
+        A[1][1] = A[2][2]/B;
+        A[2][2] = A0/B;
+        B       = -B;
+        A[1][2] /= B;
+        A[2][1] /= B;
+        return;
+      }
+
+      for (i=1;i<=N;i++)  {
+        //  1. Finding of the leading element ( in A0 );
+        //     i0  is the number of the leading string
+        A0 = 0.0;
+        i0 = 0;
+        for (j=i;j<=N;j++)  {
+          if (fabs(A[j][i])>A0)  {
+            A0 = fabs(A[j][i]);
+            i0 = j;
+          }
+        }
+        if (A0<Eps)  {
+          Signal = i;   //  Degeneration is found here
+          return;
+        }
+
+        //  2. Swapping the string
+        J0[i] = i0;
+        B     = 1.0/A[i0][i];
+        Ai    = A[i0];
+        Ai0   = A[i];
+        A[i]  = Ai;
+        A[i0] = Ai0;
+        for (j=1;j<=N;j++)
+          Ai[j] = Ai[j]*B;
+        Ai[i] = B;
+
+        //  3. Substracting the strings
+        for (j=1;j<=N;j++)
+          if (i!=j)  {
+            Ai0 = A[j];
+            B   = Ai0[i];
+            Ai0[i] = 0.0;
+            for (k=1;k<=N;k++)
+              Ai0[k] = Ai0[k] - B*Ai[k];
+           }
+
+    //#D   Det = Det/Ai[i];
+
+      }
+
+      //  4.  Back Swapping the columns
+      for (i=N;i>=1;i--)  {
+        j = J0[i];
+        if (j!=i)  {
+    //#D     Det = -Det;
+          for (k=1;k<=N;k++)  {
+            B       = A[k][i];
+            A[k][i] = A[k][j];
+            A[k][j] = B;
+          }
+        }
+      }
+
+      return;
+
+    }    //  End of the procedure  FastInverse
+
+
+
+
+    //  ----------------------------------------------------
+
+    realtype Sign ( realtype A, realtype B )  {
+      if (B>=0.0)  return  A;
+             else  return -A;
+    }
+
+    realtype SrX2Y2 ( realtype X, realtype Y )  {
+    realtype Ax,Ay;
+      Ax = fabs(X);
+      Ay = fabs(Y);
+      if (Ay>Ax)   return  Ay*sqrt((X*X)/(Y*Y)+1.0);
+      if (Ay==Ax)  return  Ax*sqrt(2.0);
+      return  Ax*sqrt((Y*Y)/(X*X)+1.0);
+    }
+
+
+    //  ----------------------------------------------------
+
+    void  SVD ( int    NA,  int       M,   int N,
+                rmatrix A,  rmatrix   U,   rmatrix V,
+                rvector W,  rvector RV1,
+                bool MatU,  bool   MatV,
+                int & RetCode )  {
+    //
+    //      13.12.01  <--  Last Modification Date
+    //                    ------------------------
+    //
+    // ================================================
+    //
+    //         The    Singular Value Decomposition
+    //    of the matrix  A  by the algorithm from
+    //      G.Forsait, M.Malkolm, K.Mouler.  Numerical
+    //    methods of mathematical calculations
+    //    M., Mir, 1980.
+    //
+    //         Matrix  A  is represented as
+    //
+    //         A  =  U * W * VT
+    //
+    // ------------------------------------------------
+    //
+    //  All dimensions are indexed from 1 on.
+    //
+    // ------------------------------------------------
+    //
+    //         Input  parameters:
+    //
+    //     NA  -   number of lines in A. NA may be
+    //           equal to M or N  only.  If NA=M
+    //           then usual SVD will be made. If MA=N
+    //           then matrix A is transposed before
+    //           the decomposition, and the meaning of
+    //           output parameters  U  and  V  is
+    //           swapped (U accepts VT and VT accepts U).
+    //           In other words, matrix  A  has physical
+    //           dimension of  M x N , same as U and V;
+    //           however the logical dimension of it
+    //           remains that of  N x M .
+    //     M   -   number of lines in  U
+    //     N   -   number of columns in  U,V and length
+    //           of  W,RV1 .  Always provide  M >= N  !
+    //     A   -   matrix [1..M][1..N] or [1..N][1..M]
+    //           to be decomposed. The matrix does not
+    //           change,  and it may coincide with  U  or
+    //           V, if NA=M (in which case  A  does change)
+    //     MatU -  compute  U , if set True
+    //     MatV -  compute  V , if set True
+    //     RV1  -  temporary array [1..N].
+    //     U    - should be always supplied as an array of
+    //            [1..M][1..N], M>=N .
+    //     V    - should be suuplied as an array of
+    //            [1..N][1..N] if MatV is True .
+    //
+    // ------------------------------------------------
+    //
+    //          Output parameters  are  :
+    //
+    //     W   -   N non-ordered singular values,
+    //           if  RetCode=0. If RetCode<>0, the
+    //           RetCode+1 ... N -th values are still
+    //           valid
+    //     U   -   matrix of right singular vectors
+    //           (arranged in columns),  corresponding
+    //           to the singular values in  W,  if
+    //           RetCode=0 and MatU is True.  If MatU
+    //           is False, U  is still used as a
+    //           temporary array. If RetCode<>0 then
+    //           the  RetCode+1 ... N -th vectors
+    //           are  valid
+    //     V   -   matrix of left singular vectors
+    //           (arranged in columns),  corresponding
+    //           to the singular values in  W,  if
+    //           RetCode=0 and MatV is True. If MatV
+    //           is False, V is not used and may be set
+    //           to NULL. If RetCode<>0 then the
+    //           RetCode+1 ... N -th vectors are valid
+    //     RetCode - the error key :
+    //            = 0   <=>   O'K
+    //              else
+    //            = k, if the k-th singular value
+    //                 was not computed after 30 iterations.
+    //
+    // ------------------------------------------------
+    //
+    //          Key  Variables  are  :
+    //
+    //     ItnLimit  -  the limit for iterations
+    //
+    //     This routine does not use any machine-dependent
+    //  constants.
+    //
+    // ================================================
+    //
+    //
+    int       ItnLimit=300;
+    int       i,j,k,l,i1,k1,l1,its,mn,ExitKey;
+    realtype  C,G,F,X,S,H,Y,Z,Scale,ANorm,GG;
+
+      l1      = 0;  // this is to keep compiler happy
+      RetCode = 0;
+
+      if (U!=A)  {
+        if (NA==M)
+          for (i=1;i<=M;i++)
+            for (j=1;j<=N;j++)
+              U[i][j] = A[i][j];
+        else
+          for (i=1;i<=M;i++)
+            for (j=1;j<=N;j++)
+              U[i][j] = A[j][i];
+      }
+
+      G     = 0.0;
+      Scale = 0.0;
+      ANorm = 0.0;
+
+      for (i=1;i<=N;i++)  {
+        l      = i+1;
+        RV1[i] = Scale*G;
+        G      = 0.0;
+        S      = 0.0;
+        Scale  = 0.0;
+        if (i<=M)  {
+          for (k=i;k<=M;k++)
+            Scale += fabs(U[k][i]);
+          if (Scale!=0.0)  {
+            for (k=i;k<=M;k++)  {
+              U[k][i] /= Scale;
+              S       += U[k][i]*U[k][i];
+            }
+            F = U[i][i];
+            G = -Sign(sqrt(S),F);
+            H = F*G-S;
+            U[i][i] = F-G;
+            if (i!=N)
+              for (j=l;j<=N;j++)  {
+                S = 0.0;
+                for (k=i;k<=M;k++)
+                  S += U[k][i]*U[k][j];
+                F = S/H;
+                for (k=i;k<=M;k++)
+                  U[k][j] += F*U[k][i];
+              }
+            for (k=i;k<=M;k++)
+              U[k][i] *= Scale;
+          }
+        }
+
+        W[i]  = Scale*G;
+        G     = 0.0;
+        S     = 0.0;
+        Scale = 0.0;
+
+        if ((i<=M) && (i!=N))  {
+          for (k=l;k<=N;k++)
+            Scale += fabs(U[i][k]);
+          if (Scale!=0.0)  {
+            for (k=l;k<=N;k++)  {
+              U[i][k] /= Scale;
+              S       += U[i][k]*U[i][k];
+            }
+            F = U[i][l];
+            G = -Sign(sqrt(S),F);
+            H = F*G-S;
+            U[i][l] = F-G;
+            for (k=l;k<=N;k++)
+              RV1[k] = U[i][k]/H;
+            if (i!=M)
+              for (j=l;j<=M;j++)  {
+                S = 0.0;
+                for (k=l;k<=N;k++)
+                  S += U[j][k]*U[i][k];
+                for (k=l;k<=N;k++)
+                  U[j][k] += S*RV1[k];
+              }
+            for (k=l;k<=N;k++)
+              U[i][k] *= Scale;
+          }
+        }
+
+        ANorm = RMax( ANorm,fabs(W[i])+fabs(RV1[i]) );
+
+      }
+
+      //   Accumulation of the right-hand transformations
+
+      if  (MatV)
+        for (i=N;i>=1;i--)  {
+          if (i!=N)  {
+            if (G!=0.0)  {
+              for (j=l;j<=N;j++)
+                V[j][i] = (U[i][j]/U[i][l]) / G;
+              for (j=l;j<=N;j++)  {
+                S = 0.0;
+                for (k=l;k<=N;k++)
+                  S += U[i][k]*V[k][j];
+                for (k=l;k<=N;k++)
+                  V[k][j] += S*V[k][i];
+              }
+            }
+            for (j=l;j<=N;j++)  {
+              V[i][j] = 0.0;
+              V[j][i] = 0.0;
+            }
+          }
+
+          V[i][i] = 1.0;
+          G       = RV1[i];
+          l       = i;
+
+        }
+
+
+      //   Accumulation of the left-hand transformations
+
+      if (MatU)  {
+        mn = N;
+        if (M<N)  mn = M;
+
+        for (i=mn;i>=1;i--)  {
+          l = i+1;
+          G = W[i];
+          if (i!=N)
+            for (j=l;j<=N;j++)
+              U[i][j] = 0.0;
+          if (G!=0.0)  {
+            if (i!=mn)
+              for (j=l;j<=N;j++)  {
+                S = 0.0;
+                for (k=l;k<=M;k++)
+                  S += U[k][i]*U[k][j];
+                F = (S/U[i][i]) / G;
+                for (k=i;k<=M;k++)
+                  U[k][j] += F*U[k][i];
+              }
+            for (j=i;j<=M;j++)
+              U[j][i] /= G;
+          } else
+            for (j=i;j<=M;j++)
+              U[j][i] = 0.0;
+
+          U[i][i] += 1.0;
+
+        }
+      }
+
+      //   Diagonalization of the two-diagonal form.
+
+      for (k=N;k>=1;k--)  {
+        k1  = k-1;
+        its = 0;
+
+        do  {
+          ExitKey  = 0;
+          l        = k+1;
+          while ((ExitKey==0) && (l>1))  {
+            l--;
+            l1 = l-1;
+            if (fabs(RV1[l])+ANorm==ANorm)   ExitKey=1;
+            else if (l1>0)  {
+              if (fabs(W[l1])+ANorm==ANorm)  ExitKey=2;
+            }
+          }
+
+    //      if (ExitKey!=1)  {  <-- this is original statement
+          if (ExitKey>1)  {  // <-- prevents from corruption due to l1<1.
+                             // This is a rare case as RV1[1] should be
+                             // always 0.0 . Apparently this logics is
+                             // on the edge of float-point arithmetic,
+                             // therefore extra precaution for the case
+                             // of l1<1 was found necessary.
+            C       = 0.0;
+            S       = 1.0;
+            ExitKey = 0;
+            i       = l;
+            while ((ExitKey==0) && (i<=k))  {
+              F       =  S*RV1[i];
+              RV1[i]  =  C*RV1[i];
+              if (fabs(F)+ANorm==ANorm)  ExitKey = 1;
+              else  {
+                G = W[i];
+                H = SrX2Y2(F,G);
+                W[i] = H;
+                C = G/H;
+                S = -F/H;
+                if (MatU)
+                  for (j=1;j<=M;j++)  {
+                    Y         =  U[j][l1];
+                    Z         =  U[j][i];
+                    U[j][l1]  =  Y*C+Z*S;
+                    U[j][i]   =  -Y*S+Z*C;
+                  }
+                i++;
+              }
+            }
+          }
+
+          //    Convergence  Checking
+
+          Z = W[k];
+          if (l!=k)  {
+            if (its>=ItnLimit)  {
+              RetCode = k;
+              return;
+            }
+            its++;
+            X  =  W[l];
+            Y  =  W[k1];
+            G  =  RV1[k1];
+            H  =  RV1[k];
+            F  =  ((Y-Z)*(Y+Z) + (G-H)*(G+H)) / ( 2.0*H*Y );
+            if (fabs(F)<=1.0)  GG = Sign(sqrt(F*F+1.0),F);
+                         else  GG = F*sqrt(1.0+1.0/F/F);
+            F  =  ((X-Z)*(X+Z) + H*(Y/(F+GG)-H)) / X;
+
+            //   Next  QR - Transformation
+
+            C  =  1.0;
+            S  =  1.0;
+            for (i1=l;i1<=k1;i1++)  {
+              i = i1+1;
+              G = RV1[i];
+              Y = W[i];
+              H = S*G;
+              G = C*G;
+              Z = SrX2Y2(F,H);
+              RV1[i1] = Z;
+              C = F/Z;
+              S = H/Z;
+              F = X*C+G*S;
+              G = -X*S+G*C;
+              H = Y*S;
+              Y = Y*C;
+              if (MatV)
+                for (j=1;j<=N;j++)  {
+                  X        = V[j][i1];
+                  Z        = V[j][i];
+                  V[j][i1] = X*C+Z*S;
+                  V[j][i]  = -X*S+Z*C;
+                }
+
+              Z = SrX2Y2(F,H);
+              W[i1] = Z;
+              if (Z!=0.0)  {
+                C = F/Z;
+                S = H/Z;
+              }
+              F = C*G+S*Y;
+              X = -S*G+C*Y;
+              if (MatU)
+                for (j=1;j<=M;j++)  {
+                  Y        = U[j][i1];
+                  Z        = U[j][i];
+                  U[j][i1] = Y*C+Z*S;
+                  U[j][i]  = -Y*S+Z*C;
+                }
+
+            }
+
+            RV1[l] = 0.0;
+            RV1[k] = F;
+            W[k]   = X;
+
+          } else if (Z<0.0)  {
+
+            W[k] = -Z;
+            if (MatV)
+              for (j=1;j<=N;j++)
+                V[j][k] = -V[j][k];
+          }
+
+        } while (l!=k);
+
+      }
+
+    }
+
+    //  -----------------------------------------------------
+
+    void  OrderSVD ( int M, int N, rmatrix U, rmatrix V,
+                     rvector W, bool MatU, bool MatV )  {
+
+    int       i,k,j;
+    realtype  P;
+
+      //  External loop of the re-ordering
+      for (i=1;i<N;i++)  {
+        k = i;
+        P = W[i];
+
+        //  Internal loop :  finding of the index of greatest
+        //  singular value over the remaining ones.
+        for (j=i+1;j<=N;j++)
+          if (W[j]>P)  {
+            k = j;
+            P = W[j];
+          }
+
+        if (k!=i)  {
+          //  Swapping the singular value
+          W[k] = W[i];
+          W[i] = P;
+          //  Swapping the U's columns (  if  needed  )
+          if (MatU)
+            for (j=1;j<=M;j++)  {
+              P       = U[j][i];
+              U[j][i] = U[j][k];
+              U[j][k] = P;
+            }
+          //  Swapping the V's columns ( if  needed )
+          if (MatV)
+            for (j=1;j<=N;j++)  {
+              P       = V[j][i];
+              V[j][i] = V[j][k];
+              V[j][k] = P;
+            }
+        }
+
+      }
+
+    }
+
+
+    /*
+
+    #ifndef  __STDIO_H
+    #include <stdio.h>
+    #endif
+
+    int main ( int argc, char ** argv, char ** env )  {
+    //  Test Jacobi
+    matrix   A,T,A1;
+    vector   Eigen,Aik;
+    realtype SR;
+    int      N,i,j,k,Signal;
+
+      N = 4;
+
+      GetMatrixMemory ( A,N,N,1,1 );
+      GetMatrixMemory ( T,N,N,1,1 );
+      GetMatrixMemory ( A1,N,N,1,1 );
+      GetVectorMemory ( Eigen,N,1 );
+      GetVectorMemory ( Aik  ,N,1 );
+
+      k = 1;
+      for (i=1;i<=N;i++)
+        for (j=i;j<=N;j++)  {
+          A[i][j]  = k++;
+          A[i][j] *= 1000.0;
+          A[j][i]  = A[i][j];
+        }
+
+      printf ( "  INITIAL MATRIX:\n" );
+      for (i=1;i<=N;i++)  {
+        for (j=1;j<=N;j++)
+          printf ( "  %10.4f",A[i][j] );
+        printf ( "\n" );
+      }
+
+      Jacobi (  N,A,T,Eigen,Aik,Signal );
+
+      printf ( "\n  EIGEN VALUES AND EIGEN VECTORS:\n" );
+      for (i=1;i<=N;i++)  {
+        printf ( "  %10.4f    ",Eigen[i] );
+        for (j=1;j<=N;j++)
+          printf ( "  %10.4f",T[j][i] );
+        printf ( "\n" );
+      }
+      printf ( "\n       measure: " );
+      for (i=1;i<=N;i++)  {
+        SR = 0.0;
+        for (j=1;j<=N;j++)
+          SR += T[j][i]*T[j][i];
+        printf ( "  %10.4f",sqrt(SR) );
+      }
+      printf ( "\n" );
+
+      for (i=1;i<=N;i++)
+        for (j=1;j<=N;j++)  {
+          A1[i][j] = 0.0;
+          for (k=1;k<=N;k++)
+            A1[i][j] += T[i][k]*Eigen[k]*T[j][k];
+        }
+
+      printf ( "\n  RESTORED INITIAL MATRIX:\n" );
+      for (i=1;i<=N;i++)  {
+        for (j=1;j<=N;j++)
+          printf ( "  %10.4f",A1[j][i] );
+        printf ( "\n" );
+      }
+
+      FreeMatrixMemory ( A,N,1,1 );
+      FreeMatrixMemory ( T,N,1,1 );
+      FreeMatrixMemory ( A1,N,1,1 );
+      FreeVectorMemory ( Eigen,1 );
+      FreeVectorMemory ( Aik  ,1 );
+
+
+    }
+
+    */
+
+  }
+
+}
diff --git a/mmdb2/mmdb_math_linalg.h b/mmdb2/mmdb_math_linalg.h
new file mode 100644
index 0000000..b646166
--- /dev/null
+++ b/mmdb2/mmdb_math_linalg.h
@@ -0,0 +1,236 @@
+//  $Id: mmdb_math_linalg.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  LinAlg  <interface>
+//       ~~~~~~~~~
+//  **** Project :  MMDB  ( MacroMolecular Data Base )
+//       ~~~~~~~~~
+//
+//  (C) E.Krissinel  2000-2013
+//
+//  =================================================================
+//
+//
+
+#ifndef __MMDB_MATH_LinAlg__
+#define __MMDB_MATH_LinAlg__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  ==========================  Jacobi  =============================
+
+
+    ///  Diagonalization of symmetric matrices A[1..N][1..N]
+    /// by the method of Jacobi.
+    extern void  Jacobi ( int     N,     //!< dimension of the matrix
+                          rmatrix A,     //!< matrix to diagonalize; the
+                                         /// lower triangle, except the
+                                         /// diagonal, will remain unchanged
+                          rmatrix T,     //!< eigenvectors placed as columns
+                          rvector Eigen, //!< vector of eigenvalues, orderd
+                                         /// by increasing
+                          rvector Aik,   //!< working array
+                          int &  Signal  //!< 0 <=> Ok, ItMax <=> iteration
+                                         /// limit exchausted.
+                        );
+
+
+    //  A5.5.2  :  Perturbed Cholesky Decomposition
+    extern void  PbCholDecomp ( int        N,
+                                rvector    HDiag,
+                                realtype   MaxOff,
+                                realtype   MachEps,
+                                rmatrix    L,
+                                realtype & MaxAdd );
+
+    //  A3.2.3a  :  Cholesky's   L - Solution  of
+    //              L*Y  =  B  ( given  B )
+    extern void  LSolve ( int N, rmatrix L, rvector B, rvector Y );
+
+    //  A3.2.3b  :  Cholesky's   LT - Solution  of
+    //              LT*X  =  Y  ( given  Y )
+    extern void  LTSolve ( int N, rmatrix L, rvector Y, rvector X );
+
+    //  A3.2.3   :  Solution of the equation    L*LT*S = G
+    //              by the  Cholesky's  method
+    extern void  ChSolve ( int N, rmatrix L, rvector G, rvector S );
+
+
+    //  ----------------------------------------------------
+
+    extern void  FastInverse (  int N, rmatrix A, ivector J0,
+    //#D                          realtype &  Det,
+                                int & Signal );
+    //
+    //      13.09.90  <--  Last Modification Date
+    //                    ------------------------
+    //
+    // ================================================
+    //
+    //        Fast Inversion of the matrix  A
+    //      by the method of  GAUSS - JORDAN  .
+    //
+    // ------------------------------------------------
+    //
+    //          Input  parameters  are  :
+    //
+    //     N   -   dimension of the matrix
+    //     A   -   the matrix [1..N][1..N] to be inverted.
+    // ------------------------------------------------
+    //
+    //     J0  -   integer vector [1..N] for temporal storage
+    //
+    // ------------------------------------------------
+    //
+    //          Output parameters  are  :
+    //
+    //     A   -   the inverted matrix
+    //     Signal - the error key :
+    //            = 0   <=>   O'K
+    //             else
+    //            degeneration was found, and
+    //            the rang of matrix is  Signal-1.
+    //
+    //        Variable  Det  may return the determinant
+    //     of matrix A.  To obtain it, remove all comments
+    //     of form  //#D.
+    //
+    // ================================================
+
+
+    //  ----------------------------------------------------
+
+    extern void  SVD ( int    NA,  int     M,    int N,
+                       rmatrix A,  rmatrix U,    rmatrix V,
+                       rvector W,  rvector RV1,
+                       bool MatU,  bool   MatV,
+                       int & RetCode );
+    //
+    //      13.12.01  <--  Last Modification Date
+    //                    ------------------------
+    //
+    // ================================================
+    //
+    //         The    Singular Value Decomposition
+    //    of the matrix  A  by the algorithm from
+    //      G.Forsait, M.Malkolm, K.Mouler.  Numerical
+    //    methods of mathematical calculations //
+    //    M., Mir, 1980.
+    //
+    //         Matrix  A  is represented as
+    //
+    //         A  =  U * W * VT
+    //
+    // ------------------------------------------------
+    //
+    //  All dimensions are indexed from 1 on.
+    //
+    // ------------------------------------------------
+    //
+    //         Input  parameters:
+    //
+    //     NA  -   number of lines in A. NA may be
+    //           equal to M or N  only.  If NA=M
+    //           then usual SVD will be made. If MA=N
+    //           then matrix A is transposed before
+    //           the decomposition, and the meaning of
+    //           output parameters  U  and  V  is
+    //           swapped (U accepts VT and VT accepts U).
+    //           In other words, matrix  A  has physical
+    //           dimension of  M x N , same as U and V;
+    //           however the logical dimension of it
+    //           remains that of  N x M .
+    //     M   -   number of lines in  U
+    //     N   -   number of columns in  U,V and length
+    //           of  W,RV1 .  Always provide  M >= N  !
+    //     A   -   matrix [1..M][1..N] or [1..N][1..M]
+    //           to be decomposed. The matrix does not
+    //           change,  and it may coincide with  U  or
+    //           V, if NA=M (in which case  A  does change)
+    //     MatU -  compute  U , if set True
+    //     MatV -  compute  V , if set True
+    //     RV1  -  temporary array [1..N].
+    //     U    - should be always supplied as an array of
+    //            [1..M][1..N], M>=N .
+    //     V    - should be suuplied as an array of
+    //            [1..N][1..N] if MatV is True .
+    //
+    // ------------------------------------------------
+    //
+    //          Output parameters  are  :
+    //
+    //     W   -   N non-ordered singular values,
+    //           if  RetCode=0. If RetCode<>0, the
+    //           RetCode+1 ... N -th values are still
+    //           valid
+    //     U   -   matrix of right singular vectors
+    //           (arranged in columns),  corresponding
+    //           to the singular values in  W,  if
+    //           RetCode=0 and MatU is True.  If MatU
+    //           is False, U  is still used as a
+    //           temporary array. If RetCode<>0 then
+    //           the  RetCode+1 ... N -th vectors
+    //           are  valid
+    //     V   -   matrix of left singular vectors
+    //           (arranged in columns),  corresponding
+    //           to the singular values in  W,  if
+    //           RetCode=0 and MatV is True. If MatV
+    //           is False, V is not used and may be set
+    //           to NULL. If RetCode<>0 then the
+    //           RetCode+1 ... N -th vectors are valid
+    //     RetCode - the error key :
+    //            = 0   <=>   O'K
+    //              else
+    //            = k, if the k-th singular value
+    //                 was not computed after 30 iterations.
+    //
+    // ------------------------------------------------
+    //
+    //          Key  Variables  are  :
+    //
+    //     ItnLimit  -  the limit for iterations
+    //
+    //     This routine does not use any machine-dependent
+    //  constants.
+    //
+    // ================================================
+    //
+    //
+
+    extern void  OrderSVD ( int M, int N, rmatrix U, rmatrix V,
+                            rvector W, bool MatU, bool MatV );
+
+
+  }
+}
+
+#endif
diff --git a/mmdb2/mmdb_math_rand.cpp b/mmdb2/mmdb_math_rand.cpp
new file mode 100644
index 0000000..1122c89
--- /dev/null
+++ b/mmdb2/mmdb_math_rand.cpp
@@ -0,0 +1,241 @@
+//  $Id: mmdb_math_rand.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  Rand  <implementation>
+//       ~~~~~~~~~
+//  **** Classes :  RandomNumber ( random number generator )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel  1997-2013
+//
+//  =================================================================
+//
+
+#include <math.h>
+
+#include "mmdb_math_rand.h"
+
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  ===================  RandomNumber  ==========================
+
+    RandomNumber::RandomNumber ( long IJ, long KL ) {
+      Init ( IJ,KL );
+    }
+
+    void  RandomNumber::Init ( long IJ, long KL )  {
+    long      i,j,k,l,m, ii,jj;
+    realtype  s,t;
+
+      iset = 0;
+      gset = 0.0;
+
+      if ((IJ<0) || (IJ>_RN_MAX_IJ) ||
+          (KL<0) || (KL>_RN_MAX_KL))  return;
+
+      i = mod(IJ/177,177) + 2;
+      j = mod(IJ,177)     + 2;
+      k = mod(KL/169,178) + 1;
+      l = mod(KL,169);
+
+      for (ii=0;ii<97;ii++)  {
+        s = 0.0;
+        t = 0.5;
+        for (jj=1;jj<=24;jj++)  {
+          m = mod(mod(i*j,179)*k,179);
+          i = j;
+          j = k;
+          k = m;
+          l = mod(53*l+1,169);
+          if (mod(l*m,64)>=32)  s += t;
+          t *= 0.5;
+        }
+        U[ii] = s;
+      }
+
+      C  = 362436.0   / 16777216.0;
+      CD = 7654321.0  / 16777216.0;
+      CM = 16777213.0 / 16777216.0;
+
+      I97 = 96;
+      J97 = 32;
+
+    }
+
+
+    // uniform [0..1] random number generator
+    realtype RandomNumber::random()  {
+    realtype uni;
+
+      uni = U[I97] - U[J97];
+      if (uni<0.0) uni += 1.0;
+      U[I97] = uni;
+      I97--;
+      if (I97<0) I97 = 96;
+      J97--;
+      if (J97<0) J97 = 96;
+      C -= CD;
+      if (C<0.0)  C += CM;
+      uni -= C;
+      if (uni<0.0) uni += 1.0;
+
+      return uni;
+
+    }
+
+
+    // uniform [-1..1] random number generator
+    realtype RandomNumber::srandom()  {
+    realtype uni;
+
+      uni = U[I97] - U[J97];
+      if (uni<0.0) uni += 1.0;
+      U[I97] = uni;
+      I97--;
+      if (I97<0) I97 = 96;
+      J97--;
+      if (J97<0) J97 = 96;
+      C -= CD;
+      if (C<0.0)  C += CM;
+      uni -= C;
+      if (uni<0.0) uni += 1.0;
+
+      return 2.0*uni - 1.0;
+
+    }
+
+    // gaussian random numbers
+    realtype RandomNumber::gauss_rnd()  {
+    realtype  v1,v2,r,fac;
+      if (iset==0)  {
+        do {
+          v1 = srandom();
+          v2 = srandom();
+          r  = v1*v1 + v2*v2;
+        } while ((r>=1.0) || (r==0.0));
+        fac  = sqrt(-2.0*log(r)/r);
+        gset = v1*fac;
+        iset = 1;
+        return v2*fac;
+      } else  {
+        iset  = 0;
+        return gset;
+      }
+    }
+
+    void  RandomNumber::write ( io::RFile f )  {
+    int Version=1;
+      f.WriteFile ( &Version,sizeof(Version) );
+      f.WriteFile ( &I97    ,sizeof(I97)     );
+      f.WriteFile ( &J97    ,sizeof(J97)     );
+      f.WriteFile ( U       ,sizeof(U)       );
+      f.WriteFile ( &C      ,sizeof(C)       );
+      f.WriteFile ( &CD     ,sizeof(CD)      );
+      f.WriteFile ( &CM     ,sizeof(CM)      );
+      f.WriteFile ( &gset   ,sizeof(gset)    );
+      f.WriteFile ( &iset   ,sizeof(iset)    );
+    }
+
+    void  RandomNumber::read ( io::RFile f )  {
+    int Version;
+      f.ReadFile ( &Version,sizeof(Version) );
+      f.ReadFile ( &I97    ,sizeof(I97)     );
+      f.ReadFile ( &J97    ,sizeof(J97)     );
+      f.ReadFile ( U       ,sizeof(U)       );
+      f.ReadFile ( &C      ,sizeof(C)       );
+      f.ReadFile ( &CD     ,sizeof(CD)      );
+      f.ReadFile ( &CM     ,sizeof(CM)      );
+      f.ReadFile ( &gset   ,sizeof(gset)    );
+      f.ReadFile ( &iset   ,sizeof(iset)    );
+    }
+
+
+  }  // namespace math
+
+}  // namespace mmdb
+
+
+/*
+
+static int m1       = 259200;
+static int ia1      = 7141;
+static int ic1      = 54773;
+static realtype rm1 = 1.0/259200.0;
+
+static int m2       = 134456;
+static int ia2      = 8121;
+static int ic2      = 28411;
+static realtype rm2 = 1.0/134456.0;
+
+static int m3       = 243000;
+static int ia3      = 4561;
+static int ic3      = 51349;
+
+static int ix1 = 0;
+static int ix2 = 0;
+static int ix3 = 0;
+
+static realtype R[97];
+
+void  randomize ( int iseed )  {
+int  j;
+  RndInit = True;
+  ix1 = mod(ic1-iseed,m1);
+  ix1 = mod(ia1*ix1+ic1,m1);
+  ix2 = mod(ix1,m2);
+  ix1 = mod(ia1*ix1+ic1,m1);
+  ix3 = mod(ix1,m3);
+  for (j=0;j<97;j++)  {
+    ix1  = mod(ia1*ix1+ic1,m1);
+    ix2  = mod(ia2*ix2+ic2,m2);
+    R[j] = (ix1+ix2*rm2)*rm1;
+  }
+}
+
+realtype  rand()  {
+int      j;
+realtype rnd;
+  if (!RndInit)  randomize();
+  ix1 = mod(ia1*ix1+ic1,m1);
+  ix2 = mod(ia2*ix2+ic2,m2);
+  ix3 = mod(ia3*ix3+ic3,m3);
+  j = 1 + (97*ix3)/m3;
+  j = IMax(j,1);
+  j = IMin(j,97);
+  rnd = R[j-1];
+  R[j] = (ix1+ix2*rm2)*rm1;
+  return rnd;
+}
+*/
+
+//  ===========================================================
+
+// End of  Random_N
diff --git a/mmdb/random_n.h b/mmdb2/mmdb_math_rand.h
old mode 100755
new mode 100644
similarity index 51%
rename from mmdb/random_n.h
rename to mmdb2/mmdb_math_rand.h
index 3a15a92..8fde4f1
--- a/mmdb/random_n.h
+++ b/mmdb2/mmdb_math_rand.h
@@ -1,18 +1,18 @@
-//  $Id: random_n.h,v 1.19 2012/01/26 17:52:21 ekr Exp $
+//  $Id: mmdb_math_rand.h $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
 //   functionality in protein crystallography applications.
 //
-//   Copyright (C) Eugene Krissinel 2000-2008.
+//   Copyright (C) Eugene Krissinel 2000-2013.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -22,50 +22,59 @@
 //
 //  =================================================================
 //
-//    05.02.03   <--  Date of Last Modification.
+//    12.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
-//  **** Module  :  Random_N  <interface>
+//  **** Module  :  Rand  <interface>
 //       ~~~~~~~~~
-//  **** Classes :  CRandomNumber ( random number generator )
+//  **** Classes :  RandomNumber ( random number generator )
 //       ~~~~~~~~~
 //
-//   (C) E. Krissinel'  1997-2008
+//   (C) E. Krissinel  1997-2013
 //
 //  =================================================================
 //
 
-#ifndef  __Random_N__
-#define  __Random_N__
+#ifndef  __MMDB_MATH_Rand__
+#define  __MMDB_MATH_Rand__
 
-#ifndef  __File__
-#include "file_.h"
-#endif
+#include "mmdb_io_file.h"
+
+namespace mmdb  {
+
+  namespace math  {
+
+    //  -------------------------------------------------------------
+
+    enum RN_MAX_SEED  {
+      _RN_MAX_IJ = 31328,
+      _RN_MAX_KL = 30081
+    };
+
+    DefineClass(RandomNumber);
 
+    class RandomNumber  {
+      public :
+        RandomNumber ( long IJ=0, long KL=0 );
+        void  Init   ( long IJ=0, long KL=0 );
+        realtype gauss_rnd(); //!< Gaussian random numbers
+        realtype random   (); //!< Uniform [0..1] random number generator
+        realtype srandom  (); //!< Uniform [-1..1] random number generator
 
-//  -------------------------------------------------------------
+        void  read  ( io::RFile f );
+        void  write ( io::RFile f );
 
-#define _RN_MAX_IJ 31328
-#define _RN_MAX_KL 30081
+      protected :
+        long     I97,J97;
+        realtype U[97],C,CD,CM;
+        realtype gset;
+        long     iset;
 
-DefineClass(CRandomNumber);
+    };
 
-class CRandomNumber  {
-  public :
-    CRandomNumber ( long IJ=0, long KL=0 );
-    void  Init    ( long IJ=0, long KL=0 );
-    realtype gauss_rnd();  //  Gaussian random numbers
-    realtype random   ();  //  Uniform [0..1] random number generator
-    realtype srandom  ();  //  Uniform [-1..1] random number generator
+  }  // namespace math
 
-    void  read    ( RCFile f );
-    void  write   ( RCFile f );
-  protected :
-    long     I97,J97;
-    realtype U[97],C,CD,CM;
-    realtype gset;
-    long     iset;
-};
+}  // namespace mmdb
 
 #endif
diff --git a/mmdb2/mmdb_mattype.cpp b/mmdb2/mmdb_mattype.cpp
new file mode 100644
index 0000000..83e4a59
--- /dev/null
+++ b/mmdb2/mmdb_mattype.cpp
@@ -0,0 +1,2087 @@
+//  $Id: mmdb_mattype.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    10.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MatType_ <implementation>
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits>
+#include <stdio.h>
+
+#include "mmdb_mattype.h"
+
+
+namespace mmdb {
+
+  // -------------------------------------------------------
+
+  realtype  MachEps;
+  realtype  floatMachEps;
+  realtype  LnMaxReal;
+  realtype  LnMinReal;
+  static realtype LnMaxRealExp;
+  static realtype LnMinRealExp;
+
+  //  Initialization. Some C++ enviroments do not do the
+  // following statements automatically, therefore it is
+  // always advisable to call InitMatType() explicitely
+  // from the top of main(). See body of InitMatType()
+  // in the very end of this file. It is completely
+  // harmless and cheap to call InitMatType() multiple
+  // times.
+
+  static bool MatTypeInit = InitMatType();
+
+
+  // -------------------------------------------------------
+
+
+#ifdef _WIN32
+  pstr strcasestr ( pstr s1, cpstr s2 )  {
+  pstr l1,l2,l;
+    l1 = NULL;
+    l2 = NULL;
+    CreateCopy ( l1,s1 );
+    CreateCopy ( l2,s2 );
+    LowerCase  ( l1 );
+    LowerCase  ( l2 );
+    l = strstr ( l1,l2 );
+    if (l)
+      l = s1 + (l-l1);
+    delete[] l1;
+    delete[] l2;
+    return l;
+  }
+#endif
+
+
+  // -------------------------------------------------------
+  bool GetVectorMemory  ( rvector & V, word N, word Shift )  {
+    V = new realtype[N];
+    if (V!=NULL)  V = V - Shift;  // shift for abovementioned enumeration
+    return  (V!=NULL);
+  }
+
+  bool GetVectorMemory ( ivector & I, word N, word Shift )  {
+    I = new int[N];
+    if (I!=NULL)  I = I - Shift;   // shift for abovementioned enumeration
+    return  (I!=NULL);
+  }
+
+  bool GetVectorMemory ( wvector & W, word N, word Shift )  {
+    W = new word[N];
+    if (W!=NULL)  W = W - Shift;   // shift for abovementioned enumeration
+    return  (W!=NULL);
+  }
+
+  bool GetVectorMemory ( bvector & B, word N, word Shift )  {
+    B = new byte[N];
+    if (B!=NULL)  B = B - Shift;   // shift for abovementioned enumeration
+    return  (B!=NULL);
+  }
+
+  bool GetVectorMemory ( ovector & O, word N, word Shift )  {
+    O = new bool[N];
+    if (O!=NULL)  O = O - Shift;   // shift for abovementioned enumeration
+    return  (O!=NULL);
+  }
+
+  bool GetVectorMemory ( lvector & L, word N, word Shift )  {
+    L = new long[N];
+    if (L!=NULL)  L = L - Shift;   // shift for abovementioned enumeration
+    return  (L!=NULL);
+  }
+
+  bool GetVectorMemory ( lwvector & L, word N, word Shift )  {
+    L = new lword[N];
+    if (L!=NULL)  L = L - Shift;   // shift for abovementioned enumeration
+    return  (L!=NULL);
+  }
+
+  bool GetVectorMemory ( psvector & P, word N, word Shift )  {
+    P = new pstr[N];
+    if (P!=NULL)  P = P - Shift;   // shift for abovementioned enumeration
+    return  (P!=NULL);
+  }
+
+  void FreeVectorMemory  ( rvector & V, word Shift ) {
+    if (V!=NULL)  {
+      V = V + Shift;  //  back shift for the work of heap system
+      delete[] V;
+      V = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( ivector & I, word Shift )  {
+    if (I!=NULL)  {
+      I = I + Shift;  //  back shift for the work of heap system
+      delete[] I;
+      I = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( wvector & W, word Shift )  {
+    if (W!=NULL)  {
+      W = W + Shift;  //  back shift for the work of heap system
+      delete[] W;
+      W = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( bvector & B, word Shift )  {
+    if (B!=NULL)  {
+      B = B + Shift;  //  back shift for the work of heap system
+      delete[] B;
+      B = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( ovector & O, word Shift )  {
+    if (O!=NULL)  {
+      O = O + Shift;  //  back shift for the work of heap system
+      delete[] O;
+      O = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( lvector & L, word Shift )  {
+    if (L!=NULL)  {
+      L = L + Shift;  //  back shift for the work of heap system
+      delete[] L;
+      L = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( lwvector & L, word Shift )  {
+    if (L!=NULL)  {
+      L = L + Shift;  //  back shift for the work of heap system
+      delete[] L;
+      L = NULL;
+    }
+  }
+
+  void FreeVectorMemory ( psvector & P, word Shift )  {
+    if (P!=NULL)  {
+      P = P + Shift;  //  back shift for the work of heap system
+      delete[] P;
+      P = NULL;
+    }
+  }
+
+  bool GetMatrixMemory  ( rmatrix & A, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    A = new rvector[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( A[i],M,ShiftM );
+      if (A[N-1]==NULL)
+            FreeMatrixMemory ( A,N,0,ShiftM );
+      else  A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrixMemory  ( imatrix & A, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    A = new ivector[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( A[i],M,ShiftM );
+      if (A[N-1]==NULL)
+            FreeMatrixMemory ( A,N,0,ShiftM );
+      else  A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrixMemory  ( wmatrix & W, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    W = new wvector[N];
+    if (W!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( W[i],M,ShiftM );
+      if (W[N-1]==NULL)
+            FreeMatrixMemory ( W,N,0,ShiftM );
+      else  W = W - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (W!=NULL);
+  }
+
+  bool GetMatrixMemory  ( bmatrix & B, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    B = new bvector[N];
+    if (B!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( B[i],M,ShiftM );
+      if (B[N-1]==NULL)
+            FreeMatrixMemory ( B,N,0,ShiftM );
+      else  B = B - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (B!=NULL);
+  }
+
+  bool GetMatrixMemory  ( omatrix & O, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    O = new ovector[N];
+    if (O!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( O[i],M,ShiftM );
+      if (O[N-1]==NULL)
+            FreeMatrixMemory ( O,N,0,ShiftM );
+      else  O = O - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (O!=NULL);
+  }
+
+  bool GetMatrixMemory  ( lmatrix & L, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    L = new lvector[N];
+    if (L!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( L[i],M,ShiftM );
+      if (L[N-1]==NULL)
+            FreeMatrixMemory ( L,N,0,ShiftM );
+      else  L = L - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (L!=NULL);
+  }
+
+  bool GetMatrixMemory  ( lwmatrix & L, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    L = new lwvector[N];
+    if (L!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( L[i],M,ShiftM );
+      if (L[N-1]==NULL)
+            FreeMatrixMemory ( L,N,0,ShiftM );
+      else  L = L - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (L!=NULL);
+  }
+
+  bool GetMatrixMemory  ( psmatrix & P, word N, word M,
+                          word ShiftN, word ShiftM ) {
+    P = new psvector[N];
+    if (P!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetVectorMemory ( P[i],M,ShiftM );
+      if (P[N-1]==NULL)
+            FreeMatrixMemory ( P,N,0,ShiftM );
+      else  P = P - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (P!=NULL);
+  }
+
+  void FreeMatrixMemory  ( rmatrix & A, word N,
+                           word ShiftN, word ShiftM ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( A[i],ShiftM );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( imatrix & A,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( A[i],ShiftM );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( wmatrix & W,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (W!=NULL)  {
+      W = W + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( W[i],ShiftM );
+      delete[] W;
+      W = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( bmatrix & B,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (B!=NULL)  {
+      B = B + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( B[i],ShiftM );
+      delete[] B;
+      B = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( omatrix & O,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (O!=NULL)  {
+      O = O + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( O[i],ShiftM );
+      delete[] O;
+      O = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( lmatrix & L,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (L!=NULL)  {
+      L = L + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( L[i],ShiftM );
+      delete[] L;
+      L = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( lwmatrix & L,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (L!=NULL)  {
+      L = L + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( L[i],ShiftM );
+      delete[] L;
+      L = NULL;
+    }
+  }
+
+  void FreeMatrixMemory  ( psmatrix & P,  word N,
+                           word ShiftN, word ShiftM ) {
+    if (P!=NULL)  {
+      P = P + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeVectorMemory ( P[i],ShiftM );
+      delete[] P;
+      P = NULL;
+    }
+  }
+
+  bool GetMatrix3Memory ( rmatrix3 & A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new rmatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( imatrix3 & A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new imatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( wmatrix3 & A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new wmatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( bmatrix3 &A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new bmatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( omatrix3 &A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new omatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( lmatrix3 & A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new lmatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( lwmatrix3 & A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new lwmatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  bool GetMatrix3Memory ( psmatrix3 & A, word N, word M, word K,
+                          word ShiftN, word ShiftM, word ShiftK ) {
+    A = new psmatrix[N];
+    if (A!=NULL)  {
+      for (word i=0;i<N;i++)
+        GetMatrixMemory ( A[i],M,K,ShiftM,ShiftK );
+      if (A[N-1]==NULL)
+        FreeMatrix3Memory ( A,N,M,0,ShiftM,ShiftK );
+      else
+        A = A - ShiftN;  //  shift for the enumeration with 1
+    }
+    return  (A!=NULL);
+  }
+
+  void FreeMatrix3Memory  ( rmatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( imatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( wmatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( bmatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+        A = A + ShiftN;  //  back shift for the work of heap system
+        for (word i=0;i<N;i++)
+            FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+        delete[] A;
+        A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( omatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+        A = A + ShiftN;  //  back shift for the work of heap system
+        for (word i=0;i<N;i++)
+            FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+        delete[] A;
+        A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( lmatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+        A = A + ShiftN;  //  back shift for the work of heap system
+        for (word i=0;i<N;i++)
+          FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+        delete[] A;
+        A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( lwmatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  void FreeMatrix3Memory  ( psmatrix3 & A, word N,      word M,
+                            word ShiftN, word ShiftM, word ShiftK ) {
+    if (A!=NULL)  {
+      A = A + ShiftN;  //  back shift for the work of heap system
+      for (word i=0;i<N;i++)
+        FreeMatrixMemory ( A[i],M,ShiftM,ShiftK );
+      delete[] A;
+      A = NULL;
+    }
+  }
+
+  realtype  MachinEps ()  {
+  //  A1.3.1   :  Calculation of the machine's epsilon
+  /*
+  realtype  rMachEps = 1.0;
+    do
+      rMachEps /= 2.0;
+    while ((1.0+rMachEps)!=1.0);
+    return  2.0*rMachEps;
+  */
+    return std::numeric_limits<realtype>::epsilon();
+  }
+
+  realtype  floatMachinEps()  {
+  //  A1.3.1   :  Calculation of the machine's epsilon
+  /*
+  float fMachEps = 1.0;
+    do
+      fMachEps /= 2.0;
+    while (float(1.0+fMachEps)!=1.0);
+    return  2.0*fMachEps;
+  */
+    return std::numeric_limits<float>::epsilon();
+  }
+
+  realtype  frac ( realtype R )  {
+  realtype  i;
+    return  modf ( R,&i );
+  }
+
+  long  mod ( long x, long y )  {
+  long k=x/y;
+  long f=x-k*y;
+    while (f<0)  f += y;
+    return f;
+  }
+
+  realtype  Pow ( realtype X, int y )  {
+  int       m,l;
+  realtype  B;
+    if (y==0)  return  1.0;
+    else if (X!=0.0)  {
+      B = X;
+      m = 1;
+      if (y>=0)  l = y;
+           else  l = -y;
+      while (m++<l)  B = B*X;
+      if (y>=0)  return  B;
+           else  return  1.0/B;
+    } else  return  0.0;
+  }
+
+  realtype  Pow1 ( realtype X, realtype Y )  {
+  int  k = mround(Y);
+    if (fabs(k-Y)<=100.0*MachEps)  return Pow(X,k);
+    if (X==0.0)  return 0.0;
+           else  return pow(X,Y);
+  }
+
+  realtype  Exp ( realtype X )  {
+  //realtype  X1 = X;
+  //realtype  B  = 1.0;
+    if   (X>=LnMaxRealExp)     return  MaxReal;
+    else if (X<=LnMinRealExp)  return  0.0;
+    else  {
+      return  exp(X);
+      /*
+      while (X1>LnMaxReal)  {
+        X1 -= LnMaxReal;
+        B  *= MaxExponent;
+      }
+      while (X1<-LnMaxReal)  {
+        X1 += LnMaxReal;
+        B  /= MaxExponent;
+      }
+      return B*exp(X1);
+      */
+    }
+  }
+
+  bool Odd ( int i )  {
+    return  (i & 1);
+  }
+
+
+  //  ----------------------------------------------------
+
+  long  HexValL ( cpstr S )  {
+  char  C;
+  int   i;
+  long  z=0;
+    for (i=0;S[i];i++)  {
+      z <<= 4;
+      C = (char)toupper(S[i]);
+      if (isdigit(C))  z += S[i]-'0';
+                 else  z += C-'A'+10;
+    }
+    return  z;
+  }
+
+
+  //  ----------------------------------------------------
+
+  long  OctValL ( cpstr S )  {
+  int   i;
+  long  z=0;
+    for (i=0;S[i];i++)  {
+      z <<= 3;
+      z += S[i]-'0';
+    }
+    return  z;
+  }
+
+
+  //  ----------------------------------------------------
+
+  long  BinValL ( cpstr S )  {
+  int   i;
+  long  z=0;
+    for (i=0;S[i];i++)  {
+      z <<= 1;
+      z += S[i]-'0';
+    }
+    return  z;
+  }
+
+  pstr  BinValS ( long L, pstr S )  {
+  int   i;
+  long  z;
+    z = long(1) << (8*sizeof(long)-1);
+    for (i=0;i<8*(int)sizeof(long);i++)  {
+      if (L & z)  S[i] = '1';
+            else  S[i] = '0';
+      z >>= 1;
+    }
+    S[8*sizeof(long)] = char(0);
+    return  S;
+  }
+
+
+
+  //  ----------------------------------------------------
+
+  pstr ParamStr ( pstr D, cpstr S, realtype V, int M, cpstr S1 )  {
+  char  VS[30];
+    strcat  ( D,S );
+    sprintf ( VS,"%-.*g",M,V );
+    strcat  ( D,VS );
+    return strcat(D,S1);
+  }
+
+
+  pstr ParamStr ( pstr D,  cpstr S, realtype V, int M,
+                  cpstr S1, realtype V2, int M2, cpstr S2 )  {
+  char  VS[30];
+    ParamStr ( D,S,V,M,S1 );
+    sprintf  ( VS,"%-.*g",M2,V2 );
+    strcat   ( D,VS );
+    return strcat(D,S2);
+  }
+
+
+  pstr CreateCopy ( pstr & Dest, cpstr Source )  {
+    if (Dest)  delete[] Dest;
+    if (Source)   {
+      Dest = new char[strlen(Source)+1];
+      strcpy ( Dest,Source );
+    } else
+      Dest = NULL;
+    return Dest;
+  }
+
+  pstr CreateCopy_n ( pstr & Dest, cpstr Source, int n )  {
+  int l;
+    if (Dest)  delete[] Dest;
+    if (Source)   {
+      l    = IMin ( strlen(Source),n );
+      Dest = new char[l+1];
+      strncpy ( Dest,Source,l );
+      Dest[l] = char(0);
+    } else
+      Dest = NULL;
+    return Dest;
+  }
+
+  pstr CreateCopCat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2,
+                      cpstr Source3, cpstr Source4,
+                      cpstr Source5 )  {
+    if (Dest) {
+      delete[] Dest;
+      Dest = NULL;
+    }
+    return CreateConcat ( Dest,Source1,Source2,Source3,Source4,Source5 );
+  }
+
+  pstr CreateCopCat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2,
+                      cpstr Source3, cpstr Source4 )  {
+    if (Dest) {
+      delete[] Dest;
+      Dest = NULL;
+    }
+    return CreateConcat ( Dest,Source1,Source2,Source3,Source4 );
+  }
+
+  pstr CreateCopCat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2,
+                      cpstr Source3 )  {
+    if (Dest) {
+      delete[] Dest;
+      Dest = NULL;
+    }
+    return CreateConcat ( Dest,Source1,Source2,Source3 );
+  }
+
+  pstr CreateCopCat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2 )  {
+    if (Dest) {
+      delete[] Dest;
+      Dest = NULL;
+    }
+    return CreateConcat ( Dest,Source1,Source2 );
+  }
+
+
+  pstr CreateConcat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2,
+                      cpstr Source3, cpstr Source4,
+                      cpstr Source5 )  {
+  pstr S;
+  int  ld,ls;
+    if (Dest) ld = strlen(Dest);
+         else ld = 0;
+    ls = 0;
+    if (Source1)  ls += strlen(Source1);
+    if (Source2)  ls += strlen(Source2);
+    if (Source3)  ls += strlen(Source3);
+    if (Source4)  ls += strlen(Source4);
+    if (Source5)  ls += strlen(Source5);
+    if (ls>0)  {
+      S = new char[ls+ld+1];
+      if (Dest)  {
+        strcpy ( S,Dest );
+        delete[] Dest;
+      } else
+        S[0] = char(0);
+      if (Source1) strcat ( S,Source1 );
+      if (Source2) strcat ( S,Source2 );
+      if (Source3) strcat ( S,Source3 );
+      if (Source4) strcat ( S,Source4 );
+      if (Source5) strcat ( S,Source5 );
+      Dest = S;
+    }
+    return Dest;
+  }
+
+
+  pstr CreateConcat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2,
+                      cpstr Source3, cpstr Source4 )  {
+  pstr S;
+  int  ld,ls;
+    if (Dest) ld = strlen(Dest);
+         else ld = 0;
+    ls = 0;
+    if (Source1)  ls += strlen(Source1);
+    if (Source2)  ls += strlen(Source2);
+    if (Source3)  ls += strlen(Source3);
+    if (Source4)  ls += strlen(Source4);
+    if (ls>0)  {
+      S = new char[ls+ld+1];
+      if (Dest)  {
+        strcpy ( S,Dest );
+        delete[] Dest;
+      } else
+        S[0] = char(0);
+      if (Source1) strcat ( S,Source1 );
+      if (Source2) strcat ( S,Source2 );
+      if (Source3) strcat ( S,Source3 );
+      if (Source4) strcat ( S,Source4 );
+      Dest = S;
+    }
+    return Dest;
+  }
+
+
+  pstr CreateConcat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2,
+                      cpstr Source3 )  {
+  pstr S;
+  int  ld,ls;
+    if (Dest) ld = strlen(Dest);
+         else ld = 0;
+    ls = 0;
+    if (Source1)  ls += strlen(Source1);
+    if (Source2)  ls += strlen(Source2);
+    if (Source3)  ls += strlen(Source3);
+    if (ls>0)  {
+      S = new char[ls+ld+1];
+      if (Dest)  {
+        strcpy ( S,Dest );
+        delete[] Dest;
+      } else
+        S[0] = char(0);
+      if (Source1) strcat ( S,Source1 );
+      if (Source2) strcat ( S,Source2 );
+      if (Source3) strcat ( S,Source3 );
+      Dest = S;
+    }
+    return Dest;
+  }
+
+  pstr CreateConcat ( pstr & Dest,
+                      cpstr Source1, cpstr Source2 )  {
+  pstr S;
+  int  ld,ls;
+    if (Dest) ld = strlen(Dest);
+         else ld = 0;
+    ls = 0;
+    if (Source1)  ls += strlen(Source1);
+    if (Source2)  ls += strlen(Source2);
+    if (ls>0)  {
+      S = new char[ls+ld+1];
+      if (Dest)  {
+        strcpy ( S,Dest );
+        delete[] Dest;
+      } else
+        S[0] = char(0);
+      if (Source1) strcat ( S,Source1 );
+      if (Source2) strcat ( S,Source2 );
+      Dest = S;
+    }
+    return Dest;
+  }
+
+  pstr CreateConcat ( pstr & Dest, cpstr Source )  {
+  pstr S;
+  int  ld,ls;
+    if (Dest)   ld = strlen(Dest);
+         else   ld = 0;
+    if (Source) ls = strlen(Source);
+           else ls = 0;
+    if (ls>0)  {
+      S = new char[ls+ld+1];
+      if (Dest)  {
+        strcpy ( S,Dest );
+        delete[] Dest;
+      } else
+        S[0] = char(0);
+      strcat ( S,Source );
+      Dest = S;
+    }
+    return Dest;
+  }
+
+
+  pstr LastOccurence ( cpstr S, char c )  {
+  pstr P=(pstr)S;
+  pstr R=NULL;
+    while (*P)  {
+      if (*P==c)  R = P;
+      P++;
+    }
+    return R;
+  }
+
+
+  pstr FirstOccurence ( cpstr S, char c )  {
+  pstr P=(pstr)S;
+    while (*P)  {
+      if (*P==c)  return P;
+      P++;
+    }
+    return NULL;
+  }
+
+  int indexOf ( cpstr S, char c )  {
+  int i=0;
+    while (S[i])  {
+      if (S[i]==c)  return i;
+      i++;
+    }
+    return -1;
+  }
+
+  pstr FirstOccurence ( cpstr S, int Slen, cpstr Q, int Qlen )  {
+  int i,j,k,l;
+    l = Slen-Qlen;
+    for (i=0;i<=l;i++)  {
+      j = 0;
+      k = i;
+      while (j<Qlen)
+        if (S[k++]!=Q[j]) break;
+                     else j++;
+      if (j>=Qlen)  return  pstr(&(S[i]));
+    }
+    return NULL;
+  }
+
+  int indexOf ( cpstr S, int Slen, cpstr Q, int Qlen )  {
+  int i,j,k,l;
+    l = Slen-Qlen;
+    for (i=0;i<=l;i++)  {
+      j = 0;
+      k = i;
+      while (j<Qlen)
+        if (S[k++]!=Q[j]) break;
+                     else j++;
+      if (j>=Qlen)  return  i;
+    }
+    return -1;
+  }
+
+
+  pstr LowerCase ( pstr s )  {
+  pstr p=s;
+    while (*p)  {
+      *p = char(tolower(int(*p)));
+      p++;
+    }
+    return s;
+  }
+
+  pstr UpperCase ( pstr s )  {
+  pstr p=s;
+    while (*p)  {
+      *p = char(toupper(int(*p)));
+      p++;
+    }
+    return s;
+  }
+
+
+  void GetString ( pstr L, cpstr S, int M )  {
+  //  Copies first M characters of string S into string L,
+  // appending the terminating null. If S contains less
+  // then M characters, L will be padded with spaces.
+  int i,j;
+    i = 0;
+    j = 0;
+    while (S[i] && (i<M))
+      L[j++] = S[i++];
+    while (j<M)
+      L[j++] = ' ';
+    L[j] = char(0);
+  }
+
+
+  void GetStrTer ( pstr L, cpstr S, int n, int LMax, int SMax )  {
+  //   Copies at least n (or LMax if LMax<n) first symbols of
+  // string S into string L, then continues copying until first
+  // space or terminating null is found. If the terminating null
+  // is met among the first n characters or if SMax<n, the string
+  // L will be padded with spaces till the length of minimum of
+  // n and LMax and then terminated with the null.
+  //   SMax are buffer lengths of L and S, respectively. Even if
+  // no space is found, the last character in L will be the
+  // terminating null.
+  int i,k,lm1,msl,mnsl;
+    lm1  = LMax-1;
+    msl  = IMin(lm1,SMax);
+    mnsl = IMin(n,msl);
+    k    = 0;
+    for (i=0;i<mnsl;i++)
+      if (S[i])  L[k++] = S[i];
+           else  break;
+    if ((k>=SMax) || (!S[k]))  {
+      lm1 = IMin(n,lm1);
+      while (k<lm1)
+        L[k++] = ' ';
+    } else  {
+      lm1 = k;
+      for (i=lm1;i<msl;i++)
+        if (S[i] && (S[i]!=' '))  L[k++] = S[i];
+                            else  break;
+    }
+    L[k] = char(0);
+  }
+
+
+  void GetStrTerWin32File ( pstr L, cpstr S, int n, int LMax,
+                            int SMax )  {
+  //
+  // Version of GetStrTer(..) allowing for spaces in the string.
+  //
+  //   Copies at least n (or LMax if LMax<n) first symbols of
+  // string S into string L, then continues copying until first
+  // terminating null is found. If the terminating null
+  // is met among the first n characters or if SMax<n, the string
+  // L will be padded with spaces till the length of minimum of
+  // n and LMax and then terminated with the null.
+  //   SMax are buffer lengths of L and S, respectively. The last
+  // character in L will be the terminating null.
+  //
+  int i,k,lm1,msl,mnsl;
+    lm1  = LMax-1;
+    msl  = IMin(lm1,SMax);
+    mnsl = IMin(n,msl);
+    k    = 0;
+    for (i=0;i<mnsl;i++)
+      if (S[i])  L[k++] = S[i];
+           else  break;
+    if ((!S[k]) || (k>=SMax))  {
+      lm1 = IMin(n,lm1);
+      while (k<lm1)
+        L[k++] = ' ';
+    } else  {
+      lm1 = k;
+      for (i=lm1;i<msl;i++)
+        if (S[i])  L[k++] = S[i];
+             else  break;
+    }
+    L[k] = char(0);
+  }
+
+  void  strcpy_n ( pstr d, cpstr s, int n )  {
+  //   Copies at most n symbols from string s to d, but
+  // no more than strlen(s) (s must contain a terminating
+  // null). The terminating null IS NEITHER appended NOR
+  // copied to d.
+  int i;
+    i = 0;
+    while ((i<n) && (s[i]))  {
+      d[i] = s[i];
+      i++;
+    }
+  }
+
+
+  void  strcpy_n1 ( pstr d, cpstr s, int n )  {
+  //   Copies at most n last symbols from string s to d, but
+  // no more than strlen(s) (s must contain a terminating null).
+  // The string in d is aligned to the right and added with
+  // spaces at the left, if necessary. The terminating null
+  // IS NEITHER appended NOR copied to d.
+  int i,k;
+    i = n-1;
+    k = strlen(s)-1;
+    while ((i>=0) && (k>=0))
+      d[i--] = s[k--];
+    while (i>=0)
+      d[i--] = ' ';
+  }
+
+  void  strcpy_nr ( pstr d, cpstr s, int n )  {
+  //   Copies at most n symbols from string s to d, but
+  // no more than strlen(s) (s must contain a terminating null).
+  // The string in d is aligned to the right and added with
+  // spaces at the left, if necessary. The terminating null
+  // IS NEITHER appended NOR copied to d.
+  int i,k;
+    i = n-1;
+    k = IMin(i,strlen(s)-1);
+    while ((i>=0) && (k>=0))
+      d[i--] = s[k--];
+    while (i>=0)
+      d[i--] = ' ';
+  }
+
+
+  void strcpy_ns ( pstr d, cpstr s, int n )  {
+  //   Copies at most n symbols from string s to d, but
+  // no more than strlen(s) (s must contain a terminating
+  // null). The terminating null IS NEITHER appended NOR
+  // copied to d; rather, d is padded with spaces if
+  // strlen(s)<n.
+  int i;
+    i = 0;
+    while ((i<n) && (s[i]))  {
+      d[i] = s[i];
+      i++;
+    }
+    while (i<n)
+      d[i++] = ' ';
+  }
+
+
+  pstr strcpy_cs ( pstr d, cpstr s )  {
+  //   Copies string s to string d cutting all spaces at
+  // at the end. Thus, " abcde   " will be copied like
+  // " abcde" (terminating null appended).
+  //   The function returns d.
+  int i;
+    i = 0;
+    while (s[i])  {
+      d[i] = s[i];
+      i++;
+    }
+    i--;
+    while ((i>0) && (d[i]==' ')) i--;
+    if (d[i]==' ')  d[i]   = char(0);
+              else  d[i+1] = char(0);
+    return d;
+  }
+
+
+  pstr strcpy_ncs ( pstr d, cpstr s, int n )  {
+  //   Copies at most n characters from string s to string d
+  // cutting all spaces at at the end. Thus, " abcde   " will
+  // be copied like " abc" at n=4 and like " abcde" at n>5
+  // (terminating null appended).
+  //   The function returns d.
+  int i;
+    i = 0;
+    while (s[i] && (i<n))  {
+      d[i] = s[i];
+      i++;
+    }
+    i--;
+    while ((i>0) && (d[i]==' ')) i--;
+    if (d[i]==' ')  d[i]   = char(0);
+              else  d[i+1] = char(0);
+    return d;
+  }
+
+  pstr strcpy_css ( pstr d, cpstr s )  {
+  //   Copies string s to string d cutting all spaces at
+  // at the begining and at the end. Thus, " ab c de   "
+  // will be copied like "ab c de" (terminating null
+  // appended).
+  //   The function returns d.
+  int i,k;
+    i = 0;
+    while (s[i]==' ')  i++;
+    k = 0;
+    while (s[i])
+      d[k++] = s[i++];
+    if (k>0)  {
+      k--;
+      while ((k>0) && (d[k]==' '))  k--;
+      if (d[k]==' ')  d[k] = char(0);
+                else  d[k+1] = char(0);
+    } else
+      d[k] = char(0);
+    return d;
+  }
+
+  pstr strcpy_ncss ( pstr d, cpstr s, int n )  {
+  //   Copies at most n characters from string s to string d cutting
+  // all spaces at the begining and at the end. Thus, " ab c de  "
+  // will be copied like "ab" at n=3 (terminating null appended).
+  //   The function returns d.
+  int i,k;
+    i = 0;
+    while ((s[i]==' ') && (i<n))  i++;
+    k = 0;
+    while (s[i] && (i<n))
+      d[k++] = s[i++];
+    if (k>0)  {
+      k--;
+      while ((k>0) && (d[k]==' '))  k--;
+      if (d[k]==' ')  d[k] = char(0);
+                else  d[k+1] = char(0);
+    } else
+      d[k] = char(0);
+    return d;
+  }
+
+
+  pstr strcpy_n0 ( pstr d, cpstr s, int n )  {
+  //   Copies at most n symbols from string s to d, but
+  // no more than strlen(s) (s must contain a terminating
+  // null). The terminating null IS appended to d.
+  //   The function returns d.
+  int i;
+    i = 0;
+    while ((i<n) && (s[i]))  {
+      d[i] = s[i];
+      i++;
+    }
+    d[i] = char(0);
+    return d;
+  }
+
+
+  int strlen_des ( cpstr s )  {
+  //  strlen_des returns the length of a string as if all extra
+  //  spaces from the latter have been deleted. Extra spaces
+  //  include all leading and tracing spaces and any sequential
+  //  spaces when more than one. The string does not change.
+  int i,l;
+    l = 0;
+    i = 0;
+    while (s[i]==' ')  i++;
+    while (s[i])  {
+      if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
+        l++;
+      i++;
+    }
+    return l;
+  }
+
+  pstr strcpy_des ( pstr d, cpstr s )  {
+  //  strcpy_des copies string s into string d removing all extra
+  //  spaces from the latter. Extra spaces include all leading and
+  //  tracing spaces and any sequential spaces when more than one.
+  int i,j;
+    j = 0;
+    i = 0;
+    while (s[i]==' ')  i++;
+    while (s[i])  {
+      if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
+        d[j++] = s[i];
+      i++;
+    }
+    d[j] = char(0);
+    return d;
+  }
+
+  pstr strcat_des ( pstr d, cpstr s )  {
+  //  strcpy_des appends string s to string d removing all extra
+  //  spaces from the latter. Extra spaces include all leading and
+  //  tracing spaces and any sequential spaces when more than one.
+  int i,j;
+    j = strlen(d);
+    i = 0;
+    while (s[i]==' ')  i++;
+    while (s[i])  {
+      if ((s[i]!=' ') || ((s[i+1]!=' ') && s[i+1]))
+        d[j++] = s[i];
+      i++;
+    }
+    d[j] = char(0);
+    return d;
+  }
+
+
+  void PadSpaces ( pstr S, int len )  {
+  //  Pads string S with spaces making its length equal to len.
+  //  The terminating zero is added, so that S should reserve
+  // space of a minimum len+1 characters.
+  int i=strlen(S);
+    while (i<len)  S[i++] = ' ';
+    S[i] = char(0);
+  }
+
+
+  pstr CutSpaces ( pstr S, int CutKey )  {
+  //   Cuts spaces at the begining or end of string S
+  // according to the value of CutKey. THe function
+  // returns S;
+  int i,k;
+    i = 0;
+    k = 0;
+    if (CutKey & SCUTKEY_BEGIN)
+      while (S[i]==' ')  i++;
+    if (k<i)
+      while (S[i])
+        S[k++] = S[i++];
+    else
+      k = strlen(S);
+    if ((CutKey & SCUTKEY_END) && (k>0))  {
+      k--;
+      while ((k>0) && (S[k]==' '))  k--;
+      if (S[k]!=' ')  k++;
+    }
+    S[k] = char(0);
+    return S;
+  }
+
+
+  pstr DelSpaces ( pstr S, char c )  {
+  //   Removes all spaces (or other symbols as specified by 'c')
+  // from the string. The string is then shrinked by the number
+  // of removed characters. Thus, " as ttt  " becomes "asttt".
+  int  i,j;
+    j = 0;
+    for (i=0;S[i];i++)
+      if (S[i]!=c)  {
+        if (j<i)  S[j] = S[i];
+        j++;
+      }
+    S[j] = char(0);
+    return S;
+  }
+
+  pstr EnforceSpaces ( pstr S )  {
+  int i,k;
+    i = 0;
+    while (S[i])  {
+      k = int(S[i]);
+      if ((k<32) && (k!=9) && (k!=10) && (k!=13))  S[i] = ' ';
+      i++;
+    }
+    return S;
+  }
+
+
+  //  ----------------------------------------------------
+
+  #define  _fbase  256
+  #define  _rfbase 256.0
+  #define  _fsign  0x80
+  #define  _fsign1 0x7F
+
+  #ifdef  UseDoubleFloat
+  # define _nfPowers  255
+  # define _nfPower0  127
+  # define _nfPower8  135
+  //# define _nfPower4  131
+  # define _nfPower4  130
+  #else
+  # define _nfPowers  31
+  # define _nfPower0  15
+  # define _nfPower8  19
+  # define _nfPower4  19
+  #endif
+
+  static realtype _fpower[_nfPowers+1];
+  static realtype _fpower8;
+  static realtype _fpower4;
+  static bool     _old_float_unibin;
+
+  bool InitFPowers()  {
+  int i;
+    _fpower[_nfPower0] = 1.0;
+    for (i=1;i<=_nfPower0;i++)  {
+      _fpower[_nfPower0+i] = _fpower[_nfPower0+i-1]*_rfbase;
+      _fpower[_nfPower0-i] = _fpower[_nfPower0-i+1]/_rfbase;
+    }
+    _fpower[_nfPowers] = fMaxReal;
+    _fpower8 = _fpower[_nfPower8];
+    _fpower4 = _fpower[_nfPower4];
+    _old_float_unibin = false;
+    return true;
+  }
+
+  void __modify4()  {
+    _fpower4 = _fpower[_nfPower4-1];
+  }
+
+  void  set_new_float_unibin()  {
+    _old_float_unibin = false;
+  }
+
+  bool is_new_float_unibin()  {
+    return !_old_float_unibin;
+  }
+
+  void  set_old_float_unibin()  {
+    _old_float_unibin = true;
+  }
+
+  void  int2UniBin ( int I, intUniBin iUB )  {
+  int  n;
+  word j;
+    n = I;
+    for (j=0;j<sizeof(intUniBin);j++)  {
+      iUB[j] = byte(n & 0xFF);
+      n >>= 8;
+    }
+  }
+
+  void  short2UniBin ( short S, shortUniBin sUB )  {
+  int   j,sh;
+  short n;
+    sh = 8*(sizeof(shortUniBin)-1);
+    for (j=sizeof(shortUniBin)-1;j>=0;j--)  {
+      n = (S >> sh) & 0xFF;
+      sUB[j] = byte(n);
+      sh -= 8;
+    }
+  }
+
+  void  long2UniBin ( long L, longUniBin lUB )  {
+  int  j,sh;
+  long n;
+    sh = 8*(sizeof(longUniBin)-1);
+    for (j=sizeof(longUniBin)-1;j>=0;j--)  {
+      n = (L >> sh) & 0xFF;
+      lUB[j] = byte(n);
+      sh -= 8;
+    }
+  }
+
+  void  word2UniBin ( word W, wordUniBin wUB )  {
+  int  j,sh;
+  word n;
+    sh = 8*(sizeof(wordUniBin)-1);
+    for (j=sizeof(wordUniBin)-1;j>=0;j--)  {
+      n = (W >> sh) & 0xFF;
+      wUB[j] = byte(n);
+      sh -= 8;
+    }
+  }
+
+
+  void  real2UniBin ( realtype R, realUniBin rUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    Q = (Q/_fpower[k2])*_fpower8;
+    rUB[0] = byte(k2);
+    for (k=sizeof(realUniBin)-1;k>0;k--)  {
+      L      = floor(Q/_rfbase);
+      rUB[k] = byte(int(Q-L*_rfbase));
+      Q      = L;
+    }
+    if (R<0)  rUB[1] |= _fsign;
+
+  }
+
+  void  shortreal2UniBin ( shortreal R, shortrealUniBin srUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    Q = (Q/_fpower[k2])*_fpower4;
+    srUB[0] = byte(k2);
+    for (k=sizeof(shortrealUniBin)-1;k>0;k--)  {
+      L = floor(Q/_rfbase);
+      srUB[k] = byte(int(Q-L*_rfbase));
+      Q = L;
+    }
+    if (R<0)  srUB[1] |= _fsign;
+
+  }
+
+  /*
+  #undef _new_float_unibin
+
+  #ifdef _new_float_unibin
+
+  void  float2UniBin ( realtype R, floatUniBin fUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    Q = (Q/_fpower[k2])*_fpower4;
+    fUB[0] = byte(k2);
+    for (k=sizeof(floatUniBin)-1;k>0;k--)  {
+      L = floor(Q/_rfbase);
+      fUB[k] = byte(int(Q-L*_rfbase));
+      Q = L;
+    }
+    if (R<0)  fUB[1] |= _fsign;
+
+  }
+
+  #else
+
+  void  float2UniBin ( realtype R, floatUniBin fUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    Q = (Q/_fpower[k2])*_fpower8;
+    fUB[0] = byte(k2);
+    for (k=sizeof(realUniBin)-1;k>0;k--)  {
+      L = floor(Q/_rfbase);
+      if (k<=sizeof(floatUniBin))
+        fUB[k] = byte(int(Q-L*_rfbase));
+      Q = L;
+    }
+    if (R<0)  fUB[1] |= _fsign;
+
+  }
+
+  #endif
+  */
+
+  void  float2UniBin ( realtype R, floatUniBin fUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    fUB[0] = byte(k2);
+
+    if (_old_float_unibin)  {
+      // this is wrong but compatible with already existing files :(
+      // in the result, it gives errors in 6th digit at back conversion
+      Q = (Q/_fpower[k2])*_fpower8;
+      for (k=sizeof(realUniBin)-1;k>0;k--)  {
+        L = floor(Q/_rfbase);
+        if (k<=(int)sizeof(floatUniBin))
+          fUB[k] = byte(int(Q-L*_rfbase));
+        Q = L;
+      }
+    } else  {
+      // this is correct
+      Q = (Q/_fpower[k2])*_fpower4;
+      for (k=sizeof(floatUniBin)-1;k>0;k--)  {
+        L = floor(Q/_rfbase);
+        fUB[k] = byte(int(Q-L*_rfbase));
+        Q = L;
+      }
+    }
+
+  //if (fUB[1] & _fsign)  printf ( " error!\n" );
+
+    if (R<0)  fUB[1] |= _fsign;
+
+  }
+
+
+  void  UniBin2float ( floatUniBin fUB, realtype & R )  {
+  int j,s;
+
+    if (fUB[1] & _fsign)  {
+      s = 1;
+      fUB[1] &= _fsign1;
+    } else
+      s = 0;
+
+    R = int(fUB[1]);
+
+    if (_old_float_unibin)  {
+      // this is wrong and gives a conversion error in 6th digit :(
+      // we have to keep this for compatibility with already existing
+      // files
+      for (j=2;j<(int)sizeof(floatUniBin);j++)
+        R = R*_rfbase + int(fUB[j]);
+      for (j=sizeof(floatUniBin);j<(int)sizeof(realUniBin);j++)
+        R *= _rfbase;
+      R = (R/_fpower8)*_fpower[int(fUB[0])];
+    } else  {
+      // this is correct
+      for (j=2;j<(int)sizeof(floatUniBin);j++)
+        R = R*_rfbase + int(fUB[j]);
+      R = (R/_fpower4)*_fpower[int(fUB[0])];
+    }
+    if (s)  R = -R;
+  }
+
+
+  /* -------------------------------------------------------
+     This piece of code shows that float2Unibin - Unbin2float
+     pair does same-quality job as the native float - double
+     conversion:
+
+    InitMatType();
+    set_new_float_unibin();
+
+    floatUniBin      fUB;
+    realUniBin      rUB;
+    realtype         maxsh  = MaxShortReal/2.0; // max manageable /2!
+    float            maxshf = maxsh;
+    realtype         maxshr = maxshf;
+    realtype         maxsh1;
+
+    float2UniBin ( maxsh,fUB );
+    UniBin2float ( fUB,maxsh1 );
+
+    printf ( " float\n %10.3f\n %10.3f\n %10.3f\n %10.3f\n",
+             maxsh,maxsh1,maxshf,maxshr );
+
+    maxsh = MaxShortReal;
+    real2UniBin ( maxsh,rUB );
+    UniBin2real ( rUB,maxsh1 );
+
+    printf ( " real\n %10.3f\n %10.3f\n",maxsh,maxsh1 );
+
+  ---- RESULTS:
+
+   float
+   170099999999999990938343446679146987520.000
+   170099999948540854500627141228603899904.000
+   170100000027769017014891478822147850240.000
+   170100000027769017014891478822147850240.000
+   real
+   340199999999999981876686893358293975040.000
+   340199999999999981876686893358293975040.000
+
+  -------------------------------------------------------------- */
+
+  /*
+  void  shortreal2UniBin ( shortreal R, shortrealUniBin srUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    Q = (Q/_fpower[k2])*_fpower8;
+    srUB[0] = byte(k2);
+    for (k=sizeof(realUniBin)-1;k>0;k--)  {
+      L = floor(Q/_rfbase);
+      if (k<=(int)sizeof(shortrealUniBin))
+        srUB[k] = byte(int(Q-L*_rfbase));
+      Q = L;
+    }
+    if (R<0)  srUB[1] |= _fsign;
+
+  }
+
+  void  float2UniBin ( realtype R, floatUniBin fUB )  {
+  int      k1,k2,k;
+  realtype Q,L;
+
+    if (R>=0)  Q = R;
+         else  Q = -R;
+    k1 = 0;
+    k2 = _nfPowers;
+    do {
+      k = (k1+k2)/2;
+      if (Q>=_fpower[k])  k1 = k;
+                    else  k2 = k;
+    } while (k2>k1+1);
+    if (Q<=_fpower[0])  k2 = 0;
+    Q = (Q/_fpower[k2])*_fpower8;
+    fUB[0] = byte(k2);
+    for (k=sizeof(realUniBin)-1;k>0;k--)  {
+      L = floor(Q/_rfbase);
+      if (k<=(int)sizeof(floatUniBin))
+        fUB[k] = byte(int(Q-L*_rfbase));
+      Q = L;
+    }
+    if (R<0)  fUB[1] |= _fsign;
+
+  }
+  */
+
+  /*
+  void  UniBin2int ( intUniBin iUB, int & I )  {
+  int j,n,sh;
+    sh = 8*sizeof(intUniBin);
+    I  = 0x00;
+    for (j=sizeof(intUniBin)-1;j>=0;j--)  {
+      sh -= 8;
+      n   = byte(iUB[j]);
+      I   = I | (n << sh);
+    }
+  }
+  */
+
+  void  UniBin2int ( intUniBin iUB, int & I )  {
+  int j;
+    I = 0x00;
+    for (j=sizeof(intUniBin)-1;j>=0;j--)  {
+      I <<= 8;
+      I |= int(iUB[j]);
+    }
+  }
+
+  void  UniBin2short ( shortUniBin sUB, short & S )  {
+  int   j,sh;
+  short n;
+    sh = 8*sizeof(shortUniBin);
+    S  = 0x00;
+    for (j=sizeof(shortUniBin)-1;j>=0;j--)  {
+      sh -= 8;
+      n   = byte(sUB[j]);
+      S   = S | (n << sh);
+    }
+  }
+
+  void  UniBin2long ( longUniBin lUB, long & L )  {
+  int  j,sh;
+  long n;
+    sh = 8*sizeof(longUniBin);
+    L  = 0x00;
+    for (j=sizeof(longUniBin)-1;j>=0;j--)  {
+      sh -= 8;
+      n   = byte(lUB[j]);
+      L   = L | (n << sh);
+    }
+  }
+
+  void  UniBin2word ( wordUniBin wUB, word & W )  {
+  int  j,sh;
+  word n;
+    sh = 8*sizeof(wordUniBin);
+    W  = 0x00;
+    for (j=sizeof(wordUniBin)-1;j>=0;j--)  {
+      sh -= 8;
+      n   = byte(wUB[j]);
+      W   = W | (n << sh);
+    }
+  }
+
+  void  UniBin2real ( realUniBin rUB, realtype & R )  {
+  int j,s;
+    if (rUB[1] & _fsign)  {
+      s = 1;
+      rUB[1] &= _fsign1;
+    } else
+      s = 0;
+    R = int(rUB[1]);
+    for (j=2;j<(int)sizeof(realUniBin);j++)
+      R = R*_rfbase + int(rUB[j]);
+    R = (R/_fpower8)*_fpower[int(rUB[0])];
+    if (s)  R = -R;
+  }
+
+  void  UniBin2shortreal ( shortrealUniBin srUB, shortreal & R )  {
+  int j,s;
+    if (srUB[1] & _fsign)  {
+      s = 1;
+      srUB[1] &= _fsign1;
+    } else
+      s = 0;
+    R = int(srUB[1]);
+    for (j=2;j<(int)sizeof(shortrealUniBin);j++)
+      R = R*_rfbase + int(srUB[j]);
+    R = (R/_fpower4)*_fpower[int(srUB[0])];
+    if (s)  R = -R;
+  }
+
+  /*
+  #ifdef _new_float_unibin
+
+  void  UniBin2float ( floatUniBin fUB, realtype & R )  {
+  int j,s;
+    if (fUB[1] & _fsign)  {
+      s = 1;
+      fUB[1] &= _fsign1;
+    } else
+      s = 0;
+    R = int(fUB[1]);
+    for (j=2;j<(int)sizeof(floatUniBin);j++)
+      R = R*_rfbase + int(fUB[j]);
+    R = (R/_fpower4)*_fpower[int(fUB[0])];
+    if (s)  R = -R;
+  }
+
+  #else
+
+  void  UniBin2float ( floatUniBin fUB, realtype & R )  {
+  int j,s;
+    if (fUB[1] & _fsign)  {
+      s = 1;
+      fUB[1] &= _fsign1;
+    } else
+      s = 0;
+    R = int(fUB[1]);
+    for (j=2;j<sizeof(floatUniBin);j++)
+      R = R*_rfbase + int(fUB[j]);
+    for (j=sizeof(floatUniBin);j<sizeof(realUniBin);j++)
+      R *= _rfbase;
+    R = (R/_fpower8)*_fpower[int(fUB[0])];
+    if (s)  R = -R;
+  }
+
+  #endif
+  */
+
+
+
+
+
+  /*
+  void  UniBin2shortreal ( shortrealUniBin srUB, shortreal & R )  {
+  int j,s;
+    if (srUB[1] & _fsign)  {
+      s = 1;
+      srUB[1] &= _fsign1;
+    } else
+      s = 0;
+    R = int(srUB[1]);
+    for (j=2;j<(int)sizeof(shortrealUniBin);j++)
+      R = R*_rfbase + int(srUB[j]);
+    for (j=sizeof(shortrealUniBin);j<(int)sizeof(realUniBin);j++)
+      R *= _rfbase;
+    R = (R/_fpower8)*_fpower[int(srUB[0])];
+    if (s)  R = -R;
+  }
+
+  void  UniBin2float ( floatUniBin fUB, realtype & R )  {
+  int j,s;
+    if (fUB[1] & _fsign)  {
+      s = 1;
+      fUB[1] &= _fsign1;
+    } else
+      s = 0;
+    R = int(fUB[1]);
+    for (j=2;j<(int)sizeof(floatUniBin);j++)
+      R = R*_rfbase + int(fUB[j]);
+    for (j=sizeof(floatUniBin);j<(int)sizeof(realUniBin);j++)
+      R *= _rfbase;
+    R = (R/_fpower8)*_fpower[int(fUB[0])];
+    if (s)  R = -R;
+  }
+  */
+
+
+  void mem_write ( int I, pstr S, int & l )  {
+  intUniBin iUB;
+    int2UniBin ( I,iUB );
+    memcpy ( &(S[l]),iUB,sizeof(intUniBin) );
+    l += sizeof(intUniBin);
+    S[l] = char(0);
+  }
+
+  void mem_write ( short I, pstr S, int & l )  {
+  shortUniBin sUB;
+    short2UniBin ( I,sUB );
+    memcpy ( &(S[l]),sUB,sizeof(shortUniBin) );
+    l += sizeof(shortUniBin);
+    S[l] = char(0);
+  }
+
+  void mem_write ( long I, pstr S, int & l )  {
+  longUniBin lUB;
+    long2UniBin ( I,lUB );
+    memcpy ( &(S[l]),lUB,sizeof(longUniBin) );
+    l += sizeof(longUniBin);
+    S[l] = char(0);
+  }
+
+  void mem_write ( word W, pstr S, int & l )  {
+  wordUniBin wUB;
+    word2UniBin ( W,wUB );
+    memcpy ( &(S[l]),wUB,sizeof(wordUniBin) );
+    l += sizeof(wordUniBin);
+    S[l] = char(0);
+  }
+
+  void mem_write ( realtype R, pstr S, int & l )  {
+  realUniBin rUB;
+    real2UniBin ( R,rUB );
+    memcpy ( &(S[l]),rUB,sizeof(realUniBin) );
+    l += sizeof(realUniBin);
+    S[l] = char(0);
+  }
+
+  void mem_write ( shortreal R, pstr S, int & l )  {
+  shortrealUniBin srUB;
+    shortreal2UniBin ( R,srUB );
+    memcpy ( &(S[l]),srUB,sizeof(shortrealUniBin) );
+    l += sizeof(shortrealUniBin);
+    S[l] = char(0);
+  }
+
+  void mem_write ( pstr L, int len, pstr S, int & l )  {
+    memcpy ( &(S[l]),L,len );
+    l += len;
+    S[l] = char(0);
+  }
+
+  void mem_write ( pstr L, pstr S, int & l )  {
+  int len;
+    if (L)  len = strlen(L);
+      else  len = 0;
+    mem_write ( len,S,l );
+    if (len>0)  {
+      memcpy ( &(S[l]),L,len );
+      l += len;
+      S[l] = char(0);
+    }
+  }
+
+  void mem_write ( bool B, pstr S, int & l )  {
+    if (B)  S[l++] = 'Y';
+      else  S[l++] = 'N';
+    S[l] = char(0);
+  }
+
+  void mem_write_byte ( byte B, pstr S, int & l )  {
+    S[l++] = char(B);
+    S[l]   = char(0);
+  }
+
+
+  void mem_read ( int & I, cpstr S, int & l )  {
+  intUniBin iUB;
+    memcpy ( iUB,&(S[l]),sizeof(intUniBin) );
+    l += sizeof(intUniBin);
+    UniBin2int ( iUB,I );
+  }
+
+  void mem_read ( short & I, cpstr S, int & l )  {
+  shortUniBin sUB;
+    memcpy ( sUB,&(S[l]),sizeof(shortUniBin) );
+    l += sizeof(shortUniBin);
+    UniBin2short ( sUB,I );
+  }
+
+  void mem_read ( long & I, cpstr S, int & l )  {
+  longUniBin lUB;
+    memcpy ( lUB,&(S[l]),sizeof(longUniBin) );
+    l += sizeof(longUniBin);
+    UniBin2long ( lUB,I );
+  }
+
+  void mem_read ( word & W, cpstr S, int & l )  {
+  wordUniBin wUB;
+    memcpy ( wUB,&(S[l]),sizeof(wordUniBin) );
+    l += sizeof(wordUniBin);
+    UniBin2word ( wUB,W );
+  }
+
+  void mem_read ( realtype & R, cpstr S, int & l )  {
+  realUniBin rUB;
+    memcpy ( rUB,&(S[l]),sizeof(realUniBin) );
+    l += sizeof(realUniBin);
+    UniBin2real ( rUB,R );
+  }
+
+  void mem_read ( shortreal & R, cpstr S, int & l )  {
+  shortrealUniBin srUB;
+    memcpy ( srUB,&(S[l]),sizeof(shortrealUniBin) );
+    l += sizeof(shortrealUniBin);
+    UniBin2shortreal ( srUB,R );
+  }
+
+  void mem_read ( pstr L, int len, cpstr S, int & l )  {
+    memcpy ( L,&(S[l]),len );
+    l += len;
+  }
+
+  void mem_read ( pstr & L, cpstr S, int & l )  {
+  int len;
+    if (L)  {
+      delete[] L;
+      L = NULL;
+    }
+    mem_read ( len,S,l );
+    if (len>0)  {
+      L = new char[len+1];
+      memcpy ( L,&(S[l]),len );
+      L[len] = char(0);
+      l += len;
+    }
+  }
+
+  void mem_read ( bool & B, cpstr S, int & l )  {
+    B = (S[l++]=='Y');
+  }
+
+  void mem_read_byte ( byte & B, cpstr S, int & l )  {
+    B = byte(S[l++]);
+  }
+
+  // -------------------------------------------------------
+
+  bool InitMatType()  {
+    MachEps      = MachinEps();
+    floatMachEps = floatMachinEps();
+    LnMaxReal    = log(fMaxReal);
+    LnMinReal    = log(fMinReal);
+    LnMaxRealExp = LnMaxReal;
+    LnMinRealExp = LnMinReal;
+    InitFPowers();
+    return true;
+  }
+
+}
+
+/* ===================================================  */
+
+// ***  end of  <MatType>
diff --git a/mmdb2/mmdb_mattype.h b/mmdb2/mmdb_mattype.h
new file mode 100644
index 0000000..08cf55c
--- /dev/null
+++ b/mmdb2/mmdb_mattype.h
@@ -0,0 +1,652 @@
+//  $Id: mmdb_mattype.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    10.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MatType_ <interface>
+//       ~~~~~~~~~
+//  **** Functions :
+//       ~~~~~~~~~~~
+//               GetString  ( reads substring from a string         )
+//               GetStrTer  ( reads substring and put term-ing null )
+//               strcpy_n   ( copies not more than n characters     )
+//               strcpy_ns  ( like strcpy_ns and pads with spaces   )
+//               strcpy_n0  ( like strcpy_n and adds terminating 0  )
+//               PadSpaces  ( pads a string with spaces             )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#ifndef  __MMDB_MatType__
+#define  __MMDB_MatType__
+
+#include <math.h>
+
+#define  UseDoubleFloat
+
+#ifndef __ClassMacros
+
+# define __ClassMacros
+
+ //  A Class definition macros
+# define DefineClass(ClassName)             \
+   class ClassName;                         \
+   typedef ClassName    * P##ClassName;     \
+   typedef ClassName    & R##ClassName;     \
+   typedef P##ClassName * PP##ClassName;    \
+   typedef P##ClassName & RP##ClassName;
+
+ //  A Structure definition macros
+# define DefineStructure(StructureName)             \
+   struct StructureName;                            \
+   typedef StructureName    * P##StructureName;     \
+   typedef StructureName    & R##StructureName;     \
+   typedef P##StructureName * PP##StructureName;    \
+   typedef P##StructureName & RP##StructureName;
+
+#endif
+
+#define UNUSED_ARGUMENT(x) (void)x
+
+// -----------------------------------------------------
+
+namespace mmdb  {
+
+#ifdef  UseDoubleFloat
+
+  typedef  double       realtype;
+  const realtype MinReal  = 2.2250e-307;
+  const realtype MaxReal  = 1.7976e+308;
+  const realtype fMinReal = 2.2250e-307;
+  const realtype fMaxReal = 1.7976e+308;
+
+#else
+
+  typedef  float       realtype;
+  const realtype MinReal  = 1.1755e-38;
+  const realtype MaxReal  = 3.4020e+38;
+  const realtype fMinReal = 1.1755e-38;
+  const realtype fMaxReal = 3.4020e+38;
+
+#endif
+
+  typedef   float     shortreal;
+  const shortreal MinShortReal = 1.1755e-38;
+  const shortreal MaxShortReal = 3.4020e+38;
+
+#define   strrchr   LastOccurence
+#define   fstrrchr  LastOccurence
+#define   strchr    FirstOccurence
+#define   fstrchr   FirstOccurence
+
+  typedef   char     *         pstr;
+  typedef   const char *       cpstr;
+  typedef   unsigned int       word;
+  typedef   unsigned char      byte;
+  typedef   signed   char      short_int;
+//  typedef   byte               Boolean;
+  typedef   unsigned int       word2;
+  typedef   byte *             byteptr;
+  typedef   unsigned long      lword;
+
+  typedef   byte intUniBin      [4];
+  typedef   byte shortUniBin    [2];
+  typedef   byte longUniBin     [4];
+  typedef   byte wordUniBin     [4];
+  typedef   byte realUniBin     [10];
+  typedef   byte floatUniBin    [5];
+  typedef   byte shortrealUniBin[5];
+
+#ifdef _WIN32
+  pstr strcasestr ( pstr s1, cpstr s2 );
+#endif
+
+#ifdef _MSC_VER
+#define   strncasecmp _strnicmp
+#define   strcasecmp  _stricmp
+#endif
+
+  const int      MaxInt  =  32767;
+  const int      MinInt  = -32768;
+  const word     MaxWord =  65535L;
+  const long int MaxInt4 =  2147483647L;
+
+  //    MinInt4 would have to be defined as  -2147483648,
+  // however some compilers do not like that. To be on safe,
+  // we define it as -2147483647:
+  const long int MinInt4  = -2147483647;
+  const lword    MaxWord4 =  4294967295UL;
+
+  const realtype Pi   = 3.141592653589793238462643;
+  const realtype Eu   = 2.718281828459045235360287;
+  const realtype ln10 = 2.3025850929940456840179915;
+
+  // ***  vectors   X[1..N] :
+  typedef   realtype * rvector;
+  typedef   int      * ivector;
+  typedef   word     * wvector;
+  typedef   byte     * bvector;
+  typedef   bool     * ovector;
+  typedef   long     * lvector;
+  typedef   lword    * lwvector;
+  typedef   pstr     * psvector;
+
+  // ***  matrices   X[1..N][1..M] :
+  typedef   rvector  * rmatrix;
+  typedef   ivector  * imatrix;
+  typedef   wvector  * wmatrix;
+  typedef   bvector  * bmatrix;
+  typedef   ovector  * omatrix;
+  typedef   lvector  * lmatrix;
+  typedef   lwvector * lwmatrix;
+  typedef   psvector * psmatrix;
+
+  // ***  matrices   X[1..N][1..M][1..K] :
+  typedef   rmatrix  * rmatrix3;
+  typedef   imatrix  * imatrix3;
+  typedef   wmatrix  * wmatrix3;
+  typedef   bmatrix  * bmatrix3;
+  typedef   omatrix  * omatrix3;
+  typedef   lmatrix  * lmatrix3;
+  typedef   lwmatrix * lwmatrix3;
+  typedef   psmatrix * psmatrix3;
+
+
+  // ------------------------------------------------------------
+
+  //  Initialization. Some C++ enviroments do not do call
+  // InitMatType() automatically, therefore it is always
+  // advisable to call InitMatType() explicitely from the top of
+  // main(). It is completely harmless and cheap (although
+  // unnecessary) to call InitMatType() multiple times.
+  extern bool InitMatType();
+
+  // ------------------------------------------------------------
+
+  inline int mround ( realtype X )  { return  (int)floor(X+0.5);   }
+  inline int ifloor ( realtype X )  { return  (int)floor(X);       }
+  inline int Abs    ( int x )       { return ( x >= 0 ? x : -x );  }
+
+  inline void ISwap ( int & x, int & y )
+  { int  b = x;  x = y;  y = b; }
+
+  inline void WSwap ( word & x, word & y )
+  { word  b = x;  x = y;  y = b; }
+
+  inline void BSwap ( byte & x, byte & y )
+  { byte b = x;  x = y;  y = b; }
+
+  inline void OSwap ( bool & x, bool & y )
+  { bool b = x;  x = y;  y = b; }
+
+  inline void LSwap ( long & x, long & y )
+  { long b = x;  x = y;  y = b; }
+
+  inline void RSwap ( realtype & x, realtype & y )
+  { realtype b = x;  x = y;  y = b; }
+
+  inline realtype RMax ( const realtype x1, const realtype x2 )
+  { return ( x1 > x2 ? x1 : x2 );  }
+
+  inline long LMax ( const long x1, const long x2 )
+  { return ( x1 > x2 ? x1 : x2 );  }
+
+  inline word WMax ( const word x1, const word x2 )
+  { return ( x1 > x2 ? x1 : x2 );  }
+
+  inline int IMax ( const int x1,  const int x2  )
+  { return ( x1 > x2 ? x1 : x2 );  }
+
+  inline realtype RMin ( const realtype x1, const realtype x2 )
+  { return ( x1 < x2 ? x1 : x2 );  }
+
+  inline long LMin ( const long x1, const long x2 )
+  { return ( x1 < x2 ? x1 : x2 );  }
+
+  inline word WMin ( const word x1, const word x2 )
+  { return ( x1 < x2 ? x1 : x2 );  }
+
+  inline int  IMin ( const int x1,  const int x2  )
+  { return ( x1 < x2 ? x1 : x2 );  }
+
+  inline realtype fsign ( const realtype x1,  const realtype x2 )  {
+  realtype  ax;
+    if (x1>=0.0)  ax = x1;
+            else  ax = -x1;
+    return ( x2 >= 0.0 ? ax : -ax );
+  }
+
+
+  // ------------------------------------------------------------
+
+  //    Allocated vectors are enumerated as [Shift..Shift+N-1]
+  //  rather than [0..N-1] !
+  //    Get-functions return  <true>  if memory was allocated;
+  //  if allocation attemt fails,  vector is assigned with  NULL
+
+  extern bool GetVectorMemory ( rvector  & V, word N, word Shift=1 );
+  extern bool GetVectorMemory ( ivector  & I, word N, word Shift=1 );
+  extern bool GetVectorMemory ( wvector  & W, word N, word Shift=1 );
+  extern bool GetVectorMemory ( bvector  & B, word N, word Shift=1 );
+  extern bool GetVectorMemory ( ovector  & O, word N, word Shift=1 );
+  extern bool GetVectorMemory ( lvector  & L, word N, word Shift=1 );
+  extern bool GetVectorMemory ( lwvector & L, word N, word Shift=1 );
+  extern bool GetVectorMemory ( psvector & P, word N, word Shift=1 );
+
+  //    Shift at deallocation MUST be the same as that at allocation !
+  //   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  //    Free-functions do nothing if vector has value  NULL (e.g.
+  //  after unsuccessful allocation).
+
+  extern void FreeVectorMemory ( rvector  & V, word Shift=1 );
+  extern void FreeVectorMemory ( ivector  & I, word Shift=1 );
+  extern void FreeVectorMemory ( wvector  & W, word Shift=1 );
+  extern void FreeVectorMemory ( bvector  & B, word Shift=1 );
+  extern void FreeVectorMemory ( ovector  & O, word Shift=1 );
+  extern void FreeVectorMemory ( lvector  & L, word Shift=1 );
+  extern void FreeVectorMemory ( lwvector & L, word Shift=1 );
+  extern void FreeVectorMemory ( psvector & P, word Shift=1 );
+
+  // -------------------------------------------------------------
+
+  //    Allocated matrices are enumerated as
+  //          [ShiftN..ShiftN+N-1, ShiftM..ShiftM+M-1]
+  //  rather than [0..N-1,0..M-1] !
+  //    Get-functions return  <true>  if memory was allocated;
+  //  if allocation attemt fails,  matrix is assigned with  NULL
+  //    Free-functions do nothing if matrix has value  NULL (e.g.
+  //  after unsuccessful allocation).
+
+  extern bool GetMatrixMemory
+       ( rmatrix  & A, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( imatrix  & A, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( wmatrix  & W, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( bmatrix  & B, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( omatrix  & O, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( lmatrix  & L, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( lwmatrix & L, word N, word M, word ShiftN=1, word ShiftM=1 );
+  extern bool GetMatrixMemory
+       ( psmatrix & P, word N, word M, word ShiftN=1, word ShiftM=1 );
+
+  //    ShiftN and ShiftM at deallocation MUST be the same as those at
+  //   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  //                          allocation !
+  //                         ~~~~~~~~~~~~~
+
+  extern  void FreeMatrixMemory  ( rmatrix  & A,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( imatrix  & A,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( wmatrix  & W,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( bmatrix  & B,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( omatrix  & O,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( lmatrix  & L,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( lwmatrix & L,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+  extern  void FreeMatrixMemory  ( psmatrix & P,  word N,
+                   word ShiftN=1, word ShiftM=1 );
+
+
+  // -------------------------------------------------------------
+  //   3D matrices
+
+  extern bool GetMatrix3Memory
+             ( rmatrix3  & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( imatrix3  & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( wmatrix3  & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( bmatrix3  & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( omatrix3  & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( lmatrix3  & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( lwmatrix3 & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern bool GetMatrix3Memory
+             ( psmatrix3 & A, word N, word M, word K,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+
+  //
+  //    ShiftN, ShiftM and ShiftK at deallocation MUST be
+  //   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  //         the same as those at allocation !
+  //        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  extern void FreeMatrix3Memory
+                 ( rmatrix3  & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( imatrix3  & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( wmatrix3  & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( bmatrix3  & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( omatrix3  & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( lmatrix3  & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( lwmatrix3 & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+  extern void FreeMatrix3Memory
+                 ( psmatrix3 & A, word N, word M,
+                   word ShiftN=1, word ShiftM=1, word ShiftK=1 );
+
+  // -------------------------------------------------------------
+
+  extern  realtype  MachEps;
+  extern  realtype  floatMachEps;
+  extern  realtype  LnMaxReal;
+  extern  realtype  LnMinReal;
+
+  extern  realtype  MachinEps     ();
+  extern  realtype  floatMachinEps();
+  extern  realtype  frac  ( realtype R   );
+  extern  long      mod   ( long     x, long     y );
+  extern  realtype  Pow   ( realtype X, int      y );
+  extern  realtype  Pow1  ( realtype X, realtype Y );
+  extern  realtype  Exp   ( realtype X );   // use to avoid catastrophies
+  extern  bool      Odd   ( int      i );
+  extern  long    HexValL ( cpstr S );
+  extern  long    OctValL ( cpstr S );
+  extern  long    BinValL ( cpstr S );
+  extern  pstr    BinValS ( long L, pstr S  );  // S[sizeof(long)+1] at least
+
+  extern  pstr ParamStr ( pstr D, cpstr S, realtype V, int M=5,
+                          cpstr S1=(pstr)"" );
+  extern  pstr ParamStr ( pstr D, cpstr S, realtype V, int M,
+                          cpstr S1, realtype V2, int M2=5,
+                          cpstr S2=(pstr)"" );
+
+
+  //  ----------  Strings
+
+  //   CreateCopy(..) allocates Dest string and copies the contents of
+  // Source into it. If Dest is not NULL prior calling the function,
+  // it is attempted to deallocate first.
+
+  extern pstr CreateCopy     ( pstr & Dest, cpstr Source );
+  extern pstr CreateCopy_n   ( pstr & Dest, cpstr Source, int n );
+
+  extern pstr CreateConcat   ( pstr & Dest, cpstr Source );
+  extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
+                                          cpstr Source2 );
+  extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2,
+                                            cpstr Source3 );
+  extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2,
+                                            cpstr Source3,
+                                            cpstr Source4 );
+  extern pstr CreateConcat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2,
+                                            cpstr Source3,
+                                            cpstr Source4,
+                                            cpstr Source5 );
+
+  extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2,
+                                            cpstr Source3,
+                                            cpstr Source4,
+                                            cpstr Source5 );
+  extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2,
+                                            cpstr Source3,
+                                            cpstr Source4 );
+  extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2,
+                                            cpstr Source3 );
+  extern pstr CreateCopCat   ( pstr & Dest, cpstr Source1,
+                                            cpstr Source2 );
+
+  extern pstr LastOccurence  ( cpstr S     , char c      );
+  extern pstr FirstOccurence ( cpstr S     , char c      );
+  extern int  indexOf        ( cpstr S     , char c      );
+  extern pstr FirstOccurence ( cpstr S, int Slen,
+                               cpstr Q, int Qlen );
+  extern int  indexOf        ( cpstr S, int Slen,
+                               cpstr Q, int Qlen );
+
+  extern pstr LowerCase ( pstr s );
+  extern pstr UpperCase ( pstr s );
+
+  //   GetString(..) copies first M characters of string S into string
+  // L, appending the terminating null. If S contains less then M
+  // characters, L will be padded with spaces.
+  extern void GetString ( pstr L, cpstr S, int M );
+
+  //   GetStrTer(..) copies at least n (or LMax if LMax<n) first symbols
+  // of string S into string L, then continues copying until first space
+  // or terminating null is found. If the terminating null is met among
+  // the first n characters or if SMax<n, the string L will be padded
+  // with spaces till the length of minimum of n and LMax and then
+  // terminated with the null.
+  //   LMax and SMax are the buffer lengths of L and S,
+  // respectively. Even if no space is found, the last character
+  // in L will be the terminating null.
+  extern void GetStrTer ( pstr L, cpstr S, int n, int LMax,
+                          int SMax );
+
+
+  // Version of GetStrTer(..) allowing for spaces in the string.
+  //
+  //   Copies at least n (or LMax if LMax<n) first symbols of
+  // string S into string L, then continues copying until first
+  // terminating null is found. If the terminating null
+  // is met among the first n characters or if SMax<n, the string
+  // L will be padded with spaces till the length of minimum of
+  // n and LMax and then terminated with the null.
+  //   SMax are buffer lengths of L and S, respectively. The last
+  // character in L will be the terminating null.
+  extern void GetStrTerWin32File ( pstr L, cpstr S, int n,
+                                   int LMax, int SMax );
+
+
+  //   strcpy_n(..) copies at most n symbols from string s to d,
+  // but no more than strlen(s) (s must contain a terminating
+  // null). The terminating null IS NEITHER appended OR copied
+  // to d.
+  extern void strcpy_n  ( pstr d, cpstr s, int n );
+
+  //   strcpy_n1(..) copies at most n last symbols from string s
+  // to d, but no more than strlen(s) (s must contain a terminating
+  // null). The string in d is aligned to the right and added with
+  // spaces at the left, if necessary. The terminating null
+  // IS NEITHER appended OR copied to d.
+  extern void strcpy_n1 ( pstr d, cpstr s, int n );
+
+  //   Copies at most n symbols from string s to d, but no
+  // more than strlen(s) (s must contain a terminating null).
+  // The string in d is aligned to the right and added with
+  // spaces at the left, if necessary. The terminating null
+  // IS NEITHER appended NOR copied to d.
+  extern void strcpy_nr ( pstr d, cpstr s, int n );
+
+  //   strcpy_ns(..) copies at most n symbols from string s to d,
+  // but no more than strlen(s) (s must contain a terminating
+  // null). The terminating null IS NEITHER appended NOR copied
+  // to d; rather, d is padded with spaces up to the length of n
+  // if strlen(s)<n.
+  extern void strcpy_ns ( pstr d, cpstr s, int n );
+
+  //   strcpy_cs(..) copies string s to string d cutting all
+  // spaces at the end. Thus, " abcde   " will be copied
+  // like " abcde" (terminating null appended).
+  //   The function returns d.
+  extern pstr strcpy_cs ( pstr d, cpstr s );
+
+  //   strcpy_ncs(..) copies at most n characters from string s
+  // to string d cutting all spaces at at the end. Thus, " abcde   "
+  // will be copied like " abc" at n=4 and like " abcde" at n>5
+  // (terminating null appended).
+  //   The function returns d.
+  extern pstr strcpy_ncs ( pstr d, cpstr s, int n );
+
+  //   strcpy_css(..) copies string s to string d cutting all
+  // spaces at the begining and at the end. Thus, " ab c de  "
+  // will be copied like "ab c de" (terminating null appended).
+  //   The function returns d.
+  extern pstr strcpy_css ( pstr d, cpstr s );
+
+  //   strcpy_ncss(..) copies at most n characters from string s
+  // to string d cutting all spaces at the begining and at the end.
+  // Thus, " ab c de  " will be copied like "ab" at n=3 (terminating
+  // null appended).
+  //   The function returns d.
+  extern pstr strcpy_ncss ( pstr d, cpstr s, int n );
+
+  //   strcpy_n0(..) copies at most n symbols from string s to d,
+  // but no more than strlen(s) (s must contain a terminating
+  // null). The terminating null IS appended to d.
+  //   The function returns d.
+  extern pstr strcpy_n0 ( pstr d, cpstr s, int n );
+
+  //   strlen_des returns the length of a string as if all extra
+  // spaces from the latter have been deleted. Extra spaces
+  // include all leading and tracing spaces and any sequential
+  // spaces when more than one. The string does not change.
+  extern int strlen_des ( cpstr s );
+
+  //   strcpy_des copies string s into string d removing all extra
+  // spaces from the latter. Extra spaces include all leading and
+  // tracing spaces and any sequential spaces when more than one.
+  extern pstr strcpy_des ( pstr d, cpstr s );
+
+  //   strcat_des appends string s to string d removing all extra
+  // spaces from the latter. Extra spaces include all leading and
+  // tracing spaces and any sequential spaces when more than one.
+  extern pstr strcat_des ( pstr d, cpstr s );
+
+  //  PadSpaces(..) pads string S with spaces making its length
+  // equal to len. The terminating zero is added, so that S should
+  // reserve space of a minimum len+1 characters.
+  extern void PadSpaces ( pstr S, int len );
+
+  enum SCUTKEY  {
+    SCUTKEY_BEGIN  = 0x00000001,
+    SCUTKEY_END    = 0x00000002,
+    SCUTKEY_BEGEND = 0x00000003
+  };
+
+  //   CutSpaces(..) cuts spaces at the begining or end of
+  // string S according to the value of CutKey. The function
+  // returns S.
+  extern pstr CutSpaces ( pstr S, int CutKey );
+
+  //   DelSpaces(..) removes all spaces (or other symbols as
+  // specified by 'c') from the string. The string is then
+  // shrinked by the number of removed characters. Thus,
+  // " as ttt  " becomes "asttt".
+  extern pstr DelSpaces ( pstr S, char c=' ' );
+
+  //   EnforceSpaces(..) replaces all unprintable characters,
+  // except <CR>, <LF>, <TAB> and some others, for spaces
+  extern pstr EnforceSpaces ( pstr S );
+
+  // -------------------------------------------------------------
+
+  ///   This call will produce correct floats in universal binaries but
+  /// make them incompatible with old files. Without this call, float
+  /// read/write will result in error after 6th digit.
+  ///   UniBin read/write of other types (realtype, shortreal, int etc)
+  /// is not affected by this call, and to the best of knowledge is
+  /// correct (no loss of precision).
+  extern void  set_new_float_unibin();
+  extern bool  is_new_float_unibin();
+  extern void  set_old_float_unibin();
+
+  extern void __modify4();
+
+  extern void int2UniBin       ( int       I,  intUniBin        iUB  );
+  extern void short2UniBin     ( short     S,  shortUniBin      sUB  );
+  extern void long2UniBin      ( long      L,  longUniBin       lUB  );
+  extern void word2UniBin      ( word      W,  wordUniBin       wUB  );
+  extern void real2UniBin      ( realtype  R,  realUniBin       rUB  );
+  extern void float2UniBin     ( realtype  R,  floatUniBin      fUB  );
+  extern void shortreal2UniBin ( shortreal R,  shortrealUniBin  srUB );
+  extern void UniBin2int       ( intUniBin        iUB, int       & I );
+  extern void UniBin2short     ( shortUniBin      sUB, short     & S );
+  extern void UniBin2long      ( longUniBin       lUB, long      & L );
+  extern void UniBin2word      ( wordUniBin       wUB, word      & W );
+  extern void UniBin2real      ( realUniBin       rUB, realtype  & R );
+  extern void UniBin2shortreal ( shortrealUniBin srUB, shortreal & R );
+  extern void UniBin2float     ( floatUniBin      fUB, realtype  & R );
+
+  extern void mem_write ( int       I, pstr S, int & l );
+  extern void mem_write ( short     I, pstr S, int & l );
+  extern void mem_write ( long      I, pstr S, int & l );
+  extern void mem_write ( word      W, pstr S, int & l );
+  extern void mem_write ( realtype  R, pstr S, int & l );
+  extern void mem_write ( shortreal R, pstr S, int & l );
+  extern void mem_write ( pstr      L, int len, pstr S, int & l );
+  extern void mem_write ( pstr      L, pstr S, int & l );
+  extern void mem_write ( bool      B, pstr S, int & l );
+  extern void mem_write_byte ( byte B, pstr S, int & l );
+
+  extern void mem_read  ( int       & I, cpstr S, int & l );
+  extern void mem_read  ( short     & I, cpstr S, int & l );
+  extern void mem_read  ( long      & I, cpstr S, int & l );
+  extern void mem_read  ( word      & W, cpstr S, int & l );
+  extern void mem_read  ( realtype  & R, cpstr S, int & l );
+  extern void mem_read  ( shortreal & R, cpstr S, int & l );
+  extern void mem_read  ( pstr        L, int len, cpstr S, int & l );
+  extern void mem_read  ( pstr      & L, cpstr S, int & l );
+  extern void mem_read  ( bool      & B, cpstr S, int & l );
+  extern void mem_read_byte ( byte  & B, cpstr S, int & l );
+
+}
+
+#endif
+
+/* ===================================================  */
+
diff --git a/mmdb2/mmdb_mmcif_.cpp b/mmdb2/mmdb_mmcif_.cpp
new file mode 100644
index 0000000..e5b962e
--- /dev/null
+++ b/mmdb2/mmdb_mmcif_.cpp
@@ -0,0 +1,3666 @@
+//  $Id: mmdb_mmcif_.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_MMCIF <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::mmcif::Category ( mmCIF category    )
+//       ~~~~~~~~~  mmdb::mmcif::Struct   ( mmCIF structure   )
+//                  mmdb::mmcif::Loop     ( mmCIF loop        )
+//                  mmdb::mmcif::Data     ( mmCIF data block  )
+//                  mmdb::mmcif::File     ( mmCIF file        )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "mmdb_mmcif_.h"
+
+namespace mmdb  {
+
+  namespace mmcif  {
+
+    //  ======================  SortTags  ===============================
+
+    void  SortTags ( psvector tag, int len, ivector index )  {
+    int  i,k,l,l1,l2;
+      if (len==1)  {
+        index[0] = 0;
+        return;
+      }
+      if (strcasecmp(tag[0],tag[1])<0)  {
+        index[0] = 0;
+        index[1] = 1;
+      } else  {
+        index[0] = 1;
+        index[1] = 0;
+      }
+      for (k=2;k<len;k++)  {
+        l2 = k-1;
+        if (strcasecmp(tag[k],tag[index[0]])<0)       l2 = 0;
+        else if (strcasecmp(tag[k],tag[index[l2]])>0) l2 = k;
+        else  {
+          l1 = 0;
+          while (l1<l2-1)  {
+            l = (l1+l2)/2;
+            if (strcasecmp(tag[k],tag[index[l]])<0)  l2 = l;
+                                               else  l1 = l;
+          }
+        }
+        for (i=k;i>l2;i--)
+          index[i] = index[i-1];
+        index[l2] = k;
+      }
+    }
+
+
+    //  ======================  Category  ==========================
+
+    const int CIF_NODATA_DOT        = 0;
+    const int CIF_NODATA_QUESTION   = 1;
+    cpstr CIF_NODATA_DOT_FIELD      = pstr("\x02" ".");
+    cpstr CIF_NODATA_QUESTION_FIELD = pstr("\x02" "?");
+
+    Category::Category() : io::Stream()  {
+      InitCategory();
+    }
+
+    Category::Category ( cpstr N ) : io::Stream()  {
+      InitCategory();
+      SetCategoryName ( N );
+    }
+
+    Category::Category ( io::RPStream Object ) : io::Stream(Object)  {
+      InitCategory();
+    }
+
+    Category::~Category()  {
+      FreeMemory();
+    }
+
+    void Category::InitCategory()  {
+      name       = NULL;
+      nTags      = 0;
+      tag        = NULL;
+      index      = NULL;
+      nAllocTags = 0;
+    }
+
+    void Category::FreeMemory()  {
+    int i;
+      if (name)  delete[] name;
+      name = NULL;
+      for (i=0;i<nAllocTags;i++)
+        if (tag[i])  delete[] tag[i];
+      FreeVectorMemory ( tag  ,0 );
+      FreeVectorMemory ( index,0 );
+      nTags      = 0;
+      nAllocTags = 0;
+    }
+
+    void Category::SetCategoryName ( cpstr N )  {
+      if (N[0])  CreateCopy ( name,N );
+      else  {
+        CreateCopy ( name,pstr(" ") );
+        name[0] = char(1);  // no category name
+      }
+    }
+
+    void Category::ExpandTags ( int nTagsNew )  {
+    int      i,nAT;
+    psvector tag1;
+    ivector  index1;
+      if (nTagsNew>nAllocTags)  {
+        nAT = nTagsNew + IMin(nAllocTags/2+1,20);
+        GetVectorMemory ( tag1  ,nAT,0 );
+        GetVectorMemory ( index1,nAT,0 );
+        for (i=0;i<nAllocTags;i++)  {
+          tag1  [i] = tag  [i];
+          index1[i] = index[i];
+        }
+        for (i=nAllocTags;i<nAT;i++)  {
+          tag1  [i] = NULL;
+          index1[i] = i;
+        }
+        FreeVectorMemory ( tag  ,0 );
+        FreeVectorMemory ( index,0 );
+        tag        = tag1;
+        index      = index1;
+        nAllocTags = nAT;
+      }
+    }
+
+    pstr Category::GetTag ( int tagNo )  {
+      if ((tagNo>=0) && (tagNo<nTags))  return tag[tagNo];
+      return NULL;
+    }
+
+    void Category::Sort()  {
+    //  Sorts tags for easing the search
+    int i,k;
+      if (nAllocTags>0)  {
+        k = 0;
+        if (!index)
+          GetVectorMemory ( index,nAllocTags,0 );
+        for (i=0;i<nTags;i++)
+          if (tag[i])  {
+            if (k<i)  {
+              tag[k] = tag[i];
+              tag[i] = NULL;
+            }
+            k++;
+          }
+        nTags = k;
+        SortTags ( tag,nTags,index );
+      }
+    }
+
+    void Category::Optimize()  {
+    int      i,k;
+    psvector tag1;
+      k = 0;
+      for (i=0;i<nTags;i++)
+        if (tag[i])  k++;
+      if (k<=0)  FreeMemory();
+      else if (k!=nAllocTags)  {
+        GetVectorMemory  ( tag1,k,0 );
+        FreeVectorMemory ( index,0 );
+        k = 0;
+        for (i=0;i<nTags;i++)
+          if (tag[i])
+            tag1[k++] = tag[i];
+        FreeVectorMemory ( tag,0 );
+        tag        = tag1;
+        nTags      = k;
+        nAllocTags = nTags;
+        Sort();
+      }
+    }
+
+    int  Category::GetTagNo ( cpstr ttag )  {
+    //   Binary search for index of tag ttag in tag[].
+    // Return:
+    //    >=0 : position of the tag found
+    //     <0 : the tag was not found, it could be inserted before
+    //          (-RC-1)th element, where RC is the return value
+    int l1,l2,l,k;
+
+      if (!tag)    return -1;
+
+      if (!index)  Sort();
+
+      l = 0;
+      l1 = 0;
+      l2 = nTags-1;
+      k  = 1;
+      while (l1<l2-1)  {
+        l = (l1+l2)/2;
+        k = strcasecmp ( ttag,tag[index[l]] );
+        if (k<0)      l2 = l;
+        else if (k>0) l1 = l;
+        else {
+          l1 = l;
+          break;
+        }
+      }
+
+      if (k==0)  return index[l];    // is at RCth position
+      k = strcasecmp ( ttag,tag[index[l1]] );
+      if (k==0)  return index[l1];   // is at RCth position
+      if (k<0)   return -1;          // would be at (-RC-1)th position
+      if (l2!=l1)  {
+        k = strcasecmp ( ttag,tag[index[l2]] );
+        if (k==0)  return index[l2]; // is at RCth position
+        if (k>0)   return -2-l2;     // would be at l2+1=(-RC-1)th position
+      }
+
+      return -2-l1;                  // would be at l1+1=(-RC-1)th position
+
+    }
+
+    int  Category::AddTag ( cpstr ttag )  {
+    //  return -1: the tag has been added on the top of array;
+    //             index is added and sorted automatically
+    //        >=0: the tag is already in the array -- its position
+    //             is returned
+    int  i1,i;
+      if (!tag)  {
+        ExpandTags ( 3 );  // get space for first 3 tags
+        CreateCopy ( tag[0],ttag );
+        nTags  = 1;
+        return -nTags;  // the tag has been added on the top of array
+      }
+      i1 = GetTagNo ( ttag );
+      if (i1>=0)  return i1;  // non-negative returns mean that
+                              // the tag is already in the array
+      i1 = -i1-1;  // otherwise the tag has to be added and indexed at here
+      // put new tag on the top of array and update index
+      ExpandTags ( nTags+1 );
+      CreateCopy ( tag[nTags],ttag );
+      for (i=nTags;i>i1;i--)
+        index[i] = index[i-1];
+      index[i1] = nTags;
+      nTags++;
+      return -nTags; // the tag has been added on the top of array
+    }
+
+    void Category::PrintTags()  {
+    int i;
+      Sort();
+      printf ( " Unsorted tags:\n" );
+      for (i=0;i<nTags;i++)
+        if (tag[i])
+          printf ( "  %s.%s\n",name,tag[i] );
+      if (index)  {
+        printf ( " Sorted tags:\n" );
+        for (i=0;i<nTags;i++)
+          if (tag[index[i]])
+            printf ( "  %s.%s\n",name,tag[index[i]] );
+      }
+    }
+
+    bool Category::CheckTags ( cpstr * tagList )  {
+    int i;
+      i = 0;
+      while (tagList[i][0])  {
+        if (GetTagNo(tagList[i])<0)  return false;
+        i++;
+      }
+      return true;
+    }
+
+    void  Category::PutCategoryName ( cpstr newName )  {
+      CreateCopy ( name,newName );
+    }
+
+    void  Category::Copy ( PCategory Category )  {
+    int i;
+      FreeMemory();
+      if (Category)  {
+        CreateCopy ( name,Category->name );
+        nTags      = Category->nTags;
+        nAllocTags = nTags;
+        if (nTags>0) {
+          GetVectorMemory ( tag  ,nAllocTags,0 );
+          GetVectorMemory ( index,nAllocTags,0 );
+          for (i=0;i<nTags;i++)  {
+            tag[i]   = NULL;
+            CreateCopy ( tag[i],Category->tag[i] );
+            index[i] = Category->index[i];
+          }
+        }
+      }
+    }
+
+
+    void Category::write ( io::RFile f )  {
+    int i;
+      if (!index)  Sort();
+      f.CreateWrite ( name   );
+      f.WriteInt    ( &nTags );
+      for (i=0;i<nTags;i++)
+        f.CreateWrite ( tag[i] );
+      f.WriteVector ( index,nTags,0 );
+    }
+
+    void Category::read ( io::RFile f )  {
+    int i;
+      FreeMemory   ();
+      f.CreateRead ( name   );
+      f.ReadInt    ( &nTags );
+      nAllocTags = nTags;
+      if (nTags>0) {
+        GetVectorMemory ( tag,nTags,0 );
+        for (i=0;i<nTags;i++)  {
+          tag[i] = NULL;
+          f.CreateRead ( tag[i] );
+        }
+      }
+      f.CreateReadVector ( index,0 );
+    }
+
+    MakeStreamFunctions(Category)
+
+
+
+    //  ======================  Struct  ===========================
+
+
+    Struct::Struct() : Category() {
+      InitStruct();
+    }
+
+    Struct::Struct ( cpstr N ) : Category(N) {
+      InitStruct();
+    }
+
+    Struct::Struct ( io::RPStream Object ) : Category(Object)  {
+      InitStruct();
+    }
+
+    Struct::~Struct()  {
+      FreeMemory();
+    }
+
+    void Struct::FreeMemory()  {
+    int i;
+      for (i=0;i<nAllocTags;i++)
+        if (field[i]) delete[] field[i];
+      FreeVectorMemory ( field,0 );
+      Category::FreeMemory();
+    }
+
+    void Struct::InitStruct()  {
+      field = NULL;
+    }
+
+    void Struct::Optimize()  {
+    int      i,k;
+    psvector f1;
+      k = 0;
+      for (i=0;i<nTags;i++)
+        if (!tag[i])  {
+          if (field[i])  delete[] field[i];
+          field[i] = NULL;
+        } else if (!field[i])  {
+          delete[] tag[i];
+          tag[i] = NULL;
+        } else
+          k++;
+      if (k<=0)  FreeMemory();
+      else if (k!=nAllocTags)  {
+        f1 = new pstr[k];
+        k  = 0;
+        for (i=0;i<nTags;i++)
+          if (tag[i])
+            f1[k++] = field[i];
+        FreeVectorMemory ( field,0 );
+        field = f1;
+        Category::Optimize();
+      }
+    }
+
+    void Struct::AddField ( cpstr F, cpstr T, bool Concatenate )  {
+    psvector field1;
+    int      i,nAT;
+    pstr     nf;
+
+      nAT = nAllocTags;
+      i   = AddTag ( T );
+
+      if (i<0) {
+        // The tag was not in the list, but has been added on the top
+        // of list. Now expand the field list and put new field on
+        // the top of it.
+        if (nAllocTags>nAT)  {
+          GetVectorMemory ( field1,nAllocTags,0 );
+          for (i=0;i<nTags-1;i++)
+            field1[i] = field[i];
+          for (i=nTags-1;i<nAllocTags;i++)
+            field1[i] = NULL;
+          FreeVectorMemory ( field,0 );
+          field = field1;
+        }
+        i        = nTags-1;
+        field[i] = NULL;
+      }
+
+      if (!F)  {
+        if ((!Concatenate) || (!field[i]))  {
+          CreateCopy ( field[i],pstr(" ?") );
+          field[i][0] = char(2);
+        }
+      } else if ((!Concatenate) || (!field[i]))
+        CreateCopy ( field[i],F );
+      else  {
+        nf = new char[strlen(field[i])+strlen(F)+1];
+        strcpy ( nf,field[i] );
+        strcat ( nf,F        );
+        delete[] field[i];
+        field[i] = nf;
+      }
+
+    }
+
+    pstr Struct::GetField ( int tagNo )  {
+      if ((tagNo>=0) && (tagNo<nTags))  return field[tagNo];
+      return NULL;
+    }
+
+    int  Struct::GetString ( pstr & S, cpstr TName,
+                                   bool Remove )  {
+    int k = GetTagNo ( TName );
+      if (S)  delete[] S;
+      S = NULL;
+      if (!field)     return CIFRC_NoField;
+      if (k<0)        return CIFRC_NoTag;
+      if (!field[k])  return CIFRC_NoField;
+      if (field[k][0]==char(2))  {
+        if (Remove)  {
+          delete[] field[k];
+          field[k] = NULL;
+        }
+      } else if (Remove)  {
+        S = field[k];
+        field[k] = NULL;
+      } else
+        CreateCopy ( S,field[k] );
+      return 0;
+    }
+
+    pstr Struct::GetString ( cpstr TName, int & RC )  {
+    int k = GetTagNo ( TName );
+      if (k<0)  {
+        RC = CIFRC_NoTag;
+        return NULL;
+      }
+      if (!field)  {
+        RC = CIFRC_NoField;
+        return NULL;
+      }
+      if (!field[k])  {
+        RC = CIFRC_NoField;
+        return NULL;
+      }
+      RC = 0;
+      if (field[k][0]==char(2))  return NULL;
+      return field[k];
+    }
+
+    int  Struct::DeleteField ( cpstr TName )  {
+    int k = GetTagNo ( TName );
+      if ((k>=0) && (field)) {
+        if (field[k])  delete[] field[k];
+        field[k] = NULL;
+      }
+      return k;
+    }
+
+    int  Struct::GetReal ( realtype & R, cpstr TName,
+                                 bool Remove )  {
+    pstr endptr;
+    int  RC;
+    int  k = GetTagNo ( TName );
+      R = 0.0;
+      if (!field)                return CIFRC_NoField;
+      if (k<0)                   return CIFRC_NoTag;
+      if (!field[k])             return CIFRC_NoField;
+      if (field[k][0]==char(2))  return CIFRC_NoData;
+      R = strtod ( field[k],&endptr );
+      if (endptr==field[k])  RC = CIFRC_WrongFormat;
+      else  {
+        RC = 0;
+        if (Remove)  {
+          delete[] field[k];
+          field[k] = NULL;
+        }
+      }
+      return RC;
+    }
+
+    int  Struct::GetInteger ( int & I, cpstr TName,
+                                    bool Remove )  {
+    pstr endptr;
+    int  RC;
+    int  k = GetTagNo ( TName );
+      I = 0;
+      if (!field)                return CIFRC_NoField;
+      if (k<0)                   return CIFRC_NoTag;
+      if (!field[k])             return CIFRC_NoField;
+      if (field[k][0]==char(2))  {
+        if (field[k][1]=='.')  I = MinInt4;
+        return CIFRC_NoData;
+      }
+      I = mround ( strtod(field[k],&endptr) );
+      if (endptr==field[k])  RC = CIFRC_WrongFormat;
+      else  {
+        RC = 0;
+        if (Remove)  {
+          delete[] field[k];
+          field[k] = NULL;
+        }
+      }
+      return RC;
+    }
+
+
+    void Struct::PutString ( cpstr S, cpstr T,
+                                   bool NonBlankOnly )  {
+    pstr p;
+      if (!S)  PutNoData ( CIF_NODATA_QUESTION,T );
+      else  {
+        p = pstr(S);
+        if (NonBlankOnly)
+          while (*p==' ')  p++;
+        if (!(*p))  PutNoData ( CIF_NODATA_DOT,T );
+              else  AddField  ( S,T,false );
+      }
+    }
+
+    void Struct::PutDate ( cpstr T )  {
+    time_t t;
+    tm *   tstruct;
+     char   S[100];
+      t       = time ( NULL );
+      tstruct = localtime(&t);
+      if (tstruct)
+            sprintf ( S,"%4i-%02i-%02i",
+                tstruct->tm_year+1900,tstruct->tm_mon+1,tstruct->tm_mday );
+      else  strcpy  ( S,"YYYY-MM-DD" );
+      AddField ( S,T,false );
+    }
+
+
+    void Struct::PutNoData ( int NoDataType, cpstr T )  {
+    char S[10];
+      S[0] = char(2);
+      if (NoDataType==CIF_NODATA_DOT)  S[1] = '.';
+                                 else  S[1] = '?';
+      S[2] = char(0);
+      AddField ( S,T,false );
+    }
+
+
+    void Struct::PutReal ( realtype R, cpstr T, int prec )  {
+    char rS[100];
+      sprintf  ( rS,"%.*g",prec,R );
+      AddField ( rS,T,false );
+    }
+
+    void Struct::PutReal ( realtype R, cpstr T, cpstr format )  {
+    char rS[100];
+      sprintf  ( rS,format,R );
+      AddField ( DelSpaces(rS,' '),T,false );
+    }
+
+    void Struct::PutInteger ( int I, cpstr T )  {
+    char iS[100];
+      if (I>MinInt4)  {
+        sprintf  ( iS,"%i",I );
+        AddField ( iS,T,false );
+      } else
+        PutNoData ( CIF_NODATA_DOT,T );
+    }
+
+
+
+    #define  NODATA_Q  pstr("?")
+    #define  NODATA_P  pstr(".")
+
+    bool Struct::WriteMMCIFStruct ( cpstr FName,
+                                    io::GZ_MODE gzipMode )  {
+    io::File f;
+      f.assign ( FName,true,false,gzipMode );
+      if (f.rewrite())  {
+        WriteMMCIF ( f );
+        f.shut();
+        return true;
+      } else
+        return false;
+    }
+
+    #define _max_output_line_width 256
+
+    void Struct::WriteMMCIF ( io::RFile f )  {
+    int   i,j,k,l,m,n;
+    pstr  F;
+
+      // calculate maximal length of tags
+      l = 0;
+      for (i=0;i<nTags;i++)
+        l = IMax(l,strlen(tag[i]));
+      l += 1;  // add one space separator
+
+      // calculate maximal space left for data
+      m  = _max_output_line_width - l;
+      // subtract category name width
+      if (name[0]!=char(1))  m -= strlen(name);
+
+      // start outout
+      f.LF();
+      for (i=0;i<nTags;i++)  {  // for each tag
+
+        // print category name, if not hidden, and dot
+        if (name[0]!=char(1))  {
+          f.Write ( name      );
+          f.Write ( pstr(".") );
+        }
+
+        // print tag, checking for duplicate tag flag
+        F = strchr ( tag[i],'\1' );
+        if (F)  {
+          *F = char(0);
+          f.Write ( tag[i] );
+          *F = '\1';
+        } else
+          f.Write ( tag[i] );
+
+        // print field
+        if (field[i])  {  // field is defined
+          F = field[i];
+          if (strchr(F,'\n') || strstr(F,"\" "))  {
+            f.Write ( pstr("\n;")   );
+            f.Write ( F             );
+            f.Write ( pstr("\n;\n") );
+          } else {
+            n = strlen(F);
+            if (n>m)  // wrap around if field is too long
+              f.Write ( pstr("\n ") );
+            else {
+              k = l-strlen(tag[i]);
+              for (j=0;j<k;j++)
+                f.Write ( pstr(" ") );
+            }
+            if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) ||
+                strchr(F,' '))  {
+              f.Write ( pstr("\"")   );
+              f.Write ( field[i]     );
+              f.Write ( pstr("\"\n") );
+            } else if (field[i][0]==char(2))  {
+              f.WriteLine ( &(field[i][1]) );
+            } else if (!field[i][0])  {
+              f.WriteLine ( NODATA_P );
+            } else
+              f.WriteLine ( field[i] );
+          }
+
+        } else  {  // field if not defined, put question mark
+
+          k = l-strlen(tag[i]);
+          for (j=0;j<k;j++)
+            f.Write ( pstr(" ") );
+          f.WriteLine ( NODATA_Q );
+
+        }
+
+      }
+
+    }
+
+    void Struct::Copy ( PCategory Struct )  {
+    int i;
+      Category::Copy ( Struct );
+      if (nTags>0)  {
+        GetVectorMemory ( field,nTags,0 );
+        for (i=0;i<nTags;i++)  {
+          field[i] = NULL;
+          CreateCopy ( field[i],PStruct(Struct)->field[i] );
+        }
+      }
+    }
+
+    void Struct::write ( io::RFile f )  {
+    int i;
+      Category::write ( f );
+      for (i=0;i<nTags;i++)
+        f.CreateWrite ( field[i] );
+    }
+
+    void Struct::read ( io::RFile f )  {
+    int i;
+      Category::read ( f );
+      if (nTags>0)  {
+        GetVectorMemory ( field,nTags,0 );
+        for (i=0;i<nTags;i++)  {
+          field[i] = NULL;
+          f.CreateRead ( field[i] );
+        }
+      }
+    }
+
+
+    MakeStreamFunctions(Struct)
+
+
+
+    //  ======================  Loop  ==============================
+
+
+    Loop::Loop() : Category()  {
+      InitLoop();
+    }
+
+    Loop::Loop ( cpstr N ) : Category(N)  {
+      InitLoop();
+    }
+
+    Loop::Loop ( io::RPStream Object ) : Category(Object)  {
+      InitLoop();
+    }
+
+    Loop::~Loop()  {
+      FreeMemory();
+    }
+
+    void Loop::InitLoop()  {
+      nRows      = 0;
+      field      = NULL;
+      iColumn    = 0;
+      nAllocRows = 0;
+    }
+
+    void Loop::FreeMemory()  {
+      DeleteFields();
+      Category::FreeMemory();
+    }
+
+    void Loop::Optimize()  {
+    int      i,j,nT,nR,k,m;
+    bool  empty;
+    psmatrix f1;
+
+      if (!field)  {
+        Category::Optimize();  // optimize tags
+        return;
+      }
+
+      // first check for empty columns
+      nT = 0;
+      for (i=0;i<nTags;i++)
+        if (!tag[i])  {
+          for (j=0;j<nRows;j++)  // delete ith column of field
+            if (field[j])  {
+              if (field[j][i])
+                delete[] field[j][i];
+              field[j][i] = NULL;
+            }
+        } else  {
+          empty = true;
+          j = 0;
+          while ((j<nRows) && empty)  {  // check if ith column is empty
+            if (field[j])
+              empty = !field[j][i];
+            j++;
+          }
+          if (empty)  {    // if ith column is empty, delete its tag
+            delete[] tag[i];
+            tag[i] = NULL;
+          } else           // otherwise count ith tag
+            nT++;
+        }
+
+      // now check for empty rows
+      nR = 0;
+      for (j=0;j<nRows;j++)
+        if (field[j])  {
+          i = 0;
+          while ((i<nTags) && (!field[j][i])) i++;
+          if (i>=nTags)  {
+            delete[] field[j];  // delete empty row
+            field[j] = NULL;
+          } else
+            nR++;             // count non-empty row
+        }
+      if ((nT<=0) || (nR<=0))
+        FreeMemory();  // the loop is completely empty
+      else if ((nT!=nTags) || (nR!=nAllocRows))  {
+        f1 = new psvector[nR];
+        m  = 0;
+        for (j=0;j<nRows;j++)
+          if (field[j])  {
+            f1[m] = new pstr[nT];
+            k = 0;
+            for (i=0;i<nTags;i++)
+              if (tag[i])
+                f1[m][k++] = field[j][i];
+            m++;
+            delete[] field[j];
+          }
+        if (field)  delete[] field;
+        field = f1;
+        nRows = nR;
+        nAllocRows = nRows;
+        Category::Optimize();  // optimize tags
+      }
+
+    }
+
+    void Loop::DeleteFields()  {
+    int i,j;
+      if (field)  {
+        for (i=0;i<nAllocRows;i++)
+          if (field[i])  {
+            for (j=0;j<nTags;j++)
+              if (field[i][j])  delete[] field[i][j];
+            delete[] field[i];
+          }
+        delete[] field;
+        field      = NULL;
+        nRows      = 0;
+        nAllocRows = 0;
+      }
+    }
+
+    void Loop::AddLoopTag ( cpstr T, bool Remove )  {
+    psmatrix  f1;
+    int       i,j,nT1;
+      if (Remove)  {
+        DeleteFields();
+        AddTag ( T );
+      } else  {
+        f1    = field;
+        field = NULL;
+        i     = AddTag ( T );
+        if ((f1) && (i<0))  {
+          // The tag was added on the top of tag array. Create
+          // and fill new fields.
+          field = new psvector[nAllocRows];
+          nT1   = nTags-1;
+          for (i=0;i<nAllocRows;i++)
+            if (f1[i])  {
+              field[i] = new pstr[nTags];
+              for (j=0;j<nT1;j++)
+                field[i][j] = f1[i][j];
+              field[i][nT1] = NULL;
+              f1[i] = NULL;
+            } else
+              field[i] = NULL;
+          delete[] f1;
+        } else
+          // The tag was already in the category. Just restore fields.
+          field = f1;
+      }
+    }
+
+
+    void Loop::ExpandRows ( int nRowsNew )  {
+    int      nAR,i;
+    psmatrix field1;
+      if (nRowsNew>nAllocRows)  {
+        nAR    = nRowsNew + IMin(nAllocRows/2+10,2000);
+        field1 = new psvector[nAR];
+        for (i=0;i<nAllocRows;i++)
+          field1[i] = field[i];
+        for (i=nAllocRows;i<nAR;i++)
+          field1[i] = NULL;
+        if (field)  delete[] field;
+        field      = field1;
+        nAllocRows = nAR;
+      }
+    }
+
+    void Loop::AddString ( cpstr S, bool NonBlankOnly )  {
+    int  i;
+    pstr p;
+      if (!S)  AddNoData ( CIF_NODATA_QUESTION );
+      else  {
+        p = pstr(S);
+        if (NonBlankOnly)
+          while (*p==' ')  p++;
+        if (!(*p))  AddNoData ( CIF_NODATA_DOT );
+        else  {
+          if (iColumn==0)  {  // start a new row
+            ExpandRows ( nRows+1 );
+            field[nRows] = new pstr[nTags];
+            for (i=0;i<nTags;i++)
+              field[nRows][i] = NULL;
+            nRows++;
+          }
+          CreateCopy ( field[nRows-1][iColumn],S );
+          iColumn++;
+          if (iColumn>=nTags) iColumn = 0;
+        }
+      }
+    }
+
+    void Loop::AddNoData ( int NoDataType )  {
+    char S[10];
+      S[0] = char(2);
+      if (NoDataType==CIF_NODATA_DOT)  S[1] = '.';
+                                 else  S[1] = '?';
+      S[2] = char(0);
+      AddString ( S );
+    }
+
+    void Loop::AddReal ( realtype R, int prec )  {
+    char rS[100];
+      sprintf ( rS,"%.*g",prec,R );
+      AddString ( rS );
+    }
+
+    void Loop::AddReal ( realtype R, cpstr format )  {
+    char rS[100];
+      sprintf ( rS,format,R );
+      AddString ( DelSpaces(rS,' ') );
+    }
+
+    void Loop::AddInteger ( int I )  {
+    char iS[100];
+      if (I>MinInt4)  {
+        sprintf ( iS,"%i",I );
+        AddString ( iS );
+      } else
+        AddNoData ( CIF_NODATA_DOT );
+    }
+
+
+    pstr Loop::GetField ( int rowNo, int tagNo )  {
+      if ((tagNo>=0) && (tagNo<nTags) &&
+          (rowNo>=0) && (rowNo<nRows))  {
+        if (field[rowNo])  return field[rowNo][tagNo];
+      }
+      return NULL;
+    }
+
+    int  Loop::GetString ( pstr & S, cpstr TName, int nrow,
+                                 bool Remove)  {
+    int k = GetTagNo ( TName );
+      if (S)  delete[] S;
+      S = NULL;
+      if (k<0)                       return CIFRC_NoTag;
+      if ((nrow<0) || (nrow>=nRows)) return CIFRC_WrongIndex;
+      if (!field[nrow])              return CIFRC_NoField;
+      if (!field[nrow][k])           return CIFRC_NoField;
+      if (field[nrow][k][0]==char(2))  {
+        if (Remove)  {
+          delete[] field[nrow][k];
+          field[nrow][k] = NULL;
+        }
+      } else if (Remove)  {
+        S = field[nrow][k];
+        field[nrow][k] = NULL;
+      } else
+        CreateCopy ( S,field[nrow][k] );
+      return 0;
+    }
+
+    pstr Loop::GetString ( cpstr TName, int nrow, int & RC )  {
+    int k = GetTagNo ( TName );
+      if (k<0)  {
+        RC = CIFRC_NoTag;
+        return NULL;
+      }
+      if ((nrow<0) || (nrow>=nRows))  {
+        RC = CIFRC_WrongIndex;
+        return NULL;
+      }
+      if (!field[nrow])  {
+        RC = CIFRC_NoField;
+        return NULL;
+      }
+      if (!field[nrow][k])  {
+        RC = CIFRC_NoField;
+        return NULL;
+      }
+      RC = 0;
+      // char(2) means the field was either '.' or '?'
+      if (field[nrow][k][0]==char(2))  return NULL;
+      return field[nrow][k];
+    }
+
+    //  CopyString() does nothing if RC is not 0
+    void Loop::CopyString   ( pstr  buf,   int maxlength,
+                                    cpstr TName, int nrow, int & RC )  {
+    pstr p;
+    int  k;
+
+      if (RC)  return;
+
+      k = GetTagNo ( TName );
+      if (k<0)  {
+        RC = CIFRC_NoTag;
+        buf[0] = char(0);
+        return;
+      }
+      if ((nrow<0) || (nrow>=nRows))  {
+        RC = CIFRC_WrongIndex;
+        buf[0] = char(0);
+        return;
+      }
+      if (!field[nrow])  {
+        RC = CIFRC_NoField;
+        buf[0] = char(0);
+        return;
+      }
+      p = field[nrow][k];
+      if (!p)  {
+        RC = CIFRC_NoField;
+        buf[0] = char(0);
+        return;
+      }
+
+      // char(2) means the field was either '.' or '?'
+      if (p[0]==char(2))  {
+        buf[0] = p[0];
+        buf[1] = char(0);
+      } else
+        strncpy ( buf,p,IMin(maxlength,strlen(p)+1) );
+
+    }
+
+
+
+    int Loop::DeleteField ( cpstr TName, int nrow )  {
+    int k = GetTagNo ( TName );
+      if (k<0)  return CIFRC_NoTag;
+      if ((nrow<0) || (nrow>=nRows))
+                return CIFRC_WrongIndex;
+      if (field[nrow])  {
+        if (field[nrow][k])  delete[] field[nrow][k];
+        field[nrow][k] = NULL;
+      }
+      return k;
+    }
+
+    int Loop::DeleteRow ( int nrow )  {
+    int i;
+      if ((nrow<0) || (nrow>=nRows))
+                return CIFRC_WrongIndex;
+      if (field[nrow])  {
+        for (i=0;i<nTags;i++)
+          if (field[nrow][i])  {
+            delete[] field[nrow][i];
+            field[nrow][i] = NULL;
+          }
+        delete[] field[nrow];
+        field[nrow] = NULL;
+      }
+      return 0;
+    }
+
+    int  Loop::GetReal ( realtype & R, cpstr TName, int nrow,
+                               bool Remove )  {
+    pstr endptr;
+    int  k = GetTagNo ( TName );
+      if (k<0)  return CIFRC_NoTag;
+      if ((nrow<0) || (nrow>=nRows))
+                return CIFRC_WrongIndex;
+      R = 0.0;
+      if (!field[nrow])                return CIFRC_NoField;
+      if (!field[nrow][k])             return CIFRC_NoField;
+      if (field[nrow][k][0]==char(2))  return CIFRC_NoField;
+      R = strtod ( field[nrow][k],&endptr );
+      if (endptr==field[nrow][k])      return CIFRC_WrongFormat;
+      if (Remove)  {
+        delete[] field[nrow][k];
+        field[nrow][k] = NULL;
+      }
+      return 0;
+    }
+
+    void Loop::CopyReal ( realtype & R, cpstr TName, int nrow,
+                                int & RC )  {
+    pstr endptr;
+    int  k;
+
+      if (RC)  return;
+
+    //  R = 0.0;
+      k = GetTagNo ( TName );
+
+      if (k<0)                              RC = CIFRC_NoTag;
+      else if ((nrow<0) || (nrow>=nRows))   RC = CIFRC_WrongIndex;
+      else if (!field[nrow])                RC = CIFRC_NoField;
+      else if (!field[nrow][k])             RC = CIFRC_NoField;
+      else if (field[nrow][k][0]==char(2))  RC = CIFRC_NoField;
+      else  {
+        R = strtod ( field[nrow][k],&endptr );
+        if (endptr==field[nrow][k])  RC = CIFRC_WrongFormat;
+      }
+
+    }
+
+    void Loop::CopyInteger ( int & I, cpstr TName, int nrow,
+                                   int & RC )  {
+    pstr endptr;
+    int  k;
+
+      if (RC)  return;
+
+      I = 0;
+      k = GetTagNo ( TName );
+
+      if (k<0)                              RC = CIFRC_NoTag;
+      else if ((nrow<0) || (nrow>=nRows))   RC = CIFRC_WrongIndex;
+      else if (!field[nrow])                RC = CIFRC_NoField;
+      else if (!field[nrow][k])             RC = CIFRC_NoField;
+      else if (field[nrow][k][0]==char(2))  RC = CIFRC_NoField;
+      else  {
+        I = mround ( strtod ( field[nrow][k],&endptr ) );
+        if (endptr==field[nrow][k])  RC = CIFRC_WrongFormat;
+      }
+
+    }
+
+    int  Loop::GetInteger ( int & I, cpstr TName, int nrow,
+                                  bool Remove )  {
+    pstr endptr;
+    int  k = GetTagNo ( TName );
+      if (k<0)  return CIFRC_NoTag;
+      if ((nrow<0) || (nrow>=nRows))
+                return CIFRC_WrongIndex;
+      I = 0;
+      if (!field[nrow])                return CIFRC_NoField;
+      if (!field[nrow][k])             return CIFRC_NoField;
+      if (field[nrow][k][0]==char(2))  {
+        if (field[nrow][k][1]=='.')  I = MinInt4;
+        return CIFRC_NoField;
+      }
+      I = mround ( strtod(field[nrow][k],&endptr) );
+      if (endptr==field[nrow][k])      return CIFRC_WrongFormat;
+      if (Remove)  {
+        delete[] field[nrow][k];
+        field[nrow][k] = NULL;
+      }
+      return 0;
+    }
+
+
+    int  Loop::GetSVector ( psvector & S, cpstr TName,
+                                  int i1, int i2, bool Remove )  {
+    int j,k,r1,r2;
+      r1 = IMin(i1,i2);
+      r2 = IMin(IMax(i1,i2),nRows-1);
+      if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
+      k = GetTagNo ( TName );
+      if (k<0)  return CIFRC_NoTag;
+      if (!S)
+        GetVectorMemory ( S,r2-r1+1,r1 );
+      if (Remove)  {
+        for (j=r1;j<=r2;j++)
+          if (field[j])  {
+            S[j] = field[j][k];
+            field[j][k] = NULL;
+            if (S[j])  {
+              if (S[j][0]==char(2))  {
+                delete[] S[j];
+                S[j] = NULL;
+              }
+            }
+          } else
+            S[j] = NULL;
+      } else  {
+        for (j=r1;j<=r2;j++)  {
+          S[j] = NULL;
+          if (field[j])  {
+            if (field[j][k])  {
+              if (field[j][k][0]!=char(2))
+                CreateCopy ( S[j],field[j][k] );
+            }
+          }
+        }
+      }
+      return 0;
+    }
+
+    int  Loop::GetRVector ( rvector & R, cpstr TName,
+                                  int i1, int i2, bool Remove )  {
+    int  j,k,r1,r2,RC;
+    pstr endptr;
+      r1 = IMin(i1,i2);
+      r2 = IMin(IMax(i1,i2),nRows-1);
+      if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
+      k = GetTagNo ( TName );
+      if (k<0)  return CIFRC_NoTag;
+      if (!R)
+        GetVectorMemory ( R,r2-r1+1,r1 );
+      RC = 0;
+      for (j=r1;j<=r2;j++)  {
+        R[j] = 0.0;
+        if (field[j])  {
+          if (field[j][k])  {
+            R[j] = strtod ( field[j][k],&endptr );
+            if (endptr==field[j][k])  RC = CIFRC_WrongFormat;
+            if (Remove)  {
+              delete[] field[j][k];
+              field[j][k] = NULL;
+            }
+          }
+        }
+      }
+      return RC;
+    }
+
+    int  Loop::GetIVector ( ivector & I, cpstr TName,
+                                  int i1, int i2, bool Remove )  {
+    int  j,k,r1,r2,RC;
+    pstr endptr;
+      r1 = IMin(i1,i2);
+      r2 = IMin(IMax(i1,i2),nRows-1);
+      if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex;
+      k = GetTagNo ( TName );
+      if (k<0)    return CIFRC_NoTag;
+      if (!I)
+        GetVectorMemory ( I,r2-r1+1,r1 );
+      RC = 0;
+      for (j=r1;j<=r2;j++)  {
+        I[j] = 0;
+        if (field[j])  {
+          if (field[j][k])  {
+            I[j] = mround ( strtod(field[j][k],&endptr) );
+            if (endptr==field[j][k]) RC = CIFRC_WrongFormat;
+            if (Remove)  {
+              delete[] field[j][k];
+              field[j][k] = NULL;
+            }
+          }
+        }
+      }
+      return RC;
+    }
+
+
+    void Loop::PutString ( cpstr S, cpstr T, int nrow )  {
+    psmatrix field1;
+    int      nT,nR,iT,i,j;
+      nT = nTags;
+      nR = nRows;
+      iT = AddTag ( T );
+      if (iT<0)  iT = nTags-1;
+      if (nTags>nT)  {
+        // a new tag has been added; all field must be reallocated.
+        nRows      = IMax(nR,nrow+1);  // nrow is indexed like 0,1,...
+        nAllocRows = IMax(nR,nrow+IMin(nR/2+1,2000));
+        field1     = new psvector[nAllocRows];
+        for (i=0;i<nR;i++)
+          if (field[i])  {
+            field1[i] = new pstr[nTags];
+            for (j=0;j<nT;j++)
+              field1[i][j] = field[i][j];
+            for (j=nT;j<nTags;j++)
+              field1[i][j] = NULL;
+            delete[] field[i];
+          } else
+            field1[i] = NULL;
+        for (i=nR;i<nRows;i++)
+          field1[i] = NULL;
+        if (field)  delete[] field;
+        field = field1;
+      } else if (nrow>=nR)  {
+        // only new rows are to be added
+        ExpandRows ( nrow+1 );
+        nRows++;
+      }
+      if (!field[nrow])  {
+        field[nrow] = new pstr[nTags];
+        for (j=0;j<nTags;j++)
+          field[nrow][j] = NULL;
+      }
+      CreateCopy ( field[nrow][iT],S );
+      iColumn = iT+1;
+      if (iColumn>=nTags) iColumn = 0;
+    }
+
+
+    void Loop::PutNoData ( int NoDataType, cpstr T, int nrow )  {
+    char S[10];
+      S[0] = char(2);
+      if (NoDataType==CIF_NODATA_DOT)  S[1] = '.';
+                                 else  S[1] = '?';
+      S[2] = char(0);
+      PutString ( S,T,nrow );
+    }
+
+
+    void Loop::PutReal ( realtype R, cpstr T, int nrow, int prec )  {
+    char rS[100];
+      sprintf ( rS,"%.*g",prec,R );
+      PutString ( rS,T,nrow );
+    }
+
+    void Loop::PutReal ( realtype R, cpstr T, int nrow,
+                               cpstr format )  {
+    char rS[100];
+      sprintf ( rS,format,R );
+      PutString ( DelSpaces(rS,' '),T,nrow );
+    }
+
+    void Loop::PutInteger ( int I, cpstr T, int nrow )  {
+    char iS[100];
+      if (I>MinInt4)  {
+        sprintf ( iS,"%i",I );
+        PutString ( iS,T,nrow );
+      } else
+        PutNoData ( CIF_NODATA_DOT,T,nrow );
+    }
+
+    void Loop::PutSVector ( psvector S, cpstr T, int i1, int i2 )  {
+    int i,j,k;
+      PutString ( S[i2],T,i2 );
+      if (iColumn==0)  k = nTags-1;
+                 else  k = iColumn-1;
+      for (i=i2-1;i>=i1;i--)  {
+        if (!field[i])  {
+          field[i] = new pstr[nTags];
+          for (j=0;j<nTags;j++)
+            field[i][j] = NULL;
+        }
+        CreateCopy ( field[i][k],S[i] );
+      }
+    }
+
+    void Loop::PutRVector ( rvector R, cpstr T,
+                                  int i1, int i2, int prec )  {
+    int  i,j,k;
+    char rS[100];
+      PutReal ( R[i2],T,i2,prec );
+      if (iColumn==0)  k = nTags-1;
+                 else  k = iColumn-1;
+      for (i=i2-1;i>=i1;i--)  {
+        if (!field[i])  {
+          field[i] = new pstr[nTags];
+          for (j=0;j<nTags;j++)
+            field[i][j] = NULL;
+        }
+        sprintf ( rS,"%.*g",prec,R[i] );
+        CreateCopy ( field[i][k],rS );
+      }
+    }
+
+    void Loop::PutIVector ( ivector I, cpstr T,
+                                  int i1, int i2 )  {
+    int  l,j,k;
+    char iS[100];
+      PutInteger ( I[i2],T,i2 );
+      if (iColumn==0)  k = nTags-1;
+                 else  k = iColumn-1;
+      for (l=i2-1;l>=i1;l--)  {
+        if (!field[l])  {
+          field[l] = new pstr[nTags];
+          for (j=0;j<nTags;j++)
+            field[l][j] = NULL;
+        }
+        sprintf ( iS,"%i",I[l] );
+        CreateCopy ( field[l][k],iS );
+      }
+    }
+
+    bool Loop::WriteMMCIFLoop ( cpstr FName, io::GZ_MODE gzipMode )  {
+    io::File f;
+      f.assign ( FName,true,false,gzipMode );
+      if (f.rewrite())  {
+        WriteMMCIF ( f );
+        f.shut();
+        return true;
+      } else
+        return false;
+    }
+
+    void Loop::WriteMMCIF ( io::RFile f )  {
+    int     i,j,k,m,n;
+    ivector l;
+    pstr    F;
+
+      // write loop keyword
+      f.Write ( pstr("\nloop_\n") );
+
+      GetVectorMemory ( l,nTags,0 );
+      k = 0;
+      for (i=0;i<nTags;i++)  {
+        if (name[0]!=char(1))  {
+          f.Write ( name      );
+          f.Write ( pstr(".") );
+        }
+        F = strchr ( tag[i],'\1' );
+        if (F)  {
+          *F = char(0);
+          f.WriteLine ( tag[i] );
+          *F = '\1';
+        } else
+          f.WriteLine ( tag[i] );
+        l[i] = 0;
+        for (j=0;j<nRows;j++)
+          if (field[j])  {
+            if (field[j][i])  {
+              F = field[j][i];
+              if (strchr(F,'\n') || strstr(F,"\" "))
+                                       l[i] = 10001;
+              else if (F[0]==char(2))  l[i] = IMax(l[i],1);
+              else if (((F[0]=='.') || (F[0]=='?')) &&
+                       (!F[1]))        l[i] = IMax(l[i],3);
+              else  {
+                if (strchr(F,' '))  m = 2;
+                              else  m = 0;
+                l[i] = IMax(l[i],strlen(F)+m);
+              }
+            }
+          }
+        l[i] = IMax(l[i],1);
+        k += l[i]+1;
+        if (k>_max_output_line_width)  {
+          l[i] = -l[i];
+          k = 0;
+        }
+      }
+      for (i=0;i<nRows;i++)  {
+        m = 0;  // counts symbols in the string
+        k = 0;  // rest of left-aligned fields to fill with spaces
+        for (j=0;j<nTags;j++)  {
+          n = k;
+          k = l[j];   // length of the field
+          if (k<0)  k = -k;
+          m += k+1;
+          if (m>_max_output_line_width)  {
+            f.LF();
+            m = k+1;
+          } else
+            while (n>0) {
+              f.Write ( pstr(" ") );
+              n--;
+            }
+          if (field[i])  {
+            if (field[i][j])  {
+              F = field[i][j];
+              if (k>10000)  {
+                if (F[0]==char(2))  {
+                  f.Write     ( pstr(" ") );
+                  f.WriteLine ( &(F[1])   );
+                } else if (!F[0])  {
+                  f.Write     ( pstr(" ") );
+                  f.WriteLine ( NODATA_P  );
+                } else  {
+                  f.Write     ( pstr(";") );
+                  f.WriteLine ( F         );
+                  f.WriteLine ( pstr(";") );
+                }
+                m = 0;
+                k = 0;
+              } else if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) ||
+                         strchr(F,' '))  {
+                f.Write ( pstr(" \"") );
+                f.Write ( F           );
+                f.Write ( pstr("\"")  );
+                k -= strlen(F)+2;
+              } else if (F[0]==char(2))  {
+                f.Write ( pstr(" ") );
+                f.Write ( &(F[1])   );
+                k--;
+              } else if (!F[0])  {
+                f.Write ( pstr(" ") );
+                f.Write ( NODATA_P  );
+                k--;
+              } else  {
+                f.Write ( pstr(" ") );
+                f.Write ( F         );
+                k -= strlen(F);
+              }
+            } else  {
+              f.Write ( pstr(" ") );
+              f.Write ( NODATA_Q  );
+              k--;
+            }
+          } else  {
+            f.Write ( pstr(" ") );
+            f.Write ( NODATA_Q  );
+            k--;
+          }
+        }
+        if (m) f.LF();
+      }
+
+    }
+
+
+    void Loop::Copy ( PCategory Loop )  {
+    int i,j;
+      Category::Copy ( Loop );
+      nRows      = PLoop(Loop)->nRows;
+      nAllocRows = nRows;
+      if ((nTags>0) && (nRows>0))  {
+        field = new psvector[nRows];
+        for (i=0;i<nRows;i++)  {
+          if (PLoop(Loop)->field[i])  {
+            field[i] = new pstr[nTags];
+            for (j=0;j<nTags;j++)  {
+              field[i][j] = NULL;
+              CreateCopy ( field[i][j],PLoop(Loop)->field[i][j] );
+            }
+          } else
+            field[i] = NULL;
+        }
+      }
+      iColumn = PLoop(Loop)->iColumn;
+    }
+
+
+    void Loop::write ( io::RFile f )  {
+    int i,j;
+      Category::write ( f );
+      f.WriteInt ( &nRows );
+      if ((nTags>0) && (nRows>0))
+        for (i=0;i<nRows;i++)
+          if (field[i])  {
+            j = 1;
+            f.WriteInt ( &j );
+            for (j=0;j<nTags;j++)
+              f.CreateWrite ( field[i][j] );
+          } else  {
+            j = 0;
+            f.WriteInt ( &j );
+          }
+      f.WriteInt ( &iColumn );
+    }
+
+    void Loop::read ( io::RFile f )  {
+    int i,j;
+      Category::read ( f );
+      f.ReadInt ( &nRows );
+      nAllocRows = nRows;
+      if ((nTags>0) && (nRows>0))  {
+        field = new psvector[nRows];
+        for (i=0;i<nRows;i++)  {
+          f.ReadInt ( &j );
+          if (j)  {
+            field[i] = new pstr[nTags];
+            for (j=0;j<nTags;j++)  {
+              field[i][j] = NULL;
+              f.CreateRead ( field[i][j] );
+            }
+          } else
+            field[i] = NULL;
+        }
+      }
+      f.ReadInt ( &iColumn );
+    }
+
+
+    MakeStreamFunctions(Loop)
+
+
+
+    //  ======================  Data  =============================
+
+
+    Data::Data() : io::Stream()  {
+      InitData();
+    }
+
+    Data::Data ( cpstr N ) : io::Stream()  {
+      InitData();
+      CreateCopy ( name,N );
+    }
+
+    Data::Data ( io::RPStream Object ) : io::Stream(Object)  {
+      InitData();
+    }
+
+    Data::~Data() {
+      FreeMemory(0);
+    }
+
+    void Data::InitData()  {
+      name         = NULL;
+      nCategories  = 0;
+      Category     = NULL;
+      index        = NULL;
+      flags        = 0;
+      Warning      = 0;
+      loopNo       = 0;
+      tagNo        = 0;
+      WrongCat     = NULL;
+      WrongTag     = NULL;
+      nWrongFields = 0;
+    }
+
+    void Data::FreeMemory ( int key )  {
+    int i;
+      if (name)  delete[] name;
+      name = NULL;
+      if (Category)  {
+        for (i=0;i<nCategories;i++)
+          if (Category[i]) delete Category[i];
+        delete[] Category;
+        Category = NULL;
+      }
+      nCategories = 0;
+      FreeVectorMemory ( index,0 );
+      if (key==0)  FreeWrongFields();
+    }
+
+    void Data::FreeWrongFields()  {
+    int i;
+      if (WrongCat)  {
+        for (i=0;i<nWrongFields;i++)
+          if (WrongCat[i])  delete[] WrongCat[i];
+        delete[] WrongCat;
+      }
+      if (WrongTag)  {
+        for (i=0;i<nWrongFields;i++)
+          if (WrongTag[i])  delete[] WrongTag[i];
+        delete[] WrongTag;
+      }
+      WrongCat     = NULL;
+      WrongTag     = NULL;
+      nWrongFields = 0;
+    }
+
+
+    void  Data::SetPrintWarnings ( bool SPW )  {
+      if (SPW)  SetFlag    ( CIFFL_PrintWarnings );
+          else  RemoveFlag ( CIFFL_PrintWarnings );
+    }
+
+    void  Data::SetStopOnWarning ( bool SOW )  {
+      if (SOW)  SetFlag    ( CIFFL_StopOnWarnings );
+          else  RemoveFlag ( CIFFL_StopOnWarnings );
+    }
+
+    void  Data::SetFlag ( CIF_FLAG F )  {
+      flags |= F;
+    }
+
+    void  Data::RemoveFlag ( CIF_FLAG F )  {
+      flags &= ~F;
+    }
+
+    void  Data::SetWrongFields ( cpstr *cats, cpstr *tags )  {
+    int i,lc,lt;
+      FreeWrongFields();
+      if ((!cats) || (!tags))  return;
+      lc = 0;
+      while (cats[lc]) lc++;
+      lt = 0;
+      while (tags[lt]) lt++;
+      nWrongFields = IMax(lc,lt);
+      if (nWrongFields>0)  {
+        WrongCat = new pstr[nWrongFields];
+        WrongTag = new pstr[nWrongFields];
+        for (i=0;i<nWrongFields;i++)  {
+          WrongCat[i] = NULL;
+          WrongTag[i] = NULL;
+          if (cats[i])  {
+            if (cats[i][0])  CreateCopy ( WrongCat[i],cats[i] );
+          }
+          if (!WrongCat[i])  {
+            CreateCopy ( WrongCat[i],pstr(" ") );
+            WrongCat[i][0] = char(1);
+          }
+          if (tags[i])  CreateCopy ( WrongTag[i],tags[i]  );
+                  else  CreateCopy ( WrongTag[i],pstr("") );
+        }
+      }
+    }
+
+    bool Data::CheckWrongField ( cpstr C, cpstr T )  {
+    int i;
+      for (i=0;i<nWrongFields;i++)
+        if ((!strcasecmp(C,WrongCat[i])) &&
+            (!strcasecmp(T,WrongTag[i])))  return true;
+      return false;
+    }
+
+    #define _max_buf_len   500
+
+    static char  _err_string[_max_buf_len+1];
+    static int   _err_line;
+
+
+    int  Data::ReadMMCIFData ( cpstr FName, io::GZ_MODE gzipMode )  {
+    io::File f;
+    char     S[_max_buf_len+1];
+    int      RC,lcount;
+      f.assign ( FName,true,false,gzipMode );
+      if (f.reset(true))  {
+        S[0]   = char(0);
+        lcount = 0;
+        RC     = ReadMMCIFData ( f,S,lcount );
+        f.shut();
+        return RC;
+      } else  {
+        _err_string[0] = char(0);
+        _err_line      = 0;
+        Warning = CIFRC_CantOpenFile;
+        return CIFRC_CantOpenFile;
+      }
+    }
+
+
+    // ---------------  General I/O functions
+
+    int  Data::ReadMMCIFData ( io::RFile f, pstr S, int & lcount )  {
+    pstr p;
+    int  i,llen;
+    pstr L;
+
+      FreeMemory(1);
+      Warning = 0;
+      loopNo  = 0;
+      tagNo   = 0;
+
+      // 1. Look for 'data_' tag
+      do {
+        p = &(S[0]);
+        while ((*p==' ') || (*p==char(9)))  p++;
+        if (strncmp(p,"data_",5))  {
+          f.ReadLine ( S,_max_buf_len );
+          lcount++;
+          p = NULL;
+        }
+      } while ((!p) && (!f.FileEnd()));
+
+      if (!p)  {
+        strcpy ( _err_string,S );
+        _err_line = lcount;
+        if (flags & CIFFL_PrintWarnings)
+          printf ( "\n **** mmCIF READ ERROR "
+                   "<<line %i: no 'data_XXXX' tag found>>\n",lcount );
+        return CIFRC_NoDataLine;
+      }
+
+      llen = _max_buf_len;
+      L    = new char[llen];
+      i    = 0;
+      p   += 5;
+      while ((*p) && (*p!=' ') && (*p!=char(9)))  {
+        L[i++] = *p;
+        p++;
+      }
+      L[i] = char(0);
+      CreateCopy ( name,L );
+
+
+      // 2. Loop over tags until next 'data_' or end of file
+
+      while (p)  {
+
+        // skip spaces
+        while ((*p==' ') || (*p==char(9)))  p++;
+
+        if ((*p) && (*p!='#'))  {  // this is not a comment, continue
+          if (*p=='_')
+            GetDataItem ( f,S,L,p,lcount,llen );
+          else if (!strncmp(p,"loop_",5))
+            GetLoop ( f,S,L,p,lcount,llen );
+          else if (!strncmp(p,"data_",5))  {
+            p = NULL;
+            break;
+          } else  {
+            // if got to here, the file is corrupted
+            strcpy ( _err_string,S );
+            _err_line = lcount;
+            Warning |= CIFW_UnrecognizedItems;
+            if (flags & CIFFL_PrintWarnings)
+              printf ( "\n **** mmCIF READ WARNING "
+                       "<<line %i: unrecognized string>>\n%s\n",
+                       lcount,S );
+            while ((*p) && (*p!=' ') && (*p!=char(9)))
+              if (*p=='#')  *p = char(0);
+                      else  p++;
+          }
+        } else
+          *p = char(0);
+
+        if (Warning && (flags & CIFFL_StopOnWarnings))  {
+          if (L)  delete[] L;
+          return Warning;
+        }
+
+        if (!(*p))  {
+          if (!f.FileEnd())  {
+            f.ReadLine ( S,_max_buf_len );
+            lcount++;
+            p = &(S[0]);
+          } else
+            p = NULL;
+        }
+
+      }
+
+      if (L)  delete[] L;
+
+      Optimize();  // get rid of over-allocated fields.
+
+      return Warning;
+
+    }
+
+
+    void Data::GetDataItem ( io::RFile f, pstr S, pstr & L,
+                             pstr & p, int & lcount, int & llen )  {
+    PStruct cifStruct;
+    char    T[100];
+    int     RC,i;
+
+      i = 0;
+      while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.'))  {
+        if (i<(int)sizeof(T)-1)  T[i++] = *p;
+        p++;
+      }
+      T[i] = char(0);
+
+      if (*p!='.')  {    // category name missing
+        strcpy ( L,T );  // item name
+        T[0] = char(1);  // special
+        T[1] = char(0);  //   category name
+      }
+
+      //  look for category
+      i = AddCategory ( T );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifStruct = new Struct ( T );
+        Category[nCategories-1] = cifStruct;
+      } else  {
+        cifStruct = PStruct(Category[i]);
+        if (cifStruct->GetCategoryID()!=MMCIF_Struct)  {
+          strcpy ( _err_string,S );
+          _err_line = lcount;
+          Warning |= CIFW_NotAStructure;
+          if (flags & CIFFL_PrintWarnings)
+            printf ( "\n **** mmCIF READ WARNING "
+                     "<<line %i: %s was a loop -- replaced>>\n%s\n",
+                     lcount,T,S );
+          delete Category[i];
+          cifStruct = new Struct ( T );
+          Category[i] = cifStruct;
+        }
+      }
+
+      if (*p=='.')  {  // get item name
+        i = 0;
+        p++;  // skip period
+        while ((*p) && (*p!=' ') && (*p!=char(9)))  {
+          T[i++] = *p;
+          p++;
+        }
+        T[i] = char(0);
+      } else
+        strcpy ( T,L );
+
+      if (nWrongFields>0)  {
+        if (CheckWrongField(cifStruct->name,T))  {
+          GetField ( f,S,L,p,lcount,llen );
+          cifStruct->DeleteField ( T );
+          return;
+        }
+      }
+
+      RC = GetField ( f,S,L,p,lcount,llen );
+
+      if (RC)  {
+        strcpy ( _err_string,S );
+        _err_line = lcount;
+        Warning |= CIFW_MissingField;
+        if (flags & CIFFL_PrintWarnings)
+          printf ( "\n **** mmCIF READ WARNING "
+                   "<<line %i: expected data field missing>>\n%s\n",
+                   lcount,S );
+      }
+
+      while ((*p==' ') || (*p==char(9)))  p++;
+      if (*p=='#')  *p = char(0);
+
+      i = cifStruct->GetTagNo ( T );
+      if (i>=0)  {
+        if (flags & CIFFL_SuggestTags)  {
+          tagNo++;
+          ParamStr ( T,pstr("\1"),tagNo );
+        } else  {
+          strcpy ( _err_string,S );
+          _err_line = lcount;
+          Warning |= CIFW_DuplicateTag;
+          if (flags & CIFFL_PrintWarnings)
+            printf ( "\n **** mmCIF READ WARNING "
+                     "<<line %i: duplicated tag>>\n%s\n",lcount,S );
+        }
+      }
+      cifStruct->AddField ( L,T );
+
+    }
+
+    void Data::GetLoop ( io::RFile f, pstr S, pstr & L,
+                         pstr & p, int & lcount, int & llen )  {
+    PLoop cifLoop;
+    pstr  p1;
+    char  T[100];
+    bool  Repeat,WrongField;
+    int   RC,i,nC;
+
+      RC = 0;
+
+      p += 5;  // skip 'loop_' tag
+
+      loopNo++;
+      cifLoop = NULL;
+      nC      = -1; // undefined category number
+      do {
+
+        while ((*p==' ') || (*p==char(9)))  p++;
+        p1 = p;
+
+        if (*p=='_')  {
+
+          // get category name
+          i = 0;
+          while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.'))  {
+            if (i<(int)sizeof(T)-1)  T[i++] = *p;
+            p++;
+          }
+          T[i] = char(0);
+
+          if (*p!='.')  {    // category name missing
+            strcpy ( L,T );  // item name
+            if (flags & CIFFL_SuggestCategories)
+                 sprintf ( T,"X%i",loopNo );
+            else strcpy  ( T,"X" );
+            T[0] = char(1);  // special category name
+          }
+
+          if (cifLoop)  {
+            if (strcmp(cifLoop->GetCategoryName(),T))  {
+              // loop ended, empty
+              p    = p1;   // play back to last category
+              cifLoop = NULL;
+            }
+          } else  {
+            //  look for category
+            i = AddCategory ( T );
+            if ((i!=nC) && (nC>=0))  {  // empty loop; most probably
+                                        // a corrupted file
+              p = p1;   // play back to last category
+              strcpy ( _err_string,S );
+              _err_line = lcount;
+              Warning |= CIFW_EmptyLoop;
+              if (flags & CIFFL_PrintWarnings)
+                printf ( "\n **** mmCIF READ WARNING "
+                         "<<line %i: empty loop>>\n%s\n",lcount,S );
+              // AddCategory(..) has added a NULL-Category on the top of
+              // category list; remove it now
+              DeleteCategory ( nCategories-1 );
+              cifLoop = NULL;
+    //          return;
+            }
+            if (i<0)  {
+              // negative value means that the category was not in the list,
+              // but a place for it has been provided and index updated
+              cifLoop = new Loop ( T );
+              Category[nCategories-1] = cifLoop;
+              nC = nCategories-1;
+            }
+          }
+    /*
+     else if (Loop)  {
+            if (!strcmp(Loop->GetCategoryName(),
+                        Category[i]->GetCategoryName()))  {
+              if (Loop->GetCategoryID()!=MMCIF_Loop)  {
+                Warning |= CIFW_NotALoop;
+                if (flags & CIFFL_PrintWarnings)
+                  printf ( "\n **** mmCIF READ WARNING "
+                           "<<line %i: %s was a structure --"
+                           " replaced>>\n%s\n",lcount,T,S );
+                delete Category[i];
+                Loop = new Loop ( T );
+                Category[i] = Loop;
+              }
+            } else
+              Loop = NULL;
+          }
+    */
+          if (cifLoop)  {
+
+            if (*p=='.')  {  // get item name
+              i = 0;
+              p++;  // skip period
+              while ((*p) && (*p!=' ') && (*p!=char(9)))  {
+                T[i++] = *p;
+                p++;
+              }
+              T[i] = char(0);
+            } else
+              strcpy ( T,L );
+
+            if (nWrongFields>0)
+                  WrongField = CheckWrongField ( cifLoop->name,T );
+            else  WrongField = false;
+
+            if (!WrongField)  {
+              if (cifLoop->AddTag(T)>=0)  {
+                if (flags & CIFFL_SuggestTags)  {
+                  tagNo++;
+                  ParamStr ( T,pstr("\1"),tagNo );
+                  cifLoop->AddTag(T);
+                } else  {
+                  strcpy ( _err_string,S );
+                  _err_line = lcount;
+                  Warning |= CIFW_DuplicateTag;
+                  if (flags & CIFFL_PrintWarnings)
+                    printf ( "\n **** mmCIF READ WARNING "
+                             "<<line %i: duplicate tag>>\n%s\n",lcount,S );
+                }
+              }
+            }
+            Repeat = true;
+
+          } else  {
+
+            p = p1;
+            Repeat = false;
+
+          }
+
+        } else if (!(*p) || (*p=='#'))  {
+          Repeat = !f.FileEnd();
+          if (Repeat)  {
+            f.ReadLine ( S,_max_buf_len );
+            lcount++;
+            p = &(S[0]);
+          } else  {
+            strcpy ( _err_string,S );
+            _err_line = lcount;
+            Warning |= CIFW_UnexpectedEOF;
+            if (flags & CIFFL_PrintWarnings)
+              printf ( "\n **** mmCIF READ WARNING "
+                       "<<line %i: unexpected end of file>>\n%s\n",
+                       lcount,S );
+          }
+        } else
+          Repeat = false;
+
+      } while (Repeat);
+
+      if (cifLoop)  {
+        do  {
+          while ((*p==' ') || (*p==char(9)))  p++;
+          if (!(*p) || (*p=='#'))  {
+            Repeat = !f.FileEnd();
+            if (Repeat)  {
+              f.ReadLine ( S,_max_buf_len );
+              lcount++;
+              p = &(S[0]);
+            }
+          } else if (*p=='_')  Repeat = false;
+          else if (!strncmp(p,"loop_",5))  Repeat = false;
+          else if (!strncmp(p,"data_",5))  Repeat = false;
+          else if (!strncmp(p,"stop_",5))  {
+            p += 5;
+            Repeat = false;
+          } else  {
+            RC = GetField ( f,S,L,p,lcount,llen );
+            if (!RC)  {
+              cifLoop->AddString ( L );
+              Repeat = true;
+            } else
+              Repeat = false;
+          }
+        } while (Repeat);
+        if ((cifLoop->iColumn!=0) || (RC))  {
+          strcpy ( _err_string,S );
+          _err_line = lcount;
+          Warning |= CIFW_LoopFieldMissing;
+          if (flags & CIFFL_PrintWarnings)
+            printf ( "\n **** mmCIF READ WARNING "
+                     "<<line %i: expected loop field missing>>\n%s\n",
+                     lcount,S );
+        }
+      }
+
+    }
+
+    int  Data::GetField ( io::RFile f, pstr S, pstr & L,
+                          pstr & p, int & lcount, int & llen )  {
+    bool Repeat;
+    pstr L1;
+    int  i,flen;
+    char c;
+
+      flen    = 0;
+      L[flen] = char(0);
+
+      do {
+
+        // skip all spaces before the field
+        while ((*p==' ') || (*p==char(9)))  p++;
+
+        if ((*p=='#') || (!(*p)))  {
+          // comment or end of line met;  the field should be
+          // found on the next line
+          Repeat = !f.FileEnd();
+          if (Repeat)  {
+            // take the next line
+            f.ReadLine ( S,_max_buf_len );
+            lcount++;
+            p = &(S[0]);
+            Repeat = (*p!=';');
+          } else  {
+            // end of file and the field is not taken
+            L[0] = char(0);
+            return 1;
+          }
+        } else
+          // first symbol of a field is found
+          Repeat = false;
+
+      } while (Repeat);
+
+
+      if (*p==';')  {      // this is a multiline field
+        p++;
+        strcpy ( L,p );    // take first line of the field
+        flen = strlen(L);
+        while (!f.FileEnd())  {
+          f.ReadLine ( S,_max_buf_len );
+          lcount++;
+          p = &(S[0]);
+          if (*p==';')  {  // multiline field terminated
+            p++;
+            while ((*p==' ') || (*p==char(9)))  p++;
+            return 0;
+          } else  {        // multiline field continues -- take next line
+            flen += strlen(S)+2;
+            if (flen>=llen)  {
+              llen = flen + IMin(2000,llen);
+              L1   = new char[llen];
+              strcpy ( L1,L );
+              delete[] L;
+              L = L1;
+            }
+            strcat ( L,"\n" );
+            strcat ( L,S );
+          }
+        }
+
+        // end of file -- take the last line of the multiline field
+        p = &(S[strlen(S)]);
+
+      } else  {
+
+        i = 0;
+        if (*p!='_')  {
+          if ((*p=='\'') || (*p=='"'))  {
+            c = *p;
+            // field in quotation marks
+            do  {
+              p++;
+              // stop taking characters either on end of line
+              // or the quotation mark
+              while ((*p) && (*p!=c))  {
+                L[i++] = *p;
+                p++;
+              }
+              while (*p==c)  {
+                // it was a quotation mark -- check that it is followed
+                // by end of line or space
+                p++;
+                if ((*p) && (*p!=' ') && (*p!=char(9)))  {
+                  // the quotation mark is not a field terminator and
+                  // belongs to the field.
+                  L[i++] = c;    // take the quotation mark
+                  if (*p!=c)     // take the non-space character
+                    L[i++] = *p; // but check for field terminator
+                }
+              }
+              // terminate the loop only on space or end of line
+            } while ((*p) && (*p!=' ') && (*p!=char(9)));
+            if (*p)  p++;
+            L[i] = char(0);
+          } else  {
+            // a simplest field without spaces
+            while ((*p) && (*p!=' ') && (*p!=char(9)))  {
+              L[i++] = *p;
+              p++;
+            }
+            L[i] = char(0);
+            if (((L[0]=='.') || (L[0]=='?')) && (!L[1]))  {
+              //  "no data" tokens
+              L[1] = L[0];
+              L[0] = char(2);
+              L[2] = char(0);
+            }
+          }
+        }
+
+      }
+
+      return 0;
+
+    }
+
+    void  Data::Sort()  {
+    int      i,k;
+    psvector cnames;
+
+      k = 0;
+      for (i=0;i<nCategories;i++)
+        if (Category[i])  {
+          if (k<i)  Category[k] = Category[i];
+          k++;
+        }
+      for (i=k;i<nCategories;i++)
+        Category[i] = NULL;
+      nCategories = k;
+
+      FreeVectorMemory ( index ,0 );
+      GetVectorMemory  ( cnames,nCategories,0 );
+      GetVectorMemory  ( index ,nCategories,0 );
+
+      for (i=0;i<nCategories;i++)  {
+        Category[i]->Sort();
+        cnames[i] = NULL;
+        CreateCopy ( cnames[i],Category[i]->name );
+      }
+
+      SortTags ( cnames,nCategories,index );
+
+      for (i=0;i<nCategories;i++)
+        if (cnames[i])  delete[] cnames[i];
+
+      if (cnames) delete[] cnames;
+
+    }
+
+    int  Data::GetCategoryNo ( cpstr cname )  {
+    //   Binary search for index of category cname in Category[].
+    // Return:
+    //    >=0 : position of the category found
+    //     <0 : the category was not found, it could be inserted before
+    //          (-RC-1)th element, where RC is the return value
+    int l1,l2,l,k;
+
+      if ((!Category) || (nCategories<1)) return -1;
+
+      if (!index)    Sort();
+
+      if (cname[0])  {
+        l  = 0;
+        l1 = 0;
+        l2 = nCategories-1;
+        k  = 1;
+        while (l1<l2-1)  {
+          l = (l1+l2)/2;
+          k = strcasecmp ( cname,Category[index[l]]->name );
+          if (k<0)      l2 = l;
+          else if (k>0) l1 = l;
+          else  {
+            l1 = l;
+            break;
+          }
+        }
+        if (k==0)  return index[l];    // is at RCth position
+        k = strcasecmp(cname,Category[index[l1]]->name);
+        if (k==0)  return index[l1];   // is at RCth position
+        if (k<0)   return -1;          // would be at (-RC-1)th position
+        if (l2!=l1)  {
+          k = strcasecmp(cname,Category[index[l2]]->name);
+          if (k==0)  return index[l2]; // is at RCth position
+          if (k>0)   return -2-l2;   // would be at l2+1=(-RC-1)th position
+        }
+        return -2-l1;                // would be at l1+1=(-RC-1)th position
+      } else
+        // 'root' category should be always on top
+        if (Category[index[0]]->name[0]==char(1))  return index[0];
+
+      return -1;
+
+    }
+
+    int  Data::AddCategory ( cpstr cname )  {
+    //  return -1: a place for category has been added on the top of array;
+    //             index is added and sorted automatically
+    //        >=0: the category is already in the array -- its position
+    //             is returned
+    int              l1,l;
+    PPCategory Category1;
+    ivector          index1;
+
+
+      if (!Category)  {
+        Category     = new PCategory[1];
+        Category[0]  = NULL;
+        GetVectorMemory ( index,1,0 );
+        index[0]     = 0;
+        nCategories  = 1;
+        return -nCategories;  // the category has been added on the top of array
+      }
+      l1 = GetCategoryNo ( cname );
+      if (l1>=0)  return l1;  // non-negative returns mean that
+                              // the category is already in the array
+      l1 = -l1-1;  // otherwise the category has to be added and indexed at here
+      // put new NULL-category on the top of array and update the index
+      Category1 = new PCategory[nCategories+1];
+      GetVectorMemory ( index1,nCategories+1,0 );
+      for (l=0;l<nCategories;l++)
+        Category1[l] = Category[l];
+      Category1[nCategories] = NULL;
+      for (l=0;l<l1;l++)
+        index1[l] = index[l];
+      index1[l1] = nCategories;
+      for (l=l1+1;l<=nCategories;l++)
+        index1[l] = index[l-1];
+      delete[] Category;
+      FreeVectorMemory ( index,0 );
+      Category = Category1;
+      index    = index1;
+      nCategories++;
+      return -nCategories; // the category has been added on
+                           // the top of array
+    }
+
+    bool Data::WriteMMCIFData ( cpstr FName, io::GZ_MODE gzipMode )  {
+    io::File f;
+      f.assign ( FName,true,false,gzipMode );
+      if (f.rewrite())  {
+        WriteMMCIF ( f );
+        f.shut();
+        return true;
+      } else
+        return false;
+    }
+
+    void Data::WriteMMCIF ( io::RFile f )  {
+    int  i;
+
+      if (name)  {
+        f.Write     ( pstr("\ndata_") );
+        f.WriteLine ( name            );
+      } else
+        f.WriteLine ( pstr("\ndata_") );
+
+      for (i=0;i<nCategories;i++)
+        if (Category[i])
+          Category[i]->WriteMMCIF ( f );
+
+    }
+
+
+    // ---------------  Retrieving data
+
+    int  Data::DeleteCategory ( cpstr CName )  {
+    int k;
+      k = GetCategoryNo ( CName );
+      if (k<0)  return CIFRC_NoCategory;
+      return DeleteCategory ( k );
+    }
+
+    int  Data::DeleteCategory ( int CatNo ) {
+    int i;
+      if (Category[CatNo])  delete Category[CatNo];
+      for (i=CatNo+1;i<nCategories;i++)
+        Category[i-1] = Category[i];
+      i = 0;
+      while ((i<nCategories) && (index[i]!=CatNo))  {
+        if (index[i]>CatNo) index[i]--;
+        i++;
+      }
+      i++;
+      while (i<nCategories)  {
+        if (index[i]>CatNo) index[i]--;
+        index[i-1] = index[i];
+        i++;
+      }
+      nCategories--;
+      index   [nCategories] = 0;
+      Category[nCategories] = NULL;
+      return 0;
+    }
+
+    int  Data::DeleteStructure ( cpstr CName )  {
+    int k;
+      k = GetCategoryNo ( CName );
+      if (k<0)  return CIFRC_NoCategory;
+      if (Category[k]->GetCategoryID()==MMCIF_Struct)
+            return DeleteCategory ( k );
+      else  return CIFRC_NotAStructure;
+    }
+
+    int  Data::DeleteLoop ( cpstr CName )  {
+    int k;
+      k = GetCategoryNo ( CName );
+      if (k<0)  return CIFRC_NoCategory;
+      if (Category[k]->GetCategoryID()==MMCIF_Loop)
+            return DeleteCategory ( k );
+      else  return CIFRC_NotALoop;
+    }
+
+    PCategory Data::GetCategory ( int categoryNo )  {
+      if ((categoryNo>=0) && (categoryNo<nCategories))
+        return Category[categoryNo];
+      return NULL;
+    }
+
+    PStruct Data::GetStructure ( cpstr CName )  {
+    int i;
+      i = GetCategoryNo ( CName );
+      if (i<0)  return NULL;
+      if (Category[i]->GetCategoryID()==MMCIF_Struct)
+            return PStruct(Category[i]);
+      else  return NULL;
+    }
+
+    PLoop Data::GetLoop ( cpstr CName )  {
+    int i;
+      i = GetCategoryNo ( CName );
+      if (i<0)  return NULL;
+      if (Category[i]->GetCategoryID()==MMCIF_Loop)
+            return PLoop(Category[i]);
+      else  return NULL;
+    }
+
+    PLoop Data::FindLoop ( cpstr * tagList )  {
+    int i;
+      for (i=0;i<nCategories;i++)
+        if (Category[i])  {
+          if (Category[i]->GetCategoryID()==MMCIF_Loop)  {
+            if (Category[i]->CheckTags(tagList))
+              return PLoop(Category[i]);
+          }
+        }
+      return NULL;
+    }
+
+    void Data::GetDataName ( pstr & dname, bool Remove )  {
+      if (Remove)  {
+        if (dname)  delete[] dname;
+        dname = name;
+        name  = NULL;
+      } else
+        CreateCopy ( dname,name );
+    }
+
+    int  Data::CheckData ( cpstr CName, cpstr TName )  {
+    //   CheckData(..) returns positive value if the field is in the
+    // file:
+    //   CIFRC_Structure  category CName is a structure
+    //   CIFRC_Loop       category CName is a loop
+    // Negative returns mean:
+    //   CIFRC_StructureNoTag  category CName is present,
+    //                        it is a structure, but it does not
+    //                        have tag TName
+    //   CIFRC_LoopNoTag       category CName is present,
+    //                        it is a loop, but it does not have
+    //                        tag TName
+    //   CIFRC_NoCategory      category CName is not present.
+    // If TName is set to NULL then only the CName is checked and
+    // possible returns are CIFRC_Structure, CIFRC_Loop and
+    // CIFRC_NoCategory.
+    int i,k;
+      i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()==MMCIF_Struct)
+            k = CIFRC_Structure;
+      else  k = CIFRC_Loop;
+      if (TName)  {
+        if (Category[i]->GetTagNo(TName)<0)  {
+          if (k==CIFRC_Structure)
+                k = CIFRC_StructureNoTag;
+          else  k = CIFRC_LoopNoTag;
+        }
+      }
+      return k;
+    }
+
+    void Data::Optimize()  {
+    int              i,k;
+    PPCategory C1;
+      k = 0;
+      for (i=0;i<nCategories;i++)
+        if (Category[i])  {
+          Category[i]->Optimize();
+          if (Category[i]->nTags<=0)  {
+            delete Category[i];
+            Category[i] = NULL;
+          } else
+            k++;
+        }
+      if (k>0)  {
+        if (k!=nCategories)  {
+          C1 = new PCategory[k];
+          k  = 0;
+          for (i=0;i<nCategories;i++)
+            if (Category[i])
+              C1[k++] = Category[i];
+          if (Category) delete[] Category;
+          Category    = C1;
+          nCategories = k;
+          FreeVectorMemory ( index,0 );
+          Sort();
+        }
+      } else  {
+        if (Category)  delete[] Category;
+        Category    = NULL;
+        nCategories = 0;
+      }
+    }
+
+    int  Data::GetString  ( pstr & Dest, cpstr CName,
+                                  cpstr TName, bool Remove )  {
+    //   GetString(..), GetReal(..) and GetInteger(..) return 0 if the
+    // requested field was found and successfully converted. Negative
+    // returns mean:
+    //    CIFRC_WrongFormat    the field was found but failed to convert
+    //                        due to improper numeric format
+    //    CIFRC_NoTag          category CName was found, but it does not
+    //                        have tag TName
+    //    CIFRC_NoCategory     category CName was not found
+    //    CIFRC_NotAStructure  category CName was found, but it is a loop
+    //                        rather than a structure.
+    //   GetString(..) will try to dispose Dest unless it is assugned
+    // NULL value before the call. The string will be then dynamically
+    // allocated and copied.
+    int i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Struct)
+                return CIFRC_NotAStructure;
+      return PStruct(Category[i])->GetString ( Dest,TName,Remove );
+    }
+
+    pstr Data::GetString ( cpstr CName, cpstr TName, int & RC )  {
+    int i = GetCategoryNo ( CName );
+      if (i<0)  {
+        RC = CIFRC_NoCategory;
+        return NULL;
+      }
+      if (Category[i]->GetCategoryID()!=MMCIF_Struct)  {
+        RC = CIFRC_NotAStructure;
+        return NULL;
+      }
+      return PStruct(Category[i])->GetString ( TName,RC );
+    }
+
+    int  Data::DeleteField ( cpstr CName, cpstr TName )  {
+    int i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Struct)
+                return CIFRC_NotAStructure;
+      return PStruct(Category[i])->DeleteField ( TName );
+    }
+
+    int  Data::GetReal ( realtype & R, cpstr CName,
+                         cpstr TName, bool Remove )  {
+    int i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Struct)
+                return CIFRC_NotAStructure;
+      return PStruct(Category[i])->GetReal ( R,TName,Remove );
+    }
+
+    int  Data::GetInteger ( int & I, cpstr CName,
+                                  cpstr TName, bool Remove )  {
+    int j = GetCategoryNo ( CName );
+      if (j<0)  return CIFRC_NoCategory;
+      if (Category[j]->GetCategoryID()!=MMCIF_Struct)
+                return CIFRC_NotAStructure;
+      return PStruct(Category[j])->GetInteger ( I,TName,Remove );
+    }
+
+    int  Data::GetLoopLength ( cpstr CName )  {
+    //   GetLoopLength(..) returns CIFRC_NotALoop if the category CName
+    // is not a loop, CIFRC_NoCategory if the category CName is not
+    // found. Non-negative returns give the length of the loop (may be
+    // 0 if the loop is empty).
+    int i;
+      i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+                return CIFRC_NotALoop;
+      return PLoop(Category[i])->nRows;
+    }
+
+    int  Data::GetLoopString  ( pstr & Dest, cpstr CName,
+                                      cpstr TName, int nrow,
+                                      bool Remove )  {
+    //   GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act
+    // like GetString(..), GetReal(..) and GetInteger(..) above for
+    // nrow-th element of the 'loop_' (indexed like 0..N-1 where N
+    // is obtained through GetLoopLength(..)). They will return
+    // CIFRC_WrongIndex if nrow is out of range.
+    int i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+                return CIFRC_NotALoop;
+      return PLoop(Category[i])->GetString ( Dest,TName,nrow,Remove );
+    }
+
+    pstr Data::GetLoopString  ( cpstr CName, cpstr TName,
+                                      int nrow, int & RC )  {
+    int i = GetCategoryNo ( CName );
+      if (i<0)  {
+        RC = CIFRC_NoCategory;
+        return NULL;
+      }
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)  {
+        RC = CIFRC_NotALoop;
+        return NULL;
+      }
+      return  PLoop(Category[i])->GetString ( TName,nrow,RC );
+    }
+
+    int Data::DeleteLoopField ( cpstr CName, cpstr TName,
+                                      int nrow )  {
+    int i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+                return CIFRC_NotALoop;
+      return PLoop(Category[i])->DeleteField ( TName,nrow );
+    }
+
+    int  Data::GetLoopReal ( realtype & R, cpstr CName,
+                                   cpstr TName, int nrow,
+                                   bool Remove )  {
+    int i = GetCategoryNo ( CName );
+      if (i<0)  return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+                return CIFRC_NotALoop;
+      return PLoop(Category[i])->GetReal ( R,TName,nrow,Remove );
+    }
+
+    int  Data::GetLoopInteger ( int & I, cpstr CName,
+                                      cpstr TName, int nrow,
+                                      bool Remove )  {
+    int j = GetCategoryNo ( CName );
+      if (j<0)  return CIFRC_NoCategory;
+      if (Category[j]->GetCategoryID()!=MMCIF_Loop)
+                return CIFRC_NotALoop;
+      return PLoop(Category[j])->GetInteger ( I,TName,nrow,Remove );
+    }
+
+
+    int  Data::GetLoopSVector ( psvector & S, cpstr CName,
+                                      cpstr TName, int i1, int i2,
+                                      bool Remove )  {
+    //   GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..)
+    // read CIF 'loop_' data into allocated vectors of strings, reals and
+    // integers, correspondingly. The vectors may be deallocated prior
+    // to call and assigned NULL, in which case they will be allocated
+    // with offsets of i1, which is also the lower index of the 'loop_'
+    // data transferred into it. The upper vector index is given by i2 or
+    // by the loop's length whichever is less. If vectors are not assigned
+    // NULL prior the call, it is assumed that they are properly (i1-offset,
+    // i2-i1+1 length) allocated.
+    //   The return codes are same as those of GetLoopString(..),
+    // GetLoopReal(..) and GetLoopInteger(..).
+    int i;
+      i = GetCategoryNo ( CName );
+      if (i<0)    return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+                  return CIFRC_NotALoop;
+      return PLoop(Category[i])->GetSVector ( S,TName,i1,i2,Remove );
+    }
+
+    int  Data::GetLoopRVector ( rvector & R, cpstr CName,
+                                      cpstr TName, int i1, int i2,
+                                      bool Remove )  {
+    int i;
+      i = GetCategoryNo ( CName );
+      if (i<0)    return CIFRC_NoCategory;
+      if (Category[i]->GetCategoryID()!=MMCIF_Loop)
+                  return CIFRC_NotALoop;
+      return PLoop(Category[i])->GetRVector ( R,TName,i1,i2,Remove );
+    }
+
+    int  Data::GetLoopIVector ( ivector & I, cpstr CName,
+                                      cpstr TName, int i1, int i2,
+                                      bool Remove )  {
+    int j;
+      j = GetCategoryNo ( CName );
+      if (j<0)    return CIFRC_NoCategory;
+      if (Category[j]->GetCategoryID()!=MMCIF_Loop)
+                  return CIFRC_NotALoop;
+      return PLoop(Category[j])->GetIVector ( I,TName,i1,i2,Remove );
+    }
+
+
+    // ---------------  Storing data
+
+    void  Data::PutDataName ( cpstr dname )  {
+    // stores name for 'data_' record
+      CreateCopy ( name,dname );
+    }
+
+    int  Data::PutNoData ( int NoDataType, cpstr CName, cpstr TName )  {
+    PStruct cifStruct;
+    int     i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifStruct = new Struct ( CName );
+        Category[nCategories-1] = cifStruct;
+      } else  {
+        cifStruct = PStruct(Category[i]);
+        if (cifStruct->GetCategoryID()!=MMCIF_Struct)  {
+          RC = CIFRC_NotAStructure;
+          delete Category[i];
+          cifStruct = new Struct ( CName );
+          Category[i] = cifStruct;
+        }
+      }
+
+      cifStruct->PutNoData ( NoDataType,TName );
+
+      return RC;
+
+    }
+
+    int  Data::PutString ( cpstr S, cpstr CName,
+                           cpstr TName, bool Concatenate )  {
+    //   PutString(..), PutReal(..) and PutInteger(..) will put the
+    // values given into the specified category (CName) under the
+    // specified tag (TName). The category, tag and field are created
+    // automatically; the field will be replaced silently if identical
+    // CName.TName is specified in two calls. Calls of these functions
+    // may follow in random order; however CIF file will have all tags
+    // grouped by categories and catgories will follow in the order
+    // of first appearance in PutString(..), PutReal(..) or
+    // PutInteger(..).
+    //   Return code - one of CIFRC_Ok or CIFRC_NotAStruct
+    PStruct cifStruct;
+    int     i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifStruct = new Struct ( CName );
+        Category[nCategories-1] = cifStruct;
+      } else  {
+        cifStruct = PStruct(Category[i]);
+        if (cifStruct->GetCategoryID()!=MMCIF_Struct)  {
+          RC = CIFRC_NotAStructure;
+          delete Category[i];
+          cifStruct = new Struct ( CName );
+          Category[i] = cifStruct;
+        }
+      }
+
+      cifStruct->AddField ( S,TName,Concatenate );
+
+      return RC;
+
+    }
+
+    int   Data::PutDate ( cpstr CName, cpstr TName )  {
+    PStruct cifStruct;
+    int     i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifStruct = new Struct ( CName );
+        Category[nCategories-1] = cifStruct;
+      } else  {
+        cifStruct = PStruct(Category[i]);
+        if (cifStruct->GetCategoryID()!=MMCIF_Struct)  {
+          RC = CIFRC_NotAStructure;
+          delete Category[i];
+          cifStruct = new Struct ( CName );
+          Category[i] = cifStruct;
+        }
+      }
+
+      cifStruct->PutDate ( TName );
+
+      return RC;
+
+    }
+
+    int  Data::PutReal ( realtype R, cpstr CName,
+                         cpstr TName, int prec )  {
+    char rS[100];
+      sprintf ( rS,"%.*g",prec,R );
+      return PutString ( rS,CName,TName,false );
+    }
+
+    int  Data::PutInteger ( int I, cpstr CName,
+                                         cpstr TName )  {
+    char iS[100];
+      if (I>MinInt4)  sprintf ( iS,"%i",I );
+      else  {
+        iS[0] = char(2);
+        iS[1] = '.';
+        iS[2] = char(0);
+      }
+      return PutString ( iS,CName,TName,false );
+    }
+
+
+    int  Data::AddLoop ( cpstr CName, PLoop & cifLoop )  {
+    int  i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifLoop = new Loop ( CName );
+        Category[nCategories-1] = cifLoop;
+        RC = CIFRC_Created;
+      } else  {
+        cifLoop = PLoop(Category[i]);
+        if (cifLoop->GetCategoryID()!=MMCIF_Loop)  {
+          RC = CIFRC_NotALoop;
+          delete Category[i];
+          cifLoop = new Loop ( CName );
+          Category[i] = cifLoop;
+        }
+      }
+
+      return RC;
+
+    }
+
+    int  Data::AddStructure ( cpstr CName, PStruct & cifStruct )  {
+    int  i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifStruct = new Struct ( CName );
+        Category[nCategories-1] = cifStruct;
+        RC = CIFRC_Created;
+      } else  {
+        cifStruct = PStruct(Category[i]);
+        if (cifStruct->GetCategoryID()!=MMCIF_Struct)  {
+          RC = CIFRC_NotAStructure;
+          delete Category[i];
+          cifStruct = new Struct ( CName );
+          Category[i] = cifStruct;
+        }
+      }
+
+      return RC;
+
+    }
+
+
+    int  Data::PutLoopNoData ( int NoDataType, cpstr CName,
+                                     cpstr TName, int nrow )  {
+    PLoop cifLoop;
+    int   i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifLoop = new Loop ( CName );
+        Category[nCategories-1] = cifLoop;
+      } else  {
+        cifLoop = PLoop(Category[i]);
+        if (cifLoop->GetCategoryID()!=MMCIF_Loop)  {
+          RC = CIFRC_NotALoop;
+          delete Category[i];
+          cifLoop = new Loop ( CName );
+          Category[i] = cifLoop;
+        }
+      }
+
+      cifLoop->PutNoData ( NoDataType,TName,nrow );
+
+      return RC;
+
+    }
+
+
+    int  Data::PutLoopString ( cpstr S, cpstr CName,
+                                     cpstr TName, int nrow )  {
+    //   PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act
+    // like PutString(..), PutReal(..) and PutInteger(..) above for
+    // nrow-th element of the 'loop_' CName (indexed begining from 0).
+    // In consequitive calls, given values of nrow does not have to be
+    // ordered; the most efficient way is to start with HIGHEST value
+    // for nrow in the loop and move down to 0. The least efficient way
+    // is to start with nrow=0 and move up.
+    PLoop cifLoop;
+    int   i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifLoop = new Loop ( CName );
+        Category[nCategories-1] = cifLoop;
+      } else  {
+        cifLoop = PLoop(Category[i]);
+        if (cifLoop->GetCategoryID()!=MMCIF_Loop)  {
+          RC = CIFRC_NotALoop;
+          delete Category[i];
+          cifLoop = new Loop ( CName );
+          Category[i] = cifLoop;
+        }
+      }
+
+      cifLoop->PutString ( S,TName,nrow );
+
+      return RC;
+
+    }
+
+    int  Data::PutLoopReal ( realtype R, cpstr CName,
+                                   cpstr TName, int nrow, int prec )  {
+    char rS[100];
+      sprintf ( rS,"%.*g",prec,R );
+      return PutLoopString ( rS,CName,TName,nrow );
+    }
+
+    int  Data::PutLoopInteger ( int I, cpstr CName,
+                                      cpstr TName, int nrow )  {
+    char iS[100];
+      sprintf ( iS,"%i",I );
+      return PutLoopString ( iS,CName,TName,nrow );
+    }
+
+
+    int  Data::PutLoopSVector ( psvector S, cpstr CName,
+                                      cpstr TName, int i1, int i2 )  {
+    //   PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..)
+    // put vectors of values into specified loop fields. Parameters i1
+    // and i2 give the range of indices of values which are to be
+    // transfered. To transfer an entire vector allocated as [0..N-1]
+    // i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is
+    // always indexed as starting form 0 on, therefore negative i1 and
+    // i2 are not allowed, and specifying i1>0 will leave first i1
+    // elements of the CIF loop for the corresponding tag undefined
+    // (will be output like '?').
+    PLoop cifLoop;
+    int   i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifLoop = new Loop ( CName );
+        Category[nCategories-1] = cifLoop;
+      } else  {
+        cifLoop = PLoop(Category[i]);
+        if (cifLoop->GetCategoryID()!=MMCIF_Loop)  {
+          RC = CIFRC_NotALoop;
+          delete Category[i];
+          cifLoop = new Loop ( CName );
+          Category[i] = cifLoop;
+        }
+      }
+
+      cifLoop->PutSVector ( S,TName,i1,i2 );
+
+      return RC;
+
+    }
+
+    int  Data::PutLoopRVector ( rvector R, cpstr CName,
+                                      cpstr TName,
+                                      int i1, int i2, int prec )  {
+    PLoop cifLoop;
+    int   i,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      i = AddCategory ( CName );
+      if (i<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifLoop = new Loop ( CName );
+        Category[nCategories-1] = cifLoop;
+      } else  {
+        cifLoop = PLoop(Category[i]);
+        if (cifLoop->GetCategoryID()!=MMCIF_Loop)  {
+          RC = CIFRC_NotALoop;
+          delete Category[i];
+          cifLoop = new Loop ( CName );
+          Category[i] = cifLoop;
+        }
+      }
+
+      cifLoop->PutRVector ( R,TName,i1,i2,prec );
+
+      return RC;
+
+    }
+
+    int  Data::PutLoopIVector ( ivector I, cpstr CName,
+                                      cpstr TName,
+                                      int i1, int i2 )  {
+    PLoop cifLoop;
+    int   j,RC;
+
+      RC = CIFRC_Ok;
+
+      //  look for category
+      j = AddCategory ( CName );
+      if (j<0)  {
+        // negative value means that the category was not in the list,
+        // but a place for it has been provided and index updated
+        cifLoop = new Loop ( CName );
+        Category[nCategories-1] = cifLoop;
+      } else  {
+        cifLoop = PLoop(Category[j]);
+        if (cifLoop->GetCategoryID()!=MMCIF_Loop)  {
+          RC = CIFRC_NotALoop;
+          delete Category[j];
+          cifLoop = new Loop ( CName );
+          Category[j] = cifLoop;
+        }
+      }
+
+      cifLoop->PutIVector ( I,TName,i1,i2 );
+
+      return RC;
+
+    }
+
+
+    int Data::RenameCategory ( cpstr CName,
+                                     cpstr newCName )  {
+    int i,RC;
+      i = GetCategoryNo ( CName );
+      if (i>=0)  {
+        Category[i]->PutCategoryName ( newCName );
+        Sort();
+        RC = CIFRC_Ok;
+      } else
+        RC = CIFRC_NoCategory;
+      return RC;
+    }
+
+
+    void Data::Copy ( PData Data )  {
+    int i;
+      FreeMemory(0);
+      CreateCopy ( name,Data->name );
+      nCategories = Data->nCategories;
+      if (nCategories>0)  {
+        Category = new PCategory[nCategories];
+        GetVectorMemory ( index,nCategories,0 );
+        for (i=0;i<nCategories;i++)  {
+          if (Data->Category[i])  {
+            if (Data->Category[i]->GetCategoryID()==MMCIF_Struct)
+                  Category[i] = new Struct();
+            else  Category[i] = new Loop();
+            Category[i]->Copy ( Data->Category[i] );
+          } else
+            Category[i] = NULL;
+          index[i] = Data->index[i];
+        }
+      }
+      flags   = Data->flags;
+      Warning = Data->Warning;
+    }
+
+
+    int  Data::CopyCategory ( PData Data, cpstr CName,
+                                    cpstr newCName )  {
+    PCategory Cat;
+    int             i,di,dc,RC;
+
+      di = Data->GetCategoryNo ( CName );
+
+      if (di>=0)  {
+
+        RC = CIFRC_Ok;
+        dc = Data->Category[di]->GetCategoryID();
+
+        //  look for category
+        i = AddCategory ( CName );
+        if (i<0)  {
+          // negative value means that the category was not in the list,
+          // but a place for it has been provided and index updated
+          if (dc==MMCIF_Loop)  Cat = new Loop   ( CName );
+                         else  Cat = new Struct ( CName );
+          Category[nCategories-1] = Cat;
+        } else  {
+          Cat = Category[i];
+          if (Cat->GetCategoryID()!=dc)  {
+            RC = CIFRC_NotAStructure;
+            delete Category[i];
+            if (dc==MMCIF_Loop)  Cat = new Loop   ( CName );
+                           else  Cat = new Struct ( CName );
+            Category[i] = Cat;
+          }
+        }
+
+        Cat->Copy ( Data->Category[di] );
+        if (newCName)  {
+          Cat->PutCategoryName ( newCName );
+          Sort();
+        }
+
+      } else
+        RC = CIFRC_NoCategory;
+
+      return RC;
+
+    }
+
+    void Data::PrintCategories()  {
+    // for debuging only
+    int i;
+      printf ( " Total %i categories:\n",nCategories );
+      for (i=0;i<nCategories;i++)
+        if (Category[i])  {
+          printf ( " %5i. ",i+1 );
+          if (Category[i]->GetCategoryID()==MMCIF_Loop)
+                printf ( "Loop      %s\n",Category[i]->name );
+          else  printf ( "Structure %s\n",Category[i]->name );
+        }
+    }
+
+
+    void Data::write ( io::RFile f )  {
+    int i,k;
+      if (!index)  Sort();
+      f.CreateWrite ( name );
+      f.WriteInt    ( &nCategories );
+      for (i=0;i<nCategories;i++)  {
+        if (Category[i])  {
+          k = Category[i]->GetCategoryID();
+          f.WriteInt ( &k );
+          Category[i]->write ( f );
+        } else  {
+          k = -1;
+          f.WriteInt ( &k );
+        }
+        f.WriteInt ( &(index[i]) );
+      }
+      f.WriteInt ( &flags   );
+      f.WriteInt ( &Warning );
+    }
+
+
+    void Data::read ( io::RFile f )  {
+    int i,k;
+      FreeMemory(0);
+      f.CreateRead ( name );
+      f.ReadInt    ( &nCategories );
+      if (nCategories>0)  {
+        Category = new PCategory[nCategories];
+        GetVectorMemory ( index,nCategories,0 );
+        for (i=0;i<nCategories;i++)  {
+          f.ReadInt ( &k );
+          if (k>=0)  {
+            if (k==MMCIF_Struct)  Category[i] = new Struct();
+                            else  Category[i] = new Loop();
+            Category[i]->read ( f );
+          } else
+            Category[i] = NULL;
+          f.ReadInt ( &(index[i]) );
+        }
+      }
+      f.ReadInt ( &flags   );
+      f.ReadInt ( &Warning );
+    }
+
+
+    MakeStreamFunctions(Data)
+
+
+
+    //  ======================  File  =============================
+
+
+    File::File() : io::Stream()  {
+      InitFile();
+    }
+
+    File::File ( cpstr FName, io::GZ_MODE gzipMode ) : io::Stream()  {
+      InitFile ();
+      ReadMMCIFFile ( FName,gzipMode );
+    }
+
+    File::File ( io::RPStream Object ) : io::Stream(Object)  {
+      InitFile();
+    }
+
+    File::~File()  {
+      FreeMemory();
+    }
+
+    void File::InitFile()  {
+      nData         = 0;
+      nAllocData    = 0;
+      data          = NULL;
+      index         = NULL;
+      PrintWarnings = false;
+      StopOnWarning = false;
+    }
+
+    void File::FreeMemory()  {
+    int i;
+      for (i=0;i<nData;i++)
+        if (data[i])  delete data[i];
+      if (data)  delete[] data;
+      data       = NULL;
+      FreeVectorMemory ( index,0 );
+      nData      = 0;
+      nAllocData = 0;
+    }
+
+
+    pstr GetMMCIFInputBuffer ( int & LineNo )  {
+      LineNo = _err_line;
+      _err_string[sizeof(_err_string)-1] = char(0);
+      return _err_string;
+    }
+
+    int  File::ReadMMCIFFile ( cpstr FName, io::GZ_MODE gzipMode )  {
+    io::File  f;
+    PData     CIF;
+    char      S[500];
+    int       RC,lcount;
+
+      FreeMemory();
+
+      CIF = NULL;
+      f.assign ( FName,true,false,gzipMode );
+      if (f.reset(true))  {
+        S[0]   = char(0);
+        lcount = 0;
+        RC     = 0;
+        while ((!RC) && (!f.FileEnd()))  {
+          if (!CIF)  CIF = new Data();
+          CIF->SetPrintWarnings ( PrintWarnings );
+          CIF->SetStopOnWarning ( StopOnWarning );
+          RC = CIF->ReadMMCIFData ( f,S,lcount );
+          if (!RC)  {
+            ExpandData ( nData+1 );
+            data[nData] = CIF;
+            nData++;
+            CIF = NULL;
+          }
+        }
+        if (CIF)  delete CIF;
+        f.shut();
+        if (RC==CIFRC_NoDataLine)  {
+          if (nData>0)  RC = 0;
+        }
+        Sort();
+        return RC;
+      } else
+        return CIFRC_CantOpenFile;
+
+    }
+
+    int File::WriteMMCIFFile ( cpstr FName, io::GZ_MODE gzipMode )  {
+    io::File f;
+      f.assign ( FName,true,false,gzipMode );
+      if (f.rewrite())  {
+        WriteMMCIF ( f );
+        f.shut();
+        return 0;
+      } else
+        return CIFRC_CantOpenFile;
+    }
+
+    void File::WriteMMCIF ( io::RFile f )  {
+    int i;
+      for (i=0;i<nData;i++)
+        if (data[i])
+          data[i]->WriteMMCIF ( f );
+    }
+
+
+    void File::Sort()  {
+    psvector tag;
+    int      i;
+      if (nData>0)  {
+        FreeVectorMemory ( index,0 );
+        GetVectorMemory  ( index,nData,0 );
+        GetVectorMemory  ( tag  ,nData,0 );
+        for (i=0;i<nData;i++)  {
+          tag[i] = NULL;
+          CreateCopy ( tag[i],data[i]->name );
+        }
+        SortTags ( tag,nData,index );
+        for (i=0;i<nData;i++)
+          if (tag[i])  {
+            delete[] tag[i];
+            tag[i] = NULL;
+          }
+        FreeVectorMemory ( tag,0 );
+      }
+    }
+
+    int  File::GetCIFDataNo ( cpstr DName )  {
+    //   Binary search for index of DName ttag in data[].
+    // Return:
+    //    >=0 : position of the DName found
+    //     <0 : the DName was not found, it could be inserted before
+    //          (-RC-1)th element, where RC is the return value
+    int l1,l2,l,k;
+
+      if (!data)   return -1;
+      if (!index)  Sort();
+
+      l  = 0;
+      l1 = 0;
+      l2 = nData-1;
+      k  = 1;
+      while (l1<l2-1)  {
+        l = (l1+l2)/2;
+        k = strcasecmp ( DName,data[index[l]]->name );
+        if (k<0)      l2 = l;
+        else if (k>0) l1 = l;
+        else  {
+          l1 = l;
+          break;
+        }
+      }
+
+      if (k==0)  return index[l];    // is at RCth position
+      k = strcasecmp ( DName,data[index[l1]]->name );
+      if (k==0)  return index[l1];   // is at RCth position
+      if (k<0)   return -1;          // would be at (-RC-1)th position
+      if (l2!=l1)  {
+        k = strcasecmp ( DName,data[index[l2]]->name );
+        if (k==0)  return index[l2]; // is at RCth position
+        if (k>0)   return -2-l2;     // would be at l2+1=(-RC-1)th position
+      }
+
+      return -2-l1;                  // would be at l1+1=(-RC-1)th position
+
+    }
+
+    PData  File::GetCIFData ( int dataNo )  {
+      if ((dataNo>=0) && (dataNo<nData))  return data[dataNo];
+                                    else  return NULL;
+    }
+
+    PData  File::GetCIFData ( cpstr DName )  {
+    int l;
+      l = GetCIFDataNo ( DName );
+      if (l>=0)  return data[l];
+           else  return NULL;
+    }
+
+    void File::ExpandData ( int nDataNew )  {
+    int          i,nAD;
+    PPData data1;
+    ivector      index1;
+      if (nDataNew>nAllocData)  {
+        nAD   = nDataNew + IMin(nAllocData/2+1,100);
+        data1 = new PData[nAD];
+        GetVectorMemory ( index1,nAD,0 );
+        for (i=0;i<nAllocData;i++)  {
+          data1 [i] = data [i];
+          index1[i] = index[i];
+        }
+        for (i=nAllocData;i<nAD;i++)  {
+          data1 [i] = NULL;
+          index1[i] = i;
+        }
+        if (data)  delete[] data;
+        FreeVectorMemory ( index,0 );
+        data       = data1;
+        index      = index1;
+        nAllocData = nAD;
+      }
+    }
+
+    int  File::AddCIFData ( cpstr DName )  {
+    //  return -1: the CIF data structure has been added on the
+    //             top of data array; the index is added and sorted
+    //             automatically
+    //        >=0: the CIF data structure is already in the array
+    //             -- its position is returned
+    int  i1,i;
+      if (!data)  {
+        ExpandData ( 3 );  // get space for first 3 CIF data structures
+        data[0] = new Data ( DName );
+        nData   = 1;
+        return -nData;     // the CIF data structure has been added
+                           // "on the top" of array
+      }
+      i1 = GetCIFDataNo ( DName );
+      if (i1>=0)  return i1;  // non-negative returns mean that the CIF
+                              // data structure is already in the array
+      i1 = -i1-1;  // otherwise the data has to be added and indexed at here
+      // put new CIF data structure on the top of array and update index
+      ExpandData ( nData+1 );
+      data[nData] = new Data ( DName );
+      for (i=nData;i>i1;i--)
+        index[i] = index[i-1];
+      index[i1] = nData;
+      nData++;
+      return -nData; // the tag has been added on the top of array
+    }
+
+
+    int File::DeleteCIFData ( cpstr DName )  {
+    int dataNo = GetCIFDataNo ( DName );
+
+      if (dataNo>=0)  return DeleteCIFData ( dataNo );
+      return dataNo;
+
+    }
+
+    int File::DeleteCIFData ( int dataNo )  {
+    int i;
+
+      if ((0<=dataNo) && (dataNo<nData))  {
+
+        if (data[dataNo])  delete data[dataNo];
+        for (i=dataNo+1;i<nData;i++)
+          data[i-1] = data[i];
+        nData--;
+
+        Sort();
+
+        return 0;
+
+      }
+
+      return -nData;
+
+    }
+
+    void File::Copy  ( PFile File )  {
+    int i;
+      FreeMemory();
+      nData      = File->nData;
+      nAllocData = nData;
+      if (nData>0)  {
+        data = new PData[nData];
+        for (i=0;i<nData;i++)  {
+          if (File->data[i])  {
+            data[i] = new Data();
+            data[i]->Copy ( File->data[i] );
+          } else
+            data[i] = NULL;
+        }
+      }
+    }
+
+
+    void File::write ( io::RFile f )  {
+    int i,k;
+      f.WriteInt ( &nData );
+      for (i=0;i<nData;i++)
+        if (data[i])  {
+          k = 1;
+          f.WriteInt ( &k );
+          data[i]->write ( f );
+        } else  {
+          k = 0;
+          f.WriteInt ( &k );
+        }
+    }
+
+    void File::read  ( io::RFile f )  {
+    int i,k;
+      FreeMemory();
+      f.ReadInt ( &nData );
+      nAllocData = nData;
+      if (nData>0)  {
+        data = new PData[nData];
+        for (i=0;i<nData;i++)  {
+          f.ReadInt ( &k );
+          if (k)  {
+            data[i] = new Data();
+            data[i]->read ( f );
+          } else
+            data[i] = NULL;
+        }
+      }
+    }
+
+
+    MakeStreamFunctions(File)
+
+
+    int  isCIF ( cpstr FName, io::GZ_MODE gzipMode )  {
+    io::File f;
+    int      rc;
+
+      f.assign ( FName,true,false,gzipMode );
+      if (f.reset(true))  {
+        rc = isCIF ( f );
+        f.shut();
+      } else
+        rc = -1;
+
+      return rc;
+
+    }
+
+    int  isCIF ( io::RFile f )  {
+    char    S[_max_buf_len+1];
+    bool Done;
+    pstr    p;
+
+      f.ReadLine ( S,_max_buf_len );
+      S[_max_buf_len] = char(0);
+      Done = false;
+      while (!Done)  {
+        p = &(S[0]);
+        while ((*p==' ') || (*p==char(9)))  p++;
+        Done = !strncmp(p,"data_",5);
+        if (!Done)  {
+          if (f.FileEnd())  {
+            Done = true;
+            p    = NULL;
+          } else  {
+            f.ReadLine ( S,_max_buf_len );
+            S[_max_buf_len] = char(0);
+          }
+        }
+      }
+
+      if (!p)  return 1;
+      if (!strncmp(p,"data_",5))  return 0;
+                            else  return 1;
+
+    }
+
+
+    pstr GetCIFMessage ( pstr M, int RC )  {
+    int  LineNo;
+    pstr InputLine;
+
+      InputLine = GetMMCIFInputBuffer ( LineNo );
+
+      if (RC>10)  {
+        if (RC & CIFW_UnrecognizedItems)
+          sprintf ( M,"unrecognized items found on %ith line\n%s",
+                    LineNo,InputLine );
+        else if (RC & CIFW_MissingField)
+          sprintf ( M,"expected data field not found; line %i reads\n%s",
+                    LineNo,InputLine );
+        else if (RC & CIFW_EmptyLoop)
+          sprintf ( M,"empty loop ('loop_') on %ith line\n%s",
+                    LineNo,InputLine );
+        else if (RC & CIFW_UnexpectedEOF)
+          sprintf ( M,"unexpected end of file; line %i reads\n%s",
+                    LineNo,InputLine );
+        else if (RC & CIFW_LoopFieldMissing)
+          sprintf ( M,"expected data field in a loop not found; "
+                      "line %i reads\n%s", LineNo,InputLine );
+        else if (RC & CIFW_LoopFieldMissing)
+          sprintf ( M,"expected data field in a loop not found; "
+                      "line %i reads\n%s", LineNo,InputLine );
+        else if (RC & CIFW_NotAStructure)
+          sprintf ( M,"a loop is used as a structure on line %i\n%s",
+                    LineNo,InputLine );
+        else if (RC & CIFW_NotALoop)
+          sprintf ( M,"a structure is used as a loop on line %i\n%s",
+                    LineNo,InputLine );
+        else if (RC & CIFW_DuplicateTag)
+          sprintf ( M,"duplicate tag was found on line %i\n%s",
+                    LineNo,InputLine );
+        else
+          sprintf ( M,"undocumented warning issued for line %i\n%s",
+                    LineNo,InputLine );
+      } else if (RC<0)
+        switch (RC)  {
+          case CIFRC_StructureNoTag : strcpy(M,"tag of a structure not "
+                                               "found");
+                                 break;
+          case CIFRC_LoopNoTag      : strcpy(M,"tag of a loop not found");
+                                 break;
+          case CIFRC_NoCategory     : strcpy(M,"category not found");
+                                 break;
+          case CIFRC_WrongFormat    : strcpy(M,"wrong format of a number");
+                                 break;
+          case CIFRC_NoTag          : strcpy(M,"tag not found");
+                                 break;
+          case CIFRC_NotAStructure  : strcpy(M,"category is not a "
+                                               "structure");
+                                 break;
+          case CIFRC_NotALoop       : strcpy(M,"category is not a loop");
+                                 break;
+          case CIFRC_WrongIndex     : strcpy(M,"index outside the loop's "
+                                               "limits");
+                                 break;
+          case CIFRC_NoField        : strcpy(M,"data is absent");
+                                 break;
+          case CIFRC_Created        : strcpy(M,"category created");
+                                 break;
+          case CIFRC_CantOpenFile   : strcpy(M,"can't open CIF file");
+                                 break;
+          case CIFRC_NoDataLine     : strcpy(M,"'data_' tag not found." );
+                                 break;
+          default                   : strcpy(M,"undocumented return code");
+        }
+
+      return M;
+
+    }
+
+  }  // namespace mmcif
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_mmcif_.h b/mmdb2/mmdb_mmcif_.h
new file mode 100644
index 0000000..388a24f
--- /dev/null
+++ b/mmdb2/mmdb_mmcif_.h
@@ -0,0 +1,2146 @@
+//  $Id: mmdb_mmcif_.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_MMCIF <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::mmcif::Category ( mmCIF category    )
+//       ~~~~~~~~~  mmdb::mmcif::Struct   ( mmCIF structure   )
+//                  mmdb::mmcif::Loop     ( mmCIF loop        )
+//                  mmdb::mmcif::Data     ( mmCIF data block  )
+//                  mmdb::mmcif::File     ( mmCIF file        )
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#ifndef __MMDB_MMCIF__
+#define __MMDB_MMCIF__
+
+
+#include "mmdb_io_stream.h"
+
+namespace mmdb  {
+
+  namespace mmcif  {
+
+
+    //  ======================  Category  ==========================
+
+    enum MMCIF_ITEM  {
+      MMCIF_Category = 0,
+      MMCIF_Struct   = 1,
+      MMCIF_Loop     = 2,
+      MMCIF_Data     = 3
+    };
+
+    DefineClass(Category);
+    DefineStreamFunctions(Category);
+
+    /// \brief mmcif::Category is a base class for mmcif::Struct and
+    ///        mmcif::Loop, implementations of mmCIF's "structure" and
+    ///        "loop" categories.
+    /*!
+    This class is not instantiated independently in any applications,
+    however, it provides a few public functions which work for
+    both mmcif::Struct and mmcif::Loop.
+
+    All data in mmCIF hierarchy is addressed using construct
+    "category.tag" plus row number (>=0) for loops. Category names
+    should always start from underscore, while tags normally start
+    with a letter, e.g. "_barrel.id".
+
+    See general principles of working with mmCIF files and mmCIF
+    hierarchies in Section \"\ref mmcif_handler\".
+    */
+
+    class Category : public io::Stream  {
+
+      friend class Data;
+
+      public :
+
+        /// \brief Basic constructor.
+        Category ();
+
+        /// \brief Constructor that assigns category name.
+        /// \param[in] N category name (must start with underscore).
+        Category ( cpstr N );
+
+        /// \brief Constructor for MMDB data streaming functions.
+        Category ( io::RPStream Object );
+
+        /// \brief Destructor.
+        ~Category();
+
+        /// \brief Returns category name.
+        /// \return NULL if name was not set
+        /// \return pointer to character string if name was set
+        inline pstr   GetCategoryName() { return name; }
+
+        /// \brief Sets category name.
+        /// \param N new category name
+        void   SetCategoryName ( cpstr N );
+
+        /// \brief Returns category type.
+        /// This function may be used when retrieving categories
+        /// (structures and loops) from data blocks (mmcif::Data).
+        /// \return MMCIF_Category for mmcif::Category
+        /// \return MMCIF_Struct   for mmcif::Struct
+        /// \return MMCIF_Loop     for mmcif::Loop
+        virtual MMCIF_ITEM GetCategoryID() { return MMCIF_Category; }
+
+        /// \brief Virtual function for writing category's content
+        ///        into mmCIF file.
+        /// Default implementation does nothing.
+        virtual void WriteMMCIF ( io::RFile ) {}
+
+        /// \brief Virtual function for optimizig data structures.
+        /// Optimized data structures take less RAM and their indexes
+        /// are sorted for quicker access. Sorting is done automatically
+        /// as new data is added to the category. If the
+        /// category is edited (fields/data removed), it may need
+        /// optimization and re-sorting for efficiency.\n\n
+        /// The sorting preserves the order of actual appearance of
+        /// tags in mmCIF file. If a category is created
+        /// programmatically, the order of tags in mmCIF file will be
+        /// the same as order of adding them to the category.
+        virtual void Optimize();
+
+        /// \brief Sorts category's data for quicker access.
+        /// The sorting is essentially re-indexing of data for quicker
+        /// access. It does not change the order of data in both mmCIF
+        /// hierarchy and mmCIF file. E.g., if tag "serial_no" was 2nd
+        /// one in given category before sorting, it will remain on 2nd
+        /// place after it, therefore no change in tag number passed
+        /// to functions in mmcif::Struct, mmcif::Loop and mmcif::Data.
+        void  Sort();
+
+        /// \brief Returns serial number of a tag in the category.
+        /// \param[in]  ttag tag (or name of a field in category)
+        /// \return \b >=0 : the tag is in given position
+        /// \return \b <0 : the tag was not found, but it could be
+        ///         inserted before tag with (-rc-1)th index, where
+        ///         'rc' is the return.
+        int   GetTagNo ( cpstr ttag );
+
+        /// \brief Adds a tag to the category.
+        /// Adding a tag in mmcif::Category does not reserve any
+        /// placeholder for the corresponding value. All tags get
+        /// automatically sorted (reindexed) for quicker access.
+        /// Tags will appear in mmCIF file in order of their addition
+        /// to the category.
+        /// \param[in]  ttag tag to be added.
+        /// \return \b >=0 the tag is already in the category, and return
+        ///             is its serial number. No changes to the category
+        ///             is done
+        /// \return \b <0  the tag was added to the list of tags, and
+        ///             return is minus total number of tags in the
+        ///             category.
+        int   AddTag ( cpstr ttag );
+
+        /// \brief Returns the total number of tags in the category
+        int   GetNofTags() { return nTags; }
+
+        /// \brief Returns tag with the specified serial number.
+        /// The tags are enumerated as 0..GetNofTags()-1.
+        /// \param tagNo tag's serial number
+        /// \return \b NULL: tagNo is outside the range
+        ///                  of 0..GetNofTags()-1
+        /// \return \b not \b NULL: tag in tagNo'th position
+        pstr  GetTag ( int tagNo );  // 0..nTags-1
+
+        /// \brief Prints list of tags to stdout.
+        /// Both sorted and unsorted tags are printed to standard
+        /// output. This function may be used for debugging.
+        void  PrintTags();
+
+        /// \brief Returns true if all tags from the list are found
+        ///        in the category.
+        /// The size of the list of tags may be less than the number
+        /// of tags in the category, and order of tags is disregarded.
+        /// \param[in] tagList  list of tags to be checked for presence
+        ///                 in the category. The list must end with NULL
+        ///                 pointer, or your program will crash.
+        /// \return \b true  if all tags from the list were found in the
+        ///               category
+        /// \return \b false if one or more tags from the list were not
+        ///               found in the category.
+        ///
+        /// Example:
+        /// \code
+        ///  cpstr tagList[] = {"id","type","date",NULL};
+        ///  mmcif::Struct cifStruct;
+        ///  if (cifStruct.CheckTags(tagList))
+        ///    printf ( " all tags are found in category %s\n",
+        ///             cifStruct.GetCategoryName() );
+        /// \endcode
+        /// This function is useful for finding categories in
+        /// "dirty cifs", where category name is not given.
+        bool CheckTags ( cpstr * tagList );
+
+        /// \brief Deep copy of categories.
+        /// Deep copy duplicates all data and memory allocations,
+        /// producing a genuine clone of the original. Only deep copy
+        /// should be used for copying MMDB objects, a mere assignment
+        /// operator will fail you.
+        /// \param[in] Category a pointer to mmcif::Category, the content of
+        ///                 which is copied into 'this' category.
+        virtual void Copy ( PCategory Category );
+
+        /// \brief MMDB stream writer.
+        void  write ( io::RFile f );
+
+        /// \brief MMDB stream reader.
+        void  read  ( io::RFile f );
+
+      protected:
+        int      nTags;
+        pstr     name;
+        psvector tag;
+        ivector  index;
+        int      nAllocTags;
+
+        void          InitCategory    ();
+        virtual void  FreeMemory      ();
+        void          ExpandTags      ( int nTagsNew );
+        void          PutCategoryName ( cpstr newName );
+
+    };
+
+
+
+    //  ======================  Struct  ============================
+
+    DefineClass(Struct);
+    DefineStreamFunctions(Struct);
+
+    /// \brief Constants used to specify mmCIF's \"data not given\" and
+    /// \"data not available\" data types.
+    extern const int CIF_NODATA_DOT;
+    extern const int CIF_NODATA_QUESTION;
+    extern cpstr     CIF_NODATA_DOT_FIELD;
+    extern cpstr     CIF_NODATA_QUESTION_FIELD;
+
+    /// \brief mmcif::Struct represents mmCIF's \"structure\" category,
+    ///        where data follows directly the corresponding tag.
+    /*!
+    mmCIF's \"structure\" category has the following form:
+    \code
+    _structure_name.tag0   value0
+    _structure_name.tag1   value1
+    ...........
+    _structure_name.tagN   valueN
+    \endcode
+    mmcif::Struct represents this construct by keeping category name
+    (\"_structure_name\") and associated lists of tags
+    (\"tag0,tag1...tagN\") and their values (\"value0,value1...valueN\").
+
+    The structure is created automatically when an mmCIF file is read,
+    or it may be created programatically and then pushed into file.
+
+    Access to data is provided via tags. Internally, all values are kept
+    as character fields, and it is only on the retrieval stage that they
+    are converted to other data types (integers, floats or strings).
+    If conversion is not possible, an error code is returned by the
+    corresponding functions, which should be checked by the application.
+
+    See general principles of working with mmCIF files and mmCIF
+    hierarchies, as well as some code samples, in Section
+    \"\ref mmcif_handler\".
+    */
+
+    class Struct : public Category  {
+
+      public :
+
+        /// \brief Basic constructor
+        Struct ();
+
+        /// \brief Constructor that assigns structure name.
+        /// \param[in] N structure name (must start with underscore).
+        Struct ( cpstr N );
+
+        /// \brief Constructor for MMDB data streaming functions
+        Struct ( io::RPStream Object );
+
+        /// \brief Destructor
+        ~Struct();
+
+        /// \brief Adds field to the structure.
+        /// \param[in] F field value
+        /// \param[in] T tag name
+        /// \param[in] Concatenate flag to concatenate existing field
+        ///            with the value of \b F. If tag \b T is already in
+        ///            the structure and \b Concatenate=true, then
+        ///            value of \b F is appended to the existing field.
+        ///            Otherwise, the field is replaced with the value
+        ///            of \b F
+        void AddField ( cpstr F, cpstr T, bool Concatenate=false );
+
+        /// \brief Returns category type \b MMCIF_Struct.
+        MMCIF_ITEM  GetCategoryID()  { return MMCIF_Struct; }
+
+        /// \brief Optimizes structure for RAM and data access speed.
+        /// Optimized data structures take less RAM and their indexes
+        /// are sorted for quicker access. Sorting is done automatically
+        /// as new data is added to the category. If the structure
+        /// is edited (fields/data removed), it may need
+        /// optimization and re-sorting for efficiency.\n\n
+        /// The sorting preserves the order of actual appearance of
+        /// tags in mmCIF file. If a structure is created
+        /// programmatically, the order of tags in mmCIF file will be
+        /// the same as order of adding them to the structure.
+        void Optimize();
+
+        /// \brief Returns value of field corresponding to tag in the
+        ///        specified position.
+        /// Tag positions are defined by the order of their appearance in
+        /// mmCIF file (if structure was read from a file), or by the
+        /// order of their addition to the structure (if structure was
+        /// created programmatically). Tags are numbered as
+        /// 0...GetNofTags()-1.
+        /// \param[in] tagNo tag number (position in the structure)
+        /// \return \b NULL: tag does not exist
+        /// \return \b CIF_NODATA_DOT_FIELD the field contains
+        ///            \"data not given\" value
+        /// \return \b CIF_NODATA_QUESTION_FIELD the field contains
+        ///            \"data not available\" value
+        /// \return \b not \b NULL: string value of the field
+        pstr GetField ( int tagNo );  // 0..nTags-1
+
+        /// \brief Fetches value, corresponding to the given tag, as
+        ///        a string
+        /// \param[out] S pointer to string, which will point to newly
+        ///               allocated character string, containing value
+        ///               associated with tag \b TName. If tag or value
+        ///               is not found, or if value corresponds to
+        ///               mmCIF's \"data not given\" or
+        ///               \"data not available\", \b S returns NULL.
+        /// \param[in] TName character string with tag name
+        /// \param[in] Remove flag to remove the tag and its value from
+        ///               structure after it is read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_NoField: value is not found
+        /// \return \b CIFRC_Ok: success. If \b S returns NULL, then
+        ///                the value corresponds to either
+        ///                \"data not available\" or
+        ///                \"data not given\".
+        /// \remarks If \b S!=NULL at time of call, the function will
+        ///  try to dispose the string it points on. This allows a slick
+        ///  re-use of the same pointer in consequitive calls. This also
+        ///  means that one should never pass unallocated pointer to
+        ///  this function. Safe use assumes the following patern:
+        ///  \code
+        ///  mmcif::Struct mmCIFStruct;
+        ///  pstr S;  // this is merely "char *S"
+        ///  int  rc;
+        ///
+        ///    S  = NULL; // null pointer before first use
+        ///    rc = mmCIFStruct.GetString ( S,"id" );
+        ///    if (rc)  CreateCopy ( S,"*** data not found" );
+        ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
+        ///    printf ( " rc=%i, S='%s'\n",rc,S );
+        ///
+        ///    rc = mmCIFStruct.GetString ( S,"property" );
+        ///    if (rc)  CreateCopy ( S,"*** data not found" );
+        ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
+        ///    printf ( " rc=%i, S='%s'\n",rc,S );
+        ///
+        ///    // etc etc etc
+        ///
+        ///    delete[] S;  // application is responsible for final
+        ///                 // disposal of memory
+        ///  \endcode
+        int  GetString ( pstr & S, cpstr TName, bool Remove=false );
+
+        /// \brief Returns pointer to value associated with given tag.
+        /// \param[in] TName character string with tag name
+        /// \param[out] RC return code:
+        ///    \arg \b CIFRC_NoTag: tag is not found
+        ///    \arg \b CIFRC_NoField: value is not found
+        ///    \arg \b CIFRC_Ok: success. If function returns NULL, then
+        ///                the value corresponds to either
+        ///                \"data not available\" or
+        ///                \"data not given\".
+        /// \return \b NULL: either tag or value is not found, or the
+        ///    value is \"data not available\" or \"data not given\".
+        ///    Read return code \b RC in order to interpret NULL return.
+        /// \return \b not \b NULL: pointer (\c char \c *) to value
+        ///    associated with \b TName.
+        /// \remarks Never try to dispose memory pointed by the return
+        /// value, or your program will crash.
+        pstr GetString ( cpstr TName, int & RC ); // NULL if TName
+                                                         // is not there
+
+        /// \brief Deletes field associated with given tag.
+        /// \param[in] TName character string with tag name
+        /// \return \b >=0: field deleted
+        /// \return \b <0: either field or tag is not found
+        int  DeleteField ( cpstr TName );  // <0 the field was not there
+
+        /// \brief Fetches value, corresponding to the given tag, as
+        ///        a real number.
+        /// \param[out] R reference to real number to accept the value.
+        ///        In case of failure, \b R returns zero.
+        /// \param[in] TName character string with tag name
+        /// \param[in] Remove flag to remove the tag and its value from
+        ///               structure after it is read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_NoField: field is not found
+        /// \return \b CIFRC_WrongFormat: value is not a real or integer
+        ///            number.
+        /// \return \b CIFRC_NoData: value is either
+        ///            \"data not available\" or
+        ///            \"data not given\".
+        /// \return \b CIFRC_Ok: success.
+        int  GetReal ( realtype & R, cpstr TName, bool Remove=false );
+
+        /// \brief Fetches value, corresponding to the given tag, as
+        ///        an integer number.
+        /// \param[out] I reference to integer number to accept the
+        ///        value. In case of failure, \b I returns zero, except
+        ///        when value is \"data not available\" or
+        ///        \"data not given\", when I returns \c MinInt4.
+        /// \param[in] TName character string with tag name
+        /// \param[in] Remove flag to remove the tag and its value from
+        ///               structure after it is read.
+        /// \return \arg \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_NoField: field is not found
+        /// \return \b CIFRC_WrongFormat: value is not an integer number.
+        /// \return \b CIFRC_NoData: value is either
+        ///            \"data not available\" or
+        ///            \"data not given\".
+        /// \return \b CIFRC_Ok: success.
+        int  GetInteger ( int & I, cpstr TName, bool Remove=false );
+
+        /// \brief Sets string value for given tag.
+        /// \param[in] S character string with value to be set.
+        ///            If \b S==NULL, the \"data not given\" value
+        ///            will be set. If \b S==\"\" (empty string), the
+        ///            \"data not available\" value is stored.
+        /// \param[in] TName character string with tag name. If tag
+        ///            is not found, it will be added to the structure.
+        /// \param[in] NonBlankOnly flag to treat white-space-only
+        ///            strings:
+        ///   \arg \b false: set as is
+        ///   \arg \b true:  set \"data not available\" value instead.
+        void PutString   ( cpstr S, cpstr TName,
+                           bool NonBlankOnly=false );
+
+        /// \brief Sets current date in format YYYY-MM-DD as a value
+        ///        for given tag.
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added to the structure.
+        void PutDate     ( cpstr T );
+
+        /// \brief Sets \"data not given\" or \"data not available\"
+        ///        values for given tag.
+        /// \param[in] NoDataType can be either
+        ///   \arg \b CIF_NODATA_DOT for \"data not given\"
+        ///   \arg \b CIF_NODATA_QUESTION for \"data not available\"
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added to the structure.
+        void PutNoData   ( int NoDataType, cpstr T  );
+
+        /// \brief Sets float-point value for given tag.
+        /// \param[in] R real number with value to be set.
+        /// \param[in] TName character string with tag name. If tag
+        ///            is not found, it will be added to the structure.
+        /// \param[in] prec float-point precision; g-format with given
+        ///            precision will be used
+        void PutReal     ( realtype R, cpstr TName, int prec=8 );
+
+        /// \brief Sets float-point value for given tag.
+        /// \param[in] R real number with value to be set.
+        /// \param[in] TName character string with tag name. If tag
+        ///            is not found, it will be added to the structure.
+        /// \param[in] format format string to convert \b R.
+        void PutReal     ( realtype R, cpstr TName, cpstr format );
+
+        /// \brief Sets integer value for given tag.
+        /// \param[in] I integer number with value to be set.
+        /// \param[in] TName character string with tag name. If tag
+        ///            is not found, it will be added to the structure.
+        void PutInteger  ( int      I, cpstr TName );
+
+        /// \brief Writes structure data in mmCIF format into file.
+        /// \param[in] FName character string with file name.
+        /// \param[in] gzipMode flag to controll compression of files:
+        ///  \arg \b GZM_NONE: do not compress
+        ///  \arg \b GZM_CHECK: check file name suffix and compress
+        ///                     (or not) accordingly
+        ///  \arg \b GZM_ENFORCE_GZIP: force gzip compression despite
+        ///                     suffix
+        ///  \arg \b GZM_ENFORCE_COMPRESS: force using compress despite
+        ///                     suffix
+        ///  \return \b true: success
+        ///  \return \b false: can not open file for writing.
+        /// \remarks This function does not create a valid mmCIF file
+        /// as \"data_XXX\" record will be missing. It may be used for
+        /// debugging though.
+        bool WriteMMCIFStruct ( cpstr FName,
+                                io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+        /// \brief Writes structure into given file.
+        /// \param f reference to MMDB's file class. The file should be
+        /// opened and closed by application.
+        /// \remarks There is a very limited use of this function on
+        /// application level. It is primarily used by mmcif::Data class.
+        void    WriteMMCIF ( io::RFile f  );
+
+        /// \brief Deep copy of structures.
+        /// Deep copy duplicates all data and memory allocations,
+        /// producing a genuine clone of the original. Only deep copy
+        /// should be used for copying MMDB objects, a mere assignment
+        /// operator will fail you.
+        /// \param[in] Struct a pointer to mmcif::Struct, the content of
+        ///                 which is copied into 'this' structure.
+        void Copy ( PCategory Struct );
+
+        /// \brief MMDB stream writer.
+        void write ( io::RFile f );
+
+        /// \brief MMDB stream reader.
+        void read  ( io::RFile f );
+
+      protected:
+        psvector field;
+
+        void InitStruct();
+        void FreeMemory();
+
+    };
+
+
+
+    //  ======================  Loop  ==============================
+
+    DefineClass(Loop);
+    DefineStreamFunctions(Loop);
+
+    /// \brief mmcif::Loop represents mmCIF's \"loop\" category, which keeps
+    ///        rows of data values associated with tags.
+    /*!
+    mmCIF's \"loop\" category has the following form:
+    \code
+    loop_
+    _loop_name.tag0   value0
+    _loop_name.tag1   value1
+    ...........
+    _loop_name.tagN   valueN
+    value00 value10 ... valueN0
+    value01 value11 ... valueN1
+    ...........
+    value0M value1M ... valueNM
+    \endcode
+    mmcif::Loop represents this construct by keeping category name
+    (\"_loop_name\") and associated lists of tags
+    (\"tag0,tag1...tagN\") and data vectors
+    (\"[value00...value0M],[value10...value1M]...[valueN0...valueNM]\").
+
+    The loop object is created automatically when an mmCIF file is read,
+    or it may be created programatically and then pushed into file.
+
+    Access to data is provided via tags and data indexes. Internally,
+    all values are kept as character fields, and it is only on the
+    retrieval stage that they are converted to other data types
+    (integers, floats or strings). If conversion is not possible, an
+    error code is returned by the corresponding functions, which should
+    be checked by the application.
+
+    The following code gives an example of creating mmCIF loop category
+    and populating it with data:
+    \code
+    mmcif::Loop loop;
+    char       S[100];
+    int        i;
+
+      // Specify loop name:
+      loop.SetCategoryName ( "_sample_loop" );
+
+      // Create loop structure, i.e., list of tags first:
+      loop.AddLoopTag ( "id"    );
+      loop.AddLoopTag ( "name"  );
+      loop.AddLoopTag ( "value" );
+
+      // Now populate it with data. This my be done in 2 ways.
+      // Here is how you write loop data in stream fashion,
+      // value-after-value:
+      for (i=0;i<3;i++)  {
+        loop.AddInteger ( i );
+        sprintf ( S,"1st_way-%i",i );
+        loop.AddString ( S );
+        loop.AddReal ( 2.5*(i+1) );
+      }
+
+      // Here is how you populate loop data using direct-access
+      // functions:
+      for (i=3;i<6;i++)  {
+        loop.PutReal ( 2.5*(i+1),"value",i );
+        loop.PutInteger ( i,"id" );
+        sprintf ( S,"2nd way: %i",i );
+        loop.PutString ( S,"name" );
+      }
+
+      loop.WriteMMCIFLoop ( "sample_loop.cif" );
+
+    \endcode
+
+    The resulting file \b sample_loop.cif will contain:
+
+    \code
+
+    loop_
+    _sample_loop.id
+    _sample_loop.name
+    _sample_loop.value
+    0   1st_way-0     2.5
+    1   1st_way-1     5.0
+    2   1st_way-2     7.5
+    3   "2nd way: 3"  10.0
+    4   "2nd way: 4"  12.5
+    5   "2nd way: 5"  15.0
+
+    \endcode
+
+    See general principles of working with mmCIF files and mmCIF
+    hierarchies, as well as some code samples, in Section
+    \"\ref mmcif_handler\".
+    */
+
+    class Loop : public Category  {
+
+      friend class Data;
+
+      public :
+
+        /// \brief Basic constructor
+        Loop ();
+
+        /// \brief Constructor that assigns structure name.
+        /// \param[in] N structure name (must start with underscore).
+        Loop ( cpstr N );
+
+        /// \brief Constructor for MMDB data streaming functions
+        Loop ( io::RPStream Object );
+
+        /// \brief Destructor
+        ~Loop();
+
+        /// \brief Adds tag to the loop.
+        /// The tag is appended to the list of existing tags. The order
+        /// of tags cannot be changed.
+        /// \param[in] T tag name
+        /// \param[in] Remove flag to remove all fields in the loop.
+        void  AddLoopTag ( cpstr T, bool Remove=true );
+
+        /// \brief Sets string value at current loop position.
+        /// When \b mmcif::Loop::Add[Data] functions use internal loop
+        /// pointer. When category is created or cleared (by using
+        /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+        /// 0th row and 0th column (tag). After each call to
+        /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+        /// to next column (tag), and wraps over to next row, 0th tag,
+        /// if list of tags is exhausted. Any remaining fields in last
+        /// row will be populated with \"data not given\" value.
+        /// \param[in] S character string with value to be set.
+        ///            If \b S==NULL, the \"data not given\" value
+        ///            will be set. If \b S==\"\" (empty string), the
+        ///            \"data not available\" value is stored.
+        /// \param[in] NonBlankOnly flag to treat white-space-only
+        ///            strings:
+        ///   \arg \b false: set as is
+        ///   \arg \b true:  set \"data not available\" value instead.
+        void  AddString ( cpstr S, bool NonBlankOnly=false );
+
+        /// \brief Sets \"data not given\" or \"data not available\" at
+        ///        current loop position.
+        /// When \b mmcif::Loop::Add[Data] functions use internal loop
+        /// pointer. When category is created or cleared (by using
+        /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+        /// 0th row and 0th column (tag). After each call to
+        /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+        /// to next column (tag), and wraps over to next row, 0th tag,
+        /// if list of tags is exhausted. Any remaining fields in last
+        /// row will be populated with \"data not given\" value.
+        /// \param[in] NoDataType integer key specifying which type of
+        ///            data absence should be set as a value:
+        ///   \arg \b CIF_NODATA_DOT for \"data not given\"
+        ///   \arg \b CIF_NODATA_QUESTION for \"data not available\"
+        void  AddNoData ( int NoDataType );
+
+        /// \brief Sets float-point value at current loop position.
+        /// When \b mmcif::Loop::Add[Data] functions use internal loop
+        /// pointer. When category is created or cleared (by using
+        /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+        /// 0th row and 0th column (tag). After each call to
+        /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+        /// to next column (tag), and wraps over to next row, 0th tag,
+        /// if list of tags is exhausted. Any remaining fields in last
+        /// row will be populated with \"data not given\" value.
+        /// \param[in] R real number with value to be set.
+        /// \param[in] prec float-point precision; g-format with given
+        ///            precision will be used
+        void  AddReal ( realtype R, int prec=8 );
+
+        /// \brief Sets float-point value at current loop position in
+        ///        given format.
+        /// When \b mmcif::Loop::Add[Data] functions use internal loop
+        /// pointer. When category is created or cleared (by using
+        /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+        /// 0th row and 0th column (tag). After each call to
+        /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+        /// to next column (tag), and wraps over to next row, 0th tag,
+        /// if list of tags is exhausted. Any remaining fields in last
+        /// row will be populated with \"data not given\" value.
+        /// \brief Sets float-point value for given tag.
+        /// \param[in] R real number with value to be set.
+        /// \param[in] format format string to convert \b R.
+        void  AddReal ( realtype R, cpstr format );
+
+        /// \brief Sets integer value at current loop position in given
+        ///        format.
+        /// When \b mmcif::Loop::Add[Data] functions use internal loop
+        /// pointer. When category is created or cleared (by using
+        /// \b mmcif::Loop::AddLoopTag ( T,true )) the pointer is set to
+        /// 0th row and 0th column (tag). After each call to
+        /// \b mmcif::Loop::Add[Data] function, internal pointer advances
+        /// to next column (tag), and wraps over to next row, 0th tag,
+        /// if list of tags is exhausted. Any remaining fields in last
+        /// row will be populated with \"data not given\" value.
+        /// \param[in] I integer number with value to be set.
+        void  AddInteger ( int I );
+
+        /// \brief Returns current length of the loop (i.e. the number
+        ///        of rows).
+        /// \return number of data rows in the loop.
+        int   GetLoopLength() { return nRows; }
+
+        /// \brief Returns string pointer on the field corresponding to
+        ///        tag in the specified position, in the specified row.
+        /// Tag positions are defined by the order of their appearance in
+        /// mmCIF file (if loop was read from a file), or by the
+        /// order of their addition to the loop (if loop was
+        /// created programmatically).
+        /// \param[in] rowNo row number (0...GetLoopLength()-1)
+        /// \param[in] tagNo tag number (0...GetNofTags()-1)
+        /// \return \b NULL: tag or row do not exist
+        /// \return \b CIF_NODATA_DOT_FIELD the field contains
+        ///            \"data not given\" value
+        /// \return \b CIF_NODATA_QUESTION_FIELD the field contains
+        ///            \"data not available\" value
+        /// \return \b not \b NULL: string value of the field
+        /// \remarks Never try to dispose memory pointed by the return
+        /// value, or your program will crash.
+        pstr  GetField ( int rowNo, int tagNo );
+
+        /// \brief Fetches value, corresponding to the given tag, in
+        ///        the given row, as a string
+        /// \param[out] S pointer to string, which will point to newly
+        ///               allocated character string, containing value
+        ///               associated with tag \b TName and row \b nrow.
+        ///               If tag, row or value
+        ///               is not found, or if value corresponds to
+        ///               mmCIF's \"data not given\" or
+        ///               \"data not available\", \b S returns NULL.
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[in] Remove flag to remove the field from
+        ///               structure after it is read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_WrongIndex: row is not found
+        /// \return \b CIFRC_NoField: value is not found
+        /// \return \b CIFRC_Ok: success. If \b S returns NULL, then
+        ///                the value corresponds to either
+        ///                \"data not available\" or
+        ///                \"data not given\".
+        /// \remarks If \b S!=NULL at time of call, the function will
+        ///  try to dispose the string it points on. This allows a slick
+        ///  re-use of the same pointer in consequitive calls. This also
+        ///  means that one should never pass unallocated pointer to
+        ///  this function. Safe use assumes the following patern:
+        ///  \code
+        ///  mmcif::Loop mmCIFLoop;
+        ///  pstr S;  // this is merely "char *S"
+        ///  int  rc;
+        ///
+        ///    S  = NULL; // null pointer before first use
+        ///    rc = mmCIFLoop.GetString ( S,"id",1 );
+        ///    if (rc)  CreateCopy ( S,"*** data not found" );
+        ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
+        ///    printf ( " rc=%i, S='%s'\n",rc,S );
+        ///
+        ///    rc = mmCIFLoop.GetString ( S,"property",0 );
+        ///    if (rc)  CreateCopy ( S,"*** data not found" );
+        ///    if (!S)  CreateCopy ( S,"*** data not given or not available" );
+        ///    printf ( " rc=%i, S='%s'\n",rc,S );
+        ///
+        ///    // etc etc etc
+        ///
+        ///    delete[] S;  // application is responsible for final
+        ///                 // disposal of memory
+        ///  \endcode
+        int   GetString ( pstr & S, cpstr TName, int nrow,
+                                           bool Remove=false );
+
+        /// \brief Returns pointer to value associated with given tag,
+        ///        in the given row of the loop.
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[out] RC return code:
+        ///    \arg \b CIFRC_NoTag: tag is not found
+        ///    \arg \b CIFRC_WrongIndex: row is not found
+        ///    \arg \b CIFRC_NoField: value is not found
+        ///    \arg \b CIFRC_Ok: success. If function returns NULL, then
+        ///                the value corresponds to either
+        ///                \"data not available\" or
+        ///                \"data not given\".
+        /// \return \b NULL: either tag, row or value is not found, or the
+        ///    value is \"data not available\" or \"data not given\".
+        ///    Read return code \b RC in order to interpret NULL return.
+        /// \return \b not \b NULL: pointer (\c char \c *) to value
+        ///    associated with \b TName.
+        /// \remarks Never try to dispose memory pointed by the return
+        /// value, or your program will crash.
+        pstr  GetString    ( cpstr TName, int nrow, int & RC );
+
+        /// \brief Copies value, associated with given tag,
+        ///        in the given row, into specified buffer.
+        ///  Terminating NULL character is appended.
+        /// \param[out] buf character string to accept the value
+        /// \param[in] maxlength maximum number of bytes to copy
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[out] RC return code:
+        ///    \arg \b CIFRC_NoTag: tag is not found
+        ///    \arg \b CIFRC_WrongIndex: row is not found
+        ///    \arg \b CIFRC_NoField: value is not found
+        ///    \arg \b CIFRC_Ok: success.
+        /// \remarks Destination string \b buf is not modified if
+        /// \b RC!=CIFRC_Ok .
+        void  CopyString   ( pstr  buf,   int maxlength,
+                             cpstr TName, int nrow, int & RC );
+
+        /// \brief Deletes field associated with given tag in
+        ///          the given row.
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \return \b >=0: field deleted
+        /// \return \b <0: either field or tag is not found
+        int   DeleteField  ( cpstr TName, int nrow );
+
+        /// \brief Deletes all fields in given row.
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \return \b CIFRC_Ok: fields deleted
+        /// \return \b CIFRC_WrongIndex: row not found
+        /// \remarks Note that this function delets just the fields, but
+        /// not the row. If you wish the row to be deleted, call
+        /// mmcif::Loop::Optimize() function after this one.
+        int   DeleteRow    ( int nrow );
+
+        /// \brief Fetches value, corresponding to the given tag,
+        ///        in the given row, as a real number.
+        /// \param[out] R reference to real number to accept the value.
+        ///        In case of failure, \b R returns zero.
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[in] Remove flag to remove the field from
+        ///               the loop after it is read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_WrongIndex: row not found
+        /// \return \b CIFRC_NoField: field is not found
+        /// \return \b CIFRC_WrongFormat: value is not a real or integer
+        ///            number.
+        /// \return \b CIFRC_NoData: value is either
+        ///            \"data not available\" or
+        ///            \"data not given\".
+        /// \return \b CIFRC_Ok: success.
+        int   GetReal ( realtype & R, cpstr TName, int nrow,
+                                           bool Remove=false );
+
+        /// \brief Copies value, associated with given tag,
+        ///        in the given row, into specified destination as
+        ///        a real number.
+        /// \param[out] R reference to real number to accept the value
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[out] RC return code:
+        ///    \arg \b CIFRC_NoTag: tag is not found
+        ///    \arg \b CIFRC_WrongIndex: row is not found
+        ///    \arg \b CIFRC_NoField: value is not found
+        ///    \arg \b CIFRC_Ok: success.
+        /// \remarks Destination \b R is set 0 if \b RC!=CIFRC_Ok.
+        void  CopyReal ( realtype & R, cpstr TName, int nrow, int & RC );
+
+        /// \brief Copies value, associated with given tag,
+        ///        in the given row, into specified destination as
+        ///        an integer number.
+        /// \param[out] I reference to integer number to accept the value
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[out] RC return code:
+        ///    \arg \b CIFRC_NoTag: tag is not found
+        ///    \arg \b CIFRC_WrongIndex: row is not found
+        ///    \arg \b CIFRC_NoField: value is not found
+        ///    \arg \b CIFRC_Ok: success.
+        /// \remarks Destination \b I is set 0 if \b RC!=CIFRC_Ok.
+        void  CopyInteger ( int & I, cpstr TName, int nrow, int & RC );
+
+        /// \brief Fetches value, corresponding to the given tag,
+        ///        in the given row, as an integer number.
+        /// \param[out] I reference to integer number to accept the value.
+        ///        In case of failure, \b R returns zero.
+        /// \param[in] TName character string with tag name
+        /// \param[in] nrow  row number (0...GetLoopLength()-1)
+        /// \param[in] Remove flag to remove the field from
+        ///               the loop after it is read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_WrongIndex: row not found
+        /// \return \b CIFRC_NoField: field is not found
+        /// \return \b CIFRC_WrongFormat: value is not a real or integer
+        ///            number.
+        /// \return \b CIFRC_NoData: value is either
+        ///            \"data not available\" or
+        ///            \"data not given\".
+        /// \return \b CIFRC_Ok: success.
+        int   GetInteger   ( int & I, cpstr TName, int nrow,
+                                           bool Remove=false );
+
+        /// \brief Fetches set of values, corresponding to the given
+        ///        tag, in the given range of rows, as a vector of
+        ///        strings.
+        /// \param[out] S reference to string vector to accept
+        ///        the values. if \b S==NULL , the vector will be
+        ///        allocated with starting index of \b i1.
+        /// \param[in] TName character string with tag name
+        /// \param[in] i1  minimum row number to fetch, the actual
+        ///            index will be calculated as \b max(0,min(i1,i2))
+        /// \param[in] i2  maximum row number to fetch, the actual
+        ///            index will be calculated as
+        ///            \b min(GetLoopLength()-1,max(i1,i2))
+        /// \param[in] Remove flag to remove fetched fields from
+        ///               the loop after they are read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_WrongIndex: invalid range of rows
+        /// \return \b CIFRC_Ok: success.
+        ///
+        /// For safe use, \b S should be pre-allocated by calling
+        /// process. Only elements \b S[i1] to \b S[i2] will contain
+        /// fetched data, others remain untouched. The calling
+        /// process is responsible for the disposal of \b S. Example:
+        /// \code
+        /// mmcif::Loop loop;
+        /// psvector   S;  // equivalent to char **S
+        /// int        i,i1,i2,rc,n;
+        ///
+        ///    // ... get loop data
+        ///
+        ///    n  = loop.GetLoopLength();
+        ///    i1 = 5;  i2 = n - 5;  // could be wrong!
+        ///
+        ///    //  allocate vector of strings
+        ///    GetVectorMemory ( S,n,0 );  // "0" for starting index
+        ///    for (i=0;i<n;i++)
+        ///      S[i] = NULL;  // initialize NULL string pointers
+        ///
+        ///    loop.GetSVector ( S,"name",i1,i2 );
+        ///    printf ( " Fetched with return code rc=%i\n",rc );
+        ///        // you may want a more thorough treatment of
+        ///        // the return code here
+        ///    for (i=i1;i<=i2;i++)
+        ///      if (S[i])  printf ( " %4i. name='%s'\n",i,S[i] );
+        ///           else  printf ( " %4i. name is not available\n",i );
+        ///
+        ///    //  S[] may be re-used for as many fetches as necessary
+        ///    //  without cleaning or disposals
+        ///
+        ///    //  dispose of vector of strings
+        ///    for (i=0;i<n;i++)
+        ///      if (S[i])  delete[] S[i];
+        ///    FreeVectorMemory ( S,0 );  // "0" for starting index
+        ///
+        /// \endcode
+        int  GetSVector ( psvector & S, cpstr TName,
+                          int i1=0, int i2=MaxInt4,
+                          bool Remove=false );
+
+        /// \brief Fetches set of values, corresponding to the given
+        ///        tag, in the given range of rows, as a vector of
+        ///        float-point numbers.
+        /// \param[out] R reference to float-point vector to accept
+        ///        the values. if \b R==NULL , the vector will be
+        ///        allocated with starting index of \b i1.
+        /// \param[in] TName character string with tag name
+        /// \param[in] i1  minimum row number to fetch, the actual
+        ///            index will be calculated as \b max(0,min(i1,i2))
+        /// \param[in] i2  maximum row number to fetch, the actual
+        ///            index will be calculated as
+        ///            \b min(GetLoopLength()-1,max(i1,i2))
+        /// \param[in] Remove flag to remove fetched fields from
+        ///               the loop after they are read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_WrongIndex: invalid range of rows
+        /// \return \b CIFRC_Ok: success.
+        ///
+        /// For safe use, \b R should be pre-allocated by calling
+        /// process. Only elements \b R[i1] to \b R[i2] will contain
+        /// fetched data, others remain untouched. The calling
+        /// process is responsible for the disposal of \b R. Example:
+        /// \code
+        /// mmcif::Loop loop;
+        /// rvector    R;  // equivalent to realtype *R
+        /// int        i,i1,i2,rc,n;
+        ///
+        ///    // ... get loop data
+        ///
+        ///    n  = loop.GetLoopLength();
+        ///    i1 = 5;  i2 = n - 5;  // could be wrong!
+        ///
+        ///    //  allocate a vector of real numbers
+        ///    GetVectorMemory ( R,n,0 );  // "0" for starting index
+        ///    // no need to initiaize unless required for the
+        ///    // application
+        ///
+        ///    rc = loop.GetRVector ( R,"value",i1,i2 );
+        ///    printf ( " Fetched with return code rc=%i\n",rc );
+        ///        // you may want a more thorough treatment of
+        ///        // the return code here
+        ///    for (i=i1;i<=i2;i++)
+        ///      printf ( " value[%4i] = %15.7g\n",i,R[i] );
+        ///
+        ///    //  R[] may be re-used for as many fetches as necessary
+        ///    //  without cleaning or disposals
+        ///
+        ///    //  dispose of the vector
+        ///    FreeVectorMemory ( R,0 );  // "0" for starting index
+        ///
+        /// \endcode
+        int  GetRVector ( rvector  & R, cpstr TName,
+                          int i1=0, int i2=MaxInt4,
+                          bool Remove=false );
+
+        /// \brief Fetches set of values, corresponding to the given
+        ///        tag, in the given range of rows, as a vector of
+        ///        integer numbers.
+        /// \param[out] I reference to float-point vector to accept
+        ///        the values. if \b I==NULL , the vector will be
+        ///        allocated with starting index of \b i1.
+        /// \param[in] TName character string with tag name
+        /// \param[in] i1  minimum row number to fetch, the actual
+        ///            index will be calculated as \b max(0,min(i1,i2))
+        /// \param[in] i2  maximum row number to fetch, the actual
+        ///            index will be calculated as
+        ///            \b min(GetLoopLength()-1,max(i1,i2))
+        /// \param[in] Remove flag to remove fetched fields from
+        ///               the loop after they are read.
+        /// \return \b CIFRC_NoTag: tag is not found
+        /// \return \b CIFRC_WrongIndex: invalid range of rows
+        /// \return \b CIFRC_Ok: success.
+        ///
+        /// For safe use, \b I should be pre-allocated by calling
+        /// process. Only elements \b I[i1] to \b I[i2] will contain
+        /// fetched data, others remain untouched. The calling
+        /// process is responsible for the disposal of \b I.
+        /// See example in mmcif::Loop::GetRVector documentation
+        /// for details.
+        int  GetIVector ( ivector  & I, cpstr TName,
+                          int i1=0, int i2=MaxInt4,
+                          bool Remove=false );
+
+        /// \brief Sets string value for given tag and row.
+        /// \param[in] S character string with value to be set.
+        ///            If \b S==NULL, the \"data not given\" value
+        ///            will be set. If \b S==\"\" (empty string), the
+        ///            \"data not available\" value is stored.
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] nrow  row number. If the row does not exist then
+        ///            it will be created, along with all other rows
+        ///            between GetLoopLength()-1 and \b nrow as
+        ///            necessary. All newly created fields will be
+        ///            initialised with \"data not given\" value.
+        void  PutString ( cpstr S, cpstr T, int nrow );
+
+        /// \brief Sets \"data not given\" or \"data not available\"
+        ///        values for given tag and row.
+        /// \param[in] NoDataType can be either
+        ///   \arg \b CIF_NODATA_DOT for \"data not given\"
+        ///   \arg \b CIF_NODATA_QUESTION for \"data not available\"
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] nrow  row number. If the row does not exist then
+        ///            it will be created, along with all other rows
+        ///            between GetLoopLength()-1 and \b nrow as
+        ///            necessary. All newly created fields will be
+        ///            initialised with \"data not given\" value.
+        void  PutNoData ( int NoDataType, cpstr T, int nrow );
+
+        /// \brief Sets float-point value for given tag and row.
+        /// \param[in] R real number with value to be set.
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] nrow  row number. If the row does not exist then
+        ///            it will be created, along with all other rows
+        ///            between GetLoopLength()-1 and \b nrow as
+        ///            necessary. All newly created fields will be
+        ///            initialised with \"data not given\" value.
+        /// \param[in] prec float-point precision; g-format with given
+        ///            precision will be used
+        void  PutReal ( realtype R, cpstr T, int nrow, int prec=8 );
+
+        /// \brief Sets float-point value for given tag and row.
+        /// \param[in] R real number with value to be set.
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] nrow  row number. If the row does not exist then
+        ///            it will be created, along with all other rows
+        ///            between GetLoopLength()-1 and \b nrow as
+        ///            necessary. All newly created fields will be
+        ///            initialised with \"data not given\" value.
+        /// \param[in] format format string to convert \b R.
+        void  PutReal ( realtype R, cpstr T, int nrow, cpstr format );
+
+        /// \brief Sets integer value for given tag.
+        /// \param[in] I integer number with value to be set.
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] nrow  row number. If the row does not exist then
+        ///            it will be created, along with all other rows
+        ///            between GetLoopLength()-1 and \b nrow as
+        ///            necessary. All newly created fields will be
+        ///            initialised with \"data not given\" value.
+        void  PutInteger ( int I, cpstr T, int nrow );
+
+        /// \brief Sets a set of string values for the given tag and
+        ///        range of rows.
+        /// \param[in] S string vector with values to store in the loop
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] i1  minimum data index in \b S to set in the loop
+        /// \param[in] i2  maximum data index in \b S to set in the loop.
+        ///
+        /// The data will be set in rows \b i1 to \b i2 (inclusive) in
+        /// the loop. If range \b [i1,i2] is not contained in the loop,
+        /// all missing rows will be created and initialised to
+        /// \"data not given\" value. Example:
+        /// \code
+        /// mmcif::Loop loop("_sample_loop");
+        /// pstr       S[100];
+        /// int        i;
+        ///
+        ///    //  initialize vector of strings
+        ///    for (i=0;i<100;i++)  {
+        ///      S[i] = new char[20];
+        ///      sprintf ( S[i],"value i=%i",i );
+        ///    }
+        ///
+        ///    //  put data in loop
+        ///    loop.PutSVector ( S,"made_up_string_value",0,99 );
+        ///
+        ///    //  dispose of vector of strings
+        ///    for (i=0;i<100;i++)
+        ///      if (S[i])  delete[] S[i];
+        ///
+        /// \endcode
+        void  PutSVector   ( psvector S, cpstr T, int i1, int i2 );
+
+        /// \brief Sets a set of float-point values for the given tag and
+        ///        range of rows.
+        /// \param[in] R vector of real numbers to store in the loop
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] i1  minimum data index in \b S to set in the loop
+        /// \param[in] i2  maximum data index in \b S to set in the loop
+        /// \param[in] prec float-point precision; g-format with given
+        ///            precision will be used.
+        ///
+        /// The data will be set in rows \b i1 to \b i2 (inclusive) in
+        /// the loop. If range \b [i1,i2] is not contained in the loop,
+        /// all missing rows will be created and initialised to
+        /// \"data not given\" value.
+        void  PutRVector   ( rvector  R, cpstr T, int i1, int i2,
+                                                       int prec=8 );
+
+        /// \brief Sets a set of integer values for the given tag and
+        ///        range of rows.
+        /// \param[in] I vector of integers to store in the loop
+        /// \param[in] T character string with tag name. If tag
+        ///            is not found, it will be added, and all data in
+        ///            the loop will be reindexed accordingly.
+        /// \param[in] i1  minimum data index in \b S to set in the loop
+        /// \param[in] i2  maximum data index in \b S to set in the loop.
+        ///
+        /// The data will be set in rows \b i1 to \b i2 (inclusive) in
+        /// the loop. If range \b [i1,i2] is not contained in the loop,
+        /// all missing rows will be created and initialised to
+        /// \"data not given\" value.
+        void  PutIVector   ( ivector  I, cpstr T, int i1, int i2 );
+
+        /// \brief Returns category type \b MMCIF_Loop.
+        MMCIF_ITEM  GetCategoryID() { return MMCIF_Loop; }
+
+        /// \brief Optimizes loop for RAM and data access speed.
+        /// Optimized data structures take less RAM and their indexes
+        /// are sorted for quicker access. Sorting is done automatically
+        /// as new data is added to the category. If the structure
+        /// is edited (fields/data removed), it may need
+        /// optimization and re-sorting for efficiency.\n\n
+        /// The sorting preserves the order of actual appearance of
+        /// tags and rows in mmCIF file. If a loop is created
+        /// programmatically, the order of tags and rows in mmCIF file
+        /// will be the same as order of adding them to the loop.
+        void  Optimize();
+
+        /// \brief Writes loop data in mmCIF format into file.
+        /// \param[in] FName character string with file name.
+        /// \param[in] gzipMode flag to controll compression of files:
+        ///  \arg \b GZM_NONE: do not compress
+        ///  \arg \b GZM_CHECK: check file name suffix and compress
+        ///                     (or not) accordingly
+        ///  \arg \b GZM_ENFORCE_GZIP: force gzip compression despite
+        ///                     suffix
+        ///  \arg \b GZM_ENFORCE_COMPRESS: force using compress despite
+        ///                     suffix
+        /// \return \b true: success
+        /// \return \b false: can not open file for writing.
+        /// \remarks This function does not create a valid mmCIF file
+        /// as \"data_XXX\" record will be missing. It may be used for
+        /// debugging though.
+        bool WriteMMCIFLoop ( cpstr FName,
+                              io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+        /// \brief Writes loop data into given file.
+        /// \param f reference to MMDB's file class. The file should be
+        /// opened and closed by application.
+        /// \remarks There is a very limited use of this function on
+        /// application level. It is primarily used by mmcif::Data class.
+        void  WriteMMCIF ( io::RFile f );
+
+        /// \brief Deep copy of loops.
+        /// Deep copy duplicates all data and memory allocations,
+        /// producing a genuine clone of the original. Only deep copy
+        /// should be used for copying MMDB objects, a mere assignment
+        /// operator will fail you.
+        /// \param[in] Loop a pointer to mmcif::Loop, the content of
+        ///                 which is copied into 'this' loop.
+        void  Copy ( PCategory Loop );
+
+        /// \brief MMDB stream writer.
+        void write ( io::RFile f );
+
+        /// \brief MMDB stream reader.
+        void read  ( io::RFile f );
+
+      protected:
+        int      nRows;
+        psmatrix field;
+        int      iColumn,nAllocRows;
+
+        void  InitLoop     ();
+        void  FreeMemory   ();
+        void  DeleteFields ();
+        void  ExpandRows   ( int nRowsNew );
+
+    };
+
+
+
+    //  ======================  Data  =============================
+
+
+    //    CIFW are warnings which may be issued on reading the CIF file.
+    // Each of them means actually a CIF syntax error.
+
+    enum CIF_WARNING  {
+      CIFW_UnrecognizedItems = 0x00000020,
+      CIFW_MissingField      = 0x00000040,
+      CIFW_EmptyLoop         = 0x00000080,
+      CIFW_UnexpectedEOF     = 0x00000100,
+      CIFW_LoopFieldMissing  = 0x00000200,
+      CIFW_NotAStructure     = 0x00000400,
+      CIFW_NotALoop          = 0x00000800,
+      CIFW_DuplicateTag      = 0x00001000
+    };
+
+    //    CIFRC are return codes from procedures of extracting data from
+    // the read CIF file. Negative returns reflect unsuccessful and
+    // not accomplished operation.
+    enum CIF_RC  {
+      CIFRC_Loop           =  2,
+      CIFRC_Structure      =  1,
+      CIFRC_Ok             =  0,
+      CIFRC_StructureNoTag = -1,
+      CIFRC_LoopNoTag      = -2,
+      CIFRC_NoCategory     = -3,
+      CIFRC_WrongFormat    = -4,
+      CIFRC_NoTag          = -5,
+      CIFRC_NotAStructure  = -6,
+      CIFRC_NotALoop       = -7,
+      CIFRC_WrongIndex     = -8,
+      CIFRC_NoField        = -9,
+      CIFRC_Created        = -12,
+      CIFRC_CantOpenFile   = -13,
+      CIFRC_NoDataLine     = -14,
+      CIFRC_NoData         = -15
+    };
+
+    //
+    //  Functional flags:
+    //  ~~~~~~~~~~~~~~~~~
+    //
+    //  CIFFL_PrintWarnings      when reading CIF file, all warning
+    //                           messages will be printed. If the flag
+    //                           is off, the warnings will be bit-encoded
+    //                           in the return code
+    //  CIFFL_StopOnWarnings     reading CIF file will stop at first
+    //                           warning issued
+    //  CIFFL_SuggestCategories  allows reading CIF file with loops having
+    //                           no categories. Hidden category names
+    //                           will be automatically generated for
+    //                           internal consistency of the system.
+    //                           These names will not appear in output.
+    //                           As these names are hidden, they cannot
+    //                           be used to access data. It is therefore
+    //                           assumed that all tags in all loops without
+    //                           categories are unique. Simply specify ""
+    //                           for category when accessing such data
+    //                           (it cannot be accessed through mmcif::Loop,
+    //                           but only through mmcif::Data functions
+    //                           taking both Category and Tag; note that
+    //                           CIFFL_SuggestCategories flag must be on
+    //                           while accessing such data).
+    //  CIFFL_SuggestTags        allows for identical tags in a category
+    //                           (including a hidden category). Hidden
+    //                           suffixes to tag names will be generated
+    //                           for internal consistency. At present,
+    //                           only data for first non-unique tag may be
+    //                           accessed.
+    //
+    enum CIF_FLAG  {
+      CIFFL_PrintWarnings     = 0x00000001,
+      CIFFL_StopOnWarnings    = 0x00000002,
+      CIFFL_SuggestCategories = 0x00000004,
+      CIFFL_SuggestTags       = 0x00000008
+    };
+
+    DefineClass(Data);
+    DefineStreamFunctions(Data);
+
+
+    /// \brief mmcif::Data represents mmCIF's \"data\" category, which keeps
+    ///        structures and loops and is mandatory element of mmCIF file.
+    /*!
+    mmCIF's \"data\" category has the following form:
+    \code
+    data_DataName
+
+    _structure1.tag1  value1
+    ..........
+
+    loop_
+    ..........
+
+    \endcode
+    In the above example, all structures and loops that follow \b data_
+    keyword until next \b data_ or end of file are part of data category
+    with name \b DataName.
+
+    mmcif::Data represents this construct by keeping a list of mmcif::Struct
+    and mmcif::Loop class instances associated with the corresponding
+    categories in the data block.
+
+    The data object is created automatically when an mmCIF file is read,
+    or it may be created programatically and then pushed into file.
+
+    Access to data is provided via category (structures and loops) names,
+    tags and data indexes (in case of loops). Alternatively, pointers to
+    contained structures and loops may be obtained first, an used for
+    fetching data using mmcif::Struct's and mmcif::Loop's interface
+    functions.
+
+    The following code gives an example of creating mmCIF's data category
+    and populating it:
+    \code
+    mmcif::Data data;
+
+      // Specify data name:
+      data.PutDataName ( "Sample_Data" );
+
+      // the following statement:
+      data.PutInteger ( 12345,"_category1","id" );
+      // creates structure "_category1" with tag "id" and assigns it
+      // the integer value of 12345.
+
+      data.PutString ( "a name","_category1","name" );
+
+      // Loops may be created quite similarly:
+      data.PutLoopInteger ( 12345   ,"_loop1","id"  ,2 );
+      data.PutLoopInteger ( "a name","_loop1","name",0 );
+
+      // push data into a file
+      data.WriteMMCIFData ( "sample.cif" );
+
+    \endcode
+
+    The resulting file \b sample.cif will contain:
+
+    \code
+    data_Sample_Data
+
+    _category1.id   12345
+    _category1.name "a name"
+
+    loop_
+    _loop1.id
+    _loop1.name
+    .      "a name"
+    .      .
+    12345  .
+    \endcode
+
+    The same result may be achieved differently:
+
+    \code
+    mmcif::Data    data;
+    mmcif::PStruct mmCIFStruct;  // equivalent to mmcif::Struct *mmCIFStruct
+    mmcif::PLoop   mmCIFLoop;    // equivalent to mmcif::Loop   *mmCIFLoop
+
+      // Specify data name:
+      data.PutDataName ( "Sample_Data" );
+
+      // create new mmCIF's structure in the data block:
+      data.AddStructure ( "_category1",mmCIFStruct );
+      if (mmCIFStruct)  {
+        mmCIFStruct->PutInteger ( 12345   ,"id"   );
+        mmCIFStruct->PutString  ( "a name","name" );
+      }
+
+      // similarly for the loop:
+      data.AddLoop ( "_loop1",mmCIFLoop );
+      if (mmCIFLoop)  {
+        mmCIFLoop->PutInteger ( 12345   ,"id"  ,2 );
+        mmCIFLoop->PutString  ( "a name","name",0 );
+      }
+
+      // push data into a file
+      data.WriteMMCIFData ( "sample.cif" );
+
+    \endcode
+
+    See general principles of working with mmCIF files and mmCIF
+    hierarchies, as well as some code samples, in Section
+    \"\ref mmcif_handler\".
+    */
+
+    class Data : public io::Stream  {
+
+      friend class File;
+
+      public :
+
+        /// \brief Basic constructor.
+        Data ();
+
+        /// \brief Constructor that assigns data block name.
+        /// \param[in] N data block name.
+        Data ( cpstr N );
+
+        /// \brief Constructor for MMDB data streaming functions.
+        Data ( io::RPStream Object );
+
+        /// \brief Destructor.
+        ~Data();
+
+
+        // -------- General I/O functions
+
+        /// \brief Sets flag to print warnings on reading mmCIF files.
+        /// \param[in] SPW flag to print warnings:
+        ///    \arg \b true : warnings will be printed to stdout
+        ///    \arg \b false : warnings will not be printed but returned
+        ///                    in return code (default)
+        void  SetPrintWarnings ( bool SPW );
+
+        /// \brief Sets flag to stop on warning when reading an mmCIF file.
+        /// \param[in] SOW flag to stop on warning:
+        ///    \arg \b true : reading will stop on first warning encountered
+        ///    \arg \b false : warnings will not stop reading (default)
+        void  SetStopOnWarning ( bool SOW );
+
+        /// \brief Sets optional flag(s) for reading mmCIF files.
+        /// By default, no flags are set.
+        /// \param[in] F flag or logical \"or\" of several flags to be set:
+        ///  \arg \b CIFFL_PrintWarnings  toggles printing warning messages
+        ///               at reading an mmCIF file, in stdout. If this
+        ///               flag is not set (default), the warnings will
+        ///               be returned in the bit-encoded return code
+        ///  \arg \b CIFFL_StopOnWarnings  if set, reading an mmCIF file
+        ///               will stop at first warning issued
+        ///  \arg \b CIFFL_SuggestCategories  allows for reading of mmCIF
+        ///               files with loops and structures having no
+        ///               category names (\"dirty CIFs\"). If this flag is
+        ///               set, then hidden category names will be
+        ///               automatically generated. These names will not
+        ///               appear in the output. As these names are hidden,
+        ///               they cannot be used to access data. In order to
+        ///               access data in such categories, consider whether
+        ///               they are structures or loops. In case of a
+        ///               unnamed structure, simply specify \"\" (empty
+        ///               string) for structure name in all access
+        ///               functions ( note that \b CIFFL_SuggestCategories
+        ///               flag must be on while accessing such data). In
+        ///               case of a loop, first use the mmcif::Data::FindLoop
+        ///               function to retrieve pointer on the hidden loop,
+        ///               and then use mmcif::Loop's interface function to
+        ///               fetch data from the loop.
+        ///  \arg \b CIFFL_SuggestTags  allows for duplicate tags in a
+        ///               category (structure or loop, including hidden
+        ///               categories). This may help reading \"dirty CIFs\".
+        ///               At present, only data for first non-unique tag
+        ///               may be accessed.
+        void  SetFlag ( CIF_FLAG F );
+
+        /// \brief Removes optional flag(s) for reading mmCIF files.
+        /// By default, no flags are set.
+        /// \param[in] F flag or logical \"or\" of several flags to be
+        ///              removed (unset):
+        ///  \arg \b CIFFL_PrintWarnings  no wornings will be printed in
+        ///               stdout, but rather returned in the bit-encoded
+        ///               return code
+        ///  \arg \b CIFFL_StopOnWarnings  warnings will not stop reading
+        ///  \arg \b CIFFL_SuggestCategories  loops without names will
+        ///               count as errors and stop reading
+        ///  \arg \b CIFFL_SuggestTags  duplicate tags in structures and
+        ///               loops will count as errors and stop reading.
+        ///
+        /// See more detail flag description in mmcif::Data::SetFlag().
+        void  RemoveFlag ( CIF_FLAG F );
+
+        /// \brief Returns bit-encoded warnings issued at last file read.
+        /// \return an integer number, which is an or-superposition of
+        ///         warning flags:
+        /// \arg \b CIFW_UnrecognizedItems: unrecognized items were found
+        /// \arg \b CIFW_MissingField: expected data field not found
+        /// \arg \b CIFW_EmptyLoop: loop category was defined but has no
+        ///                         data
+        /// \arg \b CIFW_UnexpectedEOF: mmCIF construct finished prematurely
+        /// \arg \b CIFW_LoopFieldMissing: loop category has wrong number
+        ///                         of data fields
+        /// \arg \b CIFW_NotAStructure: attempt to use a category name,
+        ///                         which was once defined as a structure,
+        ///                         as a loop
+        /// \arg \b CIFW_NotALoop: attempt to use a category name, which was
+        ///                         once defined as a loop, as a structure
+        /// \arg \b CIFW_DuplicateTag: duplicate tag was found in a
+        ///                         structure or loop
+        inline int  GetWarnings() { return Warning; }
+
+        /// \brief Sets category names and tags that are to be ignored
+        ///        on file read.
+        /// \param[in] cats list of categories, terminated by NULL
+        /// \param[in] tags list of tags, terminated by NULL.
+        ///
+        /// This special function is to aid reading corrupt mmCIF files.
+        /// The input lists should be of equal length 'n', and specify
+        /// 'n' \"wrong fields\" that should be ignored on input. E.g.,
+        /// ith \"wrong field\" is identified as \"cats[i].taga[i]\".
+        /// If \"wrong field\" belongs to a loop, then all the corresponding
+        /// column is assumed to be absent. This corrects for mmCIF errors
+        /// when defined tags in loops or structures do not have actual data
+        /// associated with them.
+        ///
+        /// In order to remove settings, call SetWrongFields(NULL,NULL).
+        ///
+        /// Example:
+        /*!
+        \code
+        // assume data for "_category.item1" and "_category.item2"
+        // missed in a file to-be-read
+        mmcif::Data data;
+        cpstr cats[] = { "_category", "_category", NULL };
+        cpstr tags[] = { "item1"    , "item2"    , NULL };
+
+           data.SetWrongFields ( cats,tags );
+           data.ReadMMCIFData  ( "corrupt.cif" );
+        \endcode
+        */
+        void  SetWrongFields ( cpstr *cats, cpstr *tags );
+
+        /// \brief Reads mmCIF data block from file.
+        /// \param FName character null-terminated string with file name
+        /// \param gzipMode flag to read compressed files:
+        /// \arg \b GZM_NONE: do not assume any compression
+        /// \arg \b GZM_CHECK: check compression type by file extension
+        /// \arg \b GZM_ENFORCE: same as \b GZM_ENFORCE_GZIP
+        /// \arg \b GZM_ENFORCE_GZIP: assume gzip compression (*.gz files)
+        /// \arg \b GZM_ENFORCE_COMPRESS: assume compression with 'compress'
+        ///         (*.Z files).
+        /// \return \b CIFRC_Ok: no errors
+        /// \return \b negative: there were errors
+        /// \return \b positive: there were warnings.
+        ///
+        /// This function will read 1st data block from the specified file.
+        /// In case of non-zero return, use GetCIFMessage() function to
+        /// print the corresponding error message or warning:
+        /*!
+        \code
+        mmcif::Data data;
+        char       errLog[500];
+        int        rc;
+           rc = data.ReadMMCIFData  ( "myfile.cif" );
+           if (rc<0)
+             printf ( " There was an error:\n %s\n",
+                      GetCIFMessage(errLog,rc) );
+           else if (rc>0)
+             printf ( " There were warnings:\n %s\n",
+                      GetCIFMessage(errLog,rc) );
+           else
+             printf ( " mmCIF file has be read in successfully.\n" );
+        \endcode
+        */
+        int  ReadMMCIFData ( cpstr FName,
+                             io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+        /// \brief Reads sequential mmCIF data blocks from file.
+        /// \param RCFile reference to a CFile object opened on a file
+        /// \param S buffer string which represent a sliding read window.
+        ///          The string should be at least 500 characters long,
+        ///          initialized with empty-string value before first read,
+        ///          and passed unchanged between the reads
+        /// \param lcount line counter, should be set zero before first
+        ///          read and passed unchanged between the reads.
+        /// \return \b CIFRC_Ok: no errors
+        /// \return \b negative: there were errors
+        /// \return \b positive: there were warnings.
+        ///
+        /// This function will read 1st data block from the current position
+        /// of the file. The function is useful if a file contains more than
+        /// a single data block, which should be read sequentially.
+        ///
+        /// \note Alternatively, files with multiple data blocks can be
+        /// read using mmcif::File class.
+        ///
+        /// In case of non-zero return, use GetCIFMessage() function to
+        /// print the corresponding error message or warning:
+        /*!
+        \code
+      mmcif::Data    mmCIFData;
+      CFile         f;
+      char          S[1000];
+      int           rc,lcount;
+
+        // open file first
+        f.assign ( "/path/example.cif" );
+        if (!f.reset(true))  {
+          printf ( " *** cannot open file '%s' for reading.\n",
+                   f.FileName() );
+          return -1;
+        }
+
+        lcount = 0;         // global line counter through the file
+        S[0]   = char(0);   // buffer string
+        while (!f.FileEnd())  {
+
+          rc = mmCIFData.ReadMMCIFData ( f,S,lcount );
+
+          if (rc!=CIFRC_Ok)  {  // error or warning
+            if ((rc<0) && (!f.FileEnd()))  { // error
+              printf ( " *** error reading file %s:\n"
+                       "     %s\n",f.FileName(),GetCIFMessage(S,rc) );
+              return rc;
+            } else if (rc>0)  { // warning
+              printf ( " ... warning on reading file %s:\n"
+                       "     %s\n",f.FileName(),GetCIFMessage(S,rc) );
+            }
+          } else  {
+            // fetch needful values from the data block
+            // ........
+          }
+
+        }
+
+        f.shut();  // close file
+
+        // NOTE: do not delete mmcif::Struct/mmcif::Loop
+        // classes obtained from mmcif::Data. If you do, get a crash.
+        // All these structures are containers that dispose their
+        // content automatically.
+        \endcode
+        */
+        int  ReadMMCIFData ( io::RFile f, pstr S, int & lcount );
+
+        /// \brief Writes mmCIF data block into file.
+        /// \param FName character null-terminated string with file name
+        /// \param gzipMode flag to read compressed files:
+        /// \arg \b GZM_NONE: do not compress
+        /// \arg \b GZM_CHECK: compress according to file extension
+        /// \arg \b GZM_ENFORCE: same as \b GZM_ENFORCE_GZIP
+        /// \arg \b GZM_ENFORCE_GZIP: compress with gzip
+        /// \arg \b GZM_ENFORCE_COMPRESS: compression with 'compress'.
+        /// \return \b true: no errors
+        /// \return \b false: file cannot be open for writing.
+        bool WriteMMCIFData   ( cpstr FName,
+                                io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+        /// \brief Writes (next) mmCIF data block into file.
+        /// \param RCFile reference to a CFile object opened on a file.
+        ///
+        /// This function allows for sequential write of mmCIF data blocks
+        /// into a file.
+        ///
+        /// \note Alternatively, files with multiple data blocks can be
+        /// created using mmcif::File class.
+        ///
+        /// Example:
+        /*!
+      \code
+      io::File       f;
+      mmcif::Data  cifData;
+
+        // open file first
+        f.assign ( "/path/example.cif" );
+        if (!f.rewrite())  {
+          printf ( " *** cannot open file '%s' for writing.\n",
+                   f.FileName() );
+          return -1;
+        }
+
+        cifData.PutDataName ( "name1" );
+        // fill cifData with all data needed
+        cifData.WriteMMCIF ( f ); // first data block written
+
+        cifData.FreeMemory  ( 0 );  // reset data block to empty
+        cifData.PutDataName ( "name2" );
+        // fill cifData with all data needed
+        cifData.WriteMMCIF ( f );  // second data block written
+
+        // add as many data blocks as needed
+
+        // now close the file
+        f.shut();
+
+      \endcode
+
+        */
+        void  WriteMMCIF ( io::RFile f );
+
+
+        // -------- Retrieving data
+
+        /// \brief Returns the number of categories (structures and loops)
+        ///        in data block.
+        inline int   GetNumberOfCategories ()  { return nCategories; }
+
+        /// \brief Retrieves pointer to category (a structure or a loop) by
+        ///        category number.
+        /// \param categoryNo category number to retrieve. Categories are
+        ///        numbered from 0 to GetNumberOfCategories()-1.
+        /// \return pointer to category, if \b categoryNo is in the right
+        ///        range, or \b NULL otherwise.
+        ///
+        /// \note The category type (structure or loop) is returned by
+        /// function mmcif::Category::GetCategoryID().
+        /// \note The application should never attempt to deallocate
+        /// the category returned. It will be properly disposed of by
+        /// mmcif::Data's destructor.
+        PCategory GetCategory ( int categoryNo ); // 0..nCategories-1
+
+        /// \brief Retrieves mmCIF structure with given name.
+        /// \param CName character string with name of the structure (must
+        ///        start with underscore).
+        /// \return pointer to structure if structure with given name was
+        ///        found, and \b NULL otherwise.
+        /// \note The application should never attempt to deallocate
+        /// the structure returned. It will be properly disposed of by
+        /// mmcif::Data's destructor.
+        PStruct GetStructure  ( cpstr CName );
+
+        /// \brief Retrieves mmCIF loop with given name.
+        /// \param CName character string with name of the loop (must
+        ///        start with underscore).
+        /// \return pointer to loop if loop with given name was
+        ///        found, and \b NULL otherwise.
+        /// \note The application should never attempt to deallocate
+        /// the loop returned. It will be properly disposed of by
+        /// mmcif::Data's destructor.
+        PLoop GetLoop ( cpstr CName );
+
+        /// \brief Finds loop containing all tags from the tag list
+        ///        provided.
+        /// \param tagList list of tags to be looked for. The list should
+        ///        be terminated by empty string \"\". The order of tags
+        ///        is not significant.
+        /// \return pointer to loop if loop with given tags was found, and
+        ///         \b NULL otherwise.
+        ///
+        /// The function will look for first loop that includes all tags
+        /// from the list. The list does not have to include all tags for
+        /// that loop in order for function to succeed. This function is
+        /// useful for reading \"dirty cifs\" that may contain loops without
+        /// a name.
+        PLoop FindLoop ( cpstr * tagList );
+
+        /// \brief Retrieves data block name into dynamically-allocated
+        ///        string.
+        /// \param dname pointer reference to a string that accepts data
+        ///        block name. If \b dname is not \b NULL, it is treated
+        ///        as a pre-allocated string, which is disposed before
+        ///        copying. The application is responsible for deallocating
+        ///        \b dname.
+        /// \param Remove flag to remove name from the data block.
+        void GetDataName ( pstr & dname, bool Remove=false );
+
+        /// \brief Returns data block name.
+        inline pstr GetDataName()  { return name; }
+
+        //   CheckData(..) returns positive value if the field is in the
+        // file:
+        //   CIFRC_Structure  category CName is a structure
+        //   CIFRC_Loop       category CName is a loop
+        // Negative returns mean:
+        //   CIFRC_StructureNoTag  category CName is present,
+        //                        it is a structure, but it does not
+        //                        have tag TName
+        //   CIFRC_LoopNoTag       category CName is present,
+        //                        it is a loop, but it does not have
+        //                        tag TName
+        //   CIFRC_NoCategory      category CName is not present.
+        // If TName is set to NULL then only the CName is checked and
+        // possible returns are CIFRC_Structure, CIFRC_Loop and
+        // CIFRC_NoCategory.
+        int  CheckData       ( cpstr CName, cpstr TName );
+
+        int  DeleteCategory  ( cpstr CName );
+        int  DeleteStructure ( cpstr CName );
+        int  DeleteLoop      ( cpstr CName );
+
+        //   Optimize() optimizes the CIF data in memory allocation. It is
+        // a good idea to call it once after extraction of data (GetXXXXXX
+        // functions) with Remove flag set on has been completed.
+        void Optimize();
+
+        //   GetString(..), GetReal(..) and GetInteger(..) return 0 if the
+        // requested field was found and successfully converted. Negative
+        // returns mean:
+        //    CIFRC_WrongFormat   the field was found but failed to convert
+        //                        due to improper numeric format
+        //    CIFRC_NoTag         category CName was found, but it does not
+        //                        have tag TName
+        //    CIFRC_NoCategory    category CName was not found
+        //    CIFRC_NotAStructure category CName was found, but it is
+        //                        a loop rather than a structure.
+        //   GetString(..) will try to dispose Dest unless it is assigned
+        // NULL value before the call. The string will be then dynamically
+        // allocated and copied.
+        //   If Remove is set to true, the field will be removed after
+        // extraction.
+        int  GetString   ( pstr & Dest, cpstr CName, cpstr TName,
+                                        bool Remove=false );
+        pstr GetString   ( cpstr CName, cpstr TName, int & RC );
+        int  DeleteField ( cpstr CName, cpstr TName );
+        int  GetReal     ( realtype & R, cpstr CName,
+                           cpstr TName, bool Remove=false );
+        int  GetInteger  ( int & I, cpstr CName, cpstr TName,
+                                    bool Remove=false );
+
+        //   GetLoopLength(..) returns CIFRC_NotALoop if the category CName
+        // is not a loop, CIFRC_NoCategory if the category CName is not
+        // found. Non-negative returns give the length of the loop (may be
+        // 0 if the loop is empty).
+        int  GetLoopLength ( cpstr CName );
+
+        //   GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act
+        // like GetString(..), GetReal(..) and GetInteger(..) above for
+        // nrow-th element of the 'loop_' (indexed like 0..N-1 where N
+        // is obtained through GetLoopLength(..)). They will return
+        // CIFRC_WrongIndex if nrow is out of range.
+        //   If Remove is set to true, the field will be removed after
+        // extraction.
+        int  GetLoopString   ( pstr & Dest, cpstr CName,
+                                            cpstr TName, int nrow,
+                                            bool Remove=false );
+        pstr GetLoopString   ( cpstr CName, cpstr TName,
+                               int nrow, int & RC );
+        int  DeleteLoopField ( cpstr CName, cpstr TName,
+                               int nrow );
+        int  GetLoopReal     ( realtype & R, cpstr CName,
+                                             cpstr TName, int nrow,
+                                             bool Remove=false );
+        int  GetLoopInteger  ( int & I, cpstr CName,
+                                        cpstr TName, int nrow,
+                                        bool Remove=false );
+
+        //   GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..)
+        // read CIF 'loop_' data into allocated vectors of strings, reals
+        // and integers, correspondingly. The vectors may be deallocated
+        // prior to call and assigned NULL, in which case they will be
+        // allocated with offsets of i1, which is also the lower index of
+        // the 'loop_' data transferred into it. The upper vector index is
+        // given by i2 or by the loop's length whichever is less. If
+        // vectors are not assigned NULL prior the call, it is assumed
+        // that they are properly (i1-offset, i2-i1+1 length) allocated.
+        //   The return codes are same as those of GetLoopString(..),
+        // GetLoopReal(..) and GetLoopInteger(..).
+        int  GetLoopSVector ( psvector & S, cpstr CName,
+                              cpstr TName, int i1=0, int i2=MaxInt4,
+                              bool Remove=false );
+        int  GetLoopRVector ( rvector  & R, cpstr CName,
+                              cpstr TName, int i1=0, int i2=MaxInt4,
+                              bool Remove=false );
+        int  GetLoopIVector ( ivector  & I, cpstr CName,
+                              cpstr TName, int i1=0, int i2=MaxInt4,
+                              bool Remove=false );
+
+
+        // -------- Storing data
+
+        //   Unless the data are to be added to the existing CIF structure,
+        // FreeMemory() should be called once before creating a new
+        // CIF data set.
+        void FreeMemory ( int key );
+
+        void PutDataName ( cpstr dname ); // stores name for 'data_'
+                                          // record
+
+        //   PutString(..), PutReal(..) and PutInteger(..) will put the
+        // values given into the specified category (CName) under the
+        // specified tag (TName). The category, tag and field are created
+        // automatically; the field will be replaced silently if identical
+        // CName.TName is specified in two calls. Calls of these functions
+        // may follow in random order; however CIF file will have all tags
+        // grouped by categories and catgories will follow in the order
+        // of first appearance in PutString(..), PutReal(..) or
+        // PutInteger(..).
+        //   Return code - one of CIFRC_Ok or CIFRC_NotAStruct
+        int  PutNoData   ( int NoDataType, cpstr CName,
+                           cpstr TName );
+        int  PutString   ( cpstr S, cpstr CName,
+                           cpstr TName, bool Concatenate=false );
+        int  PutDate     ( cpstr CName, cpstr TName );
+        int  PutReal     ( realtype R, cpstr CName, cpstr TName,
+                                       int prec=8 );
+        int  PutInteger  ( int I, cpstr CName, cpstr TName );
+
+        //   If loop category CName is not present in the CIF data
+        // structure, AddLoop(..) creates an empty one and returns
+        // its pointer in Loop. If loop category CName is already in
+        // the CIF data structure, its pointer is returned, and any
+        // data which might be contained in it, remains untouched.
+        //   To stuff the loop with data, first the data tags have to
+        // be specified by calling  Loop->AddLoopTag(..). After all
+        // tags are given, the data comes as a stream of calls
+        // Loop->AddString(..), Loop->AddReal(..) and
+        // Loop->AddInteger(..) which should provide data for every
+        // tag in sequence in strictly the same order as the tags
+        // were given. This essentially reflects reading a CIF loop
+        // from a file.
+        //   Alternatively, the loop data may be stored with PutLoopXXX()
+        // functions given below, although this way may be less
+        // efficient (but more flexible).
+        //   AddLoop(..) may return
+        //     CIFRC_Ok       category was present
+        //     CIFRC_Created  category was not present but it has
+        //                    been created; the category is empty
+        //     CIFRC_NotALoop category was present as a structure, but
+        //                    has been replaced for a loop;
+        //                    the category is empty.
+        int  AddLoop      ( cpstr CName, PLoop   & cifLoop   );
+        int  AddStructure ( cpstr CName, PStruct & cifStruct );
+
+        //   PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act
+        // like PutString(..), PutReal(..) and PutInteger(..) above for
+        // nrow-th element of the 'loop_' CName (indexed begining from 0).
+        // In consequitive calls, given values of nrow does not have to be
+        // ordered; the most efficient way is to start with HIGHEST value
+        // for nrow in the loop and move down to 0. The least efficient way
+        // is to start with nrow=0 and move up.
+        //   These functions allow to form loops in arbitrary way.
+        //   The functions may return CIFRC_Ok or CIFRC_NotALoop.
+        int  PutLoopNoData  ( int NoDataType, cpstr CName,
+                                              cpstr TName, int nrow );
+        int  PutLoopString  ( cpstr S,   cpstr CName,
+                                              cpstr TName, int nrow );
+        int  PutLoopReal    ( realtype R, cpstr CName,
+                                          cpstr TName, int nrow,
+                                          int  prec=8 );
+        int  PutLoopInteger ( int I, cpstr CName, cpstr TName,
+                                     int nrow );
+
+        //   PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..)
+        // put vectors of values into specified loop fields. Parameters i1
+        // and i2 give the range of indices of values which are to be
+        // transfered. To transfer an entire vector allocated as [0..N-1]
+        // i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is
+        // always indexed as starting form 0 on, therefore negative i1 and
+        // i2 are not allowed, and specifying i1>0 will leave first i1
+        // elements of the CIF loop for the corresponding tag undefined
+        // (will be output like '?').
+        //   These functions allow to form loops in arbitrary way.
+        int  PutLoopSVector ( psvector S, cpstr CName,
+                              cpstr TName, int i1, int i2 );
+        int  PutLoopRVector ( rvector  R, cpstr CName,
+                              cpstr TName, int i1, int i2,
+                              int prec=8 );
+        int  PutLoopIVector ( ivector  I, cpstr CName,
+                              cpstr TName, int i1, int i2 );
+
+        int  RenameCategory ( cpstr CName, cpstr newCName );
+
+        // --------
+
+        void Copy         ( PData Data );
+        int  CopyCategory ( PData Data, cpstr CName,
+                                        cpstr newCName=NULL );
+
+        void PrintCategories();  // for debuging only
+
+        void write ( io::RFile f );
+        void read  ( io::RFile f );
+
+      protected:
+        pstr       name;
+        int        nCategories;
+        PPCategory Category;
+        ivector    index;
+        int        flags;
+        int        Warning;
+        int        loopNo;  // used locally for suggesting categories
+        int        tagNo;   // used locally for suggesting tags
+        psvector   WrongCat;
+        psvector   WrongTag;
+        int        nWrongFields;
+
+        void  InitData        ();
+        void  FreeWrongFields ();
+        bool  CheckWrongField ( cpstr C, cpstr T );
+        void  Sort            ();
+
+        //   GetCategoryNo searches for index of category cname
+        // in Category[]. Return:
+        //    >=0 : position of the category found
+        //     <0 : the category was not found, it could be inserted before
+        //          (-RC-1)th element, where RC is the return value
+        int  GetCategoryNo  ( cpstr cname );
+        int  AddCategory    ( cpstr cname );
+        int  DeleteCategory ( int  CatNo );
+
+        void GetDataItem    ( io::RFile f, pstr S, pstr & L, pstr & p,
+                                        int & lcount, int & llen );
+        void GetLoop        ( io::RFile f, pstr S, pstr & L, pstr & p,
+                                        int & lcount, int & llen );
+        int  GetField       ( io::RFile f, pstr S, pstr & L, pstr & p,
+                                        int & lcount, int & llen );
+
+    };
+
+
+
+    //  ========================  File  =============================
+
+    DefineClass(File);
+    DefineStreamFunctions(File);
+
+    class File : public io::Stream  {
+
+      public :
+        int      nData;
+        ivector  index;
+        PPData   data;
+
+        File ();
+        File ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK );
+        File ( io::RPStream Object );
+        ~File();
+
+        void  SetPrintWarnings ( bool SPW ) { PrintWarnings = SPW; }
+        void  SetStopOnWarning ( bool SOW ) { StopOnWarning = SOW; }
+
+        int   ReadMMCIFFile  ( cpstr FName,
+                               io::GZ_MODE gzipMode=io::GZM_CHECK );
+        int   WriteMMCIFFile ( cpstr FName,
+                               io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+        int   GetNofData()  { return nData; }
+        PData GetCIFData     ( int   dataNo );  // 0..nData-1
+        PData GetCIFData     ( cpstr DName  );
+        int   AddCIFData     ( cpstr DName  );
+        int   DeleteCIFData  ( cpstr DName  );
+        int   DeleteCIFData  ( int   dataNo );
+        int   GetCIFDataNo   ( cpstr DName  );
+
+        void  WriteMMCIF     ( io::RFile f  );
+
+        void  Copy  ( PFile File );
+
+        void  write ( io::RFile f );
+        void  read  ( io::RFile f );
+
+      protected:
+        int  nAllocData;
+        bool PrintWarnings;
+        bool StopOnWarning;
+
+        void  InitFile   ();
+        void  FreeMemory ();
+        void  Sort       ();
+        void  ExpandData ( int nDataNew );
+
+    };
+
+
+    extern pstr GetMMCIFInputBuffer ( int & LineNo );
+
+    //  isCIF will return
+    //    -1   if file FName does not exist
+    //     0   if file FName is likely a CIF file ( 'data_' is present )
+    //     1   if file FName is not a CIF file ( 'data_' is absent )
+    extern int isCIF ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK );
+    extern int isCIF ( io::RFile f );
+
+    pstr GetCIFMessage ( pstr M, int RC );
+
+
+  }  // namespace mmcif
+
+}  // namespace mmdb
+
+
+#endif
+
+
diff --git a/mmdb2/mmdb_model.cpp b/mmdb2/mmdb_model.cpp
new file mode 100644
index 0000000..ca1d537
--- /dev/null
+++ b/mmdb2/mmdb_model.cpp
@@ -0,0 +1,5332 @@
+//  $Id: mmdb_model.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Model <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::HetCompound  ( description of het compounds  )
+//       ~~~~~~~~~  mmdb::HetCompounds (HETNAM, HETSYN, FORMULA records)
+//                  mmdb::SSContainer  (container for helixes and turns)
+//                  mmdb::Helix        ( helix info                    )
+//                  mmdb::Strand       ( strand info                   )
+//                  mmdb::Sheet        ( sheet info                    )
+//                  mmdb::Sheets       ( container for sheets          )
+//                  mmdb::Turn         ( turn info                     )
+//                  mmdb::LinkContainer   ( container for link data    )
+//                  mmdb::Link            ( link data                  )
+//                  mmdb::LinkRContainer  ( container for refmac link  )
+//                  mmdb::LinkR           ( link data                  )
+//                  mmdb::CisPepContainer ( container for CisPep data  )
+//                  mmdb::CisPep          ( CisPep data                )
+//                  mmdb::Model        ( PDB model                     )
+//
+//  Copyright (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_model.h"
+#include "mmdb_manager.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb  {
+
+  //  ===================  HetCompound  =========================
+
+  HetCompound::HetCompound ( cpstr HetName ) : io::Stream()  {
+    InitHetCompound ( HetName );
+  }
+
+  HetCompound::HetCompound ( io::RPStream Object ) : io::Stream(Object)  {
+    InitHetCompound ( pstr("---") );
+  }
+
+  HetCompound::~HetCompound() {
+    FreeMemory();
+  }
+
+  void  HetCompound::InitHetCompound ( cpstr HetName )  {
+    strcpy_n0 ( hetID,HetName,sizeof(ResName) );
+    comment    = NULL;
+    nSynonyms  = 0;
+    hetSynonym = NULL;
+    compNum    = MinInt4;
+    wc         = ' ';
+    Formula    = NULL;
+  }
+
+  void  HetCompound::FreeMemory()  {
+  int i;
+    if (comment)  {
+      delete[] comment;
+      comment = NULL;
+    }
+    if (hetSynonym)  {
+      for (i=0;i<nSynonyms;i++)
+        if (hetSynonym[i])  delete[] hetSynonym[i];
+      delete[] hetSynonym;
+      hetSynonym = NULL;
+    }
+    nSynonyms = 0;
+    if (Formula)  {
+      delete[] Formula;
+      Formula = NULL;
+    }
+  }
+
+  void  HetCompound::AddKeyWord ( cpstr W, bool Closed )  {
+  psvector HS1;
+  int      i;
+    if (Closed || (!hetSynonym))  {
+      // first synonym orthe previous synonym was closed by semicolon
+      // -- add a new one
+      HS1 = new pstr[nSynonyms+1];
+      for (i=0;i<nSynonyms;i++)
+        HS1[i] = hetSynonym[i];
+      if (hetSynonym)  delete[] hetSynonym;
+      hetSynonym = HS1;
+      hetSynonym[nSynonyms] = NULL;
+      CreateCopy ( hetSynonym[nSynonyms],W );
+      nSynonyms++;
+    } else  {
+      // just add W to the last synonym
+      CreateConcat ( hetSynonym[nSynonyms-1],pstr(" "),W );
+    }
+  }
+
+
+  void HetCompound::HETNAM_PDBDump ( io::RFile f )  {
+  char S[100];
+  pstr p1,p2;
+  char c;
+  int  N,i;
+
+    if (!comment)  return;
+
+    c = ' ';
+    N  = 0;
+    p1 = comment;
+    do  {
+      N++;
+      if (N==1)  sprintf ( S,"HETNAM     %3s " ,hetID   );
+           else  sprintf ( S,"HETNAM  %2i %3s ",N,hetID );
+      while (*p1==' ')  p1++;
+      p2 = strchr(p1,'\n');
+      if (p2)  {
+        c   = *p2;
+        *p2 = char(0);
+      } else if (strlen(p1)>53)  {
+        i = 0;
+        while (p1[i] && (i<53) && (p1[i]!=' '))  i++;
+        p2  = &(p1[i]);
+        c   = *p2;
+        *p2 = char(0);
+      }
+      if (*p1)  {
+        strcat      ( S,p1 );
+        PadSpaces   ( S,80 );
+        f.WriteLine ( S );
+      } else
+        N--;
+      if (p2)  {
+        *p2 = c;
+        if (c)  p1 = p2+1;
+          else  p2 = NULL;
+      }
+    } while (p2);
+
+  }
+
+
+  void HetCompound::HETSYN_PDBDump ( io::RFile f )  {
+  char S[100];
+  pstr p;
+  char c;
+  int  N,k,i,l;
+    if (!hetSynonym)  return;
+    N = 0;
+    k = 0;
+    p = &(hetSynonym[0][0]);
+    do  {
+      N++;
+      if (N==1)  sprintf ( S,"HETSYN     %3s " ,hetID   );
+           else  sprintf ( S,"HETSYN  %2i %3s ",N,hetID );
+      i = 0;
+      do  {
+        l = strlen(p)+2;
+        if (i+l<54)  {
+          strcat ( S,p );
+          if (k<nSynonyms-1) strcat ( S,"; " );
+          k++;
+          i += l;
+          if (k<nSynonyms)  p = &(hetSynonym[k][0]);
+                      else  i = 60;  // break loop
+        } else  {
+          if (i==0)  {
+            // too long synonym, has to be split over several lines
+            i = l-3;
+            while (i>51)  {
+              i--;
+              while ((i>0) && (p[i]!=' '))  i--;
+            }
+            if (i<2)  i = 51;  // no spaces!
+            c    = p[i];
+            p[i] = char(0);
+            strcat ( S,p );
+            p[i] = c;
+            p    = &(p[i]);
+            while (*p==' ')  p++;
+          }
+          i = 60;  // break loop
+        }
+      } while (i<54);
+      PadSpaces ( S,80 );
+      f.WriteLine ( S );
+    } while (k<nSynonyms);
+  }
+
+
+  void HetCompound::FORMUL_PDBDump ( io::RFile f )  {
+  char S[100];
+  pstr p1,p2;
+  char c;
+  int  N,i;
+    if (!Formula)  return;
+    N  = 0;
+    p1 = Formula;
+    do  {
+      N++;
+      if (compNum>MinInt4)  {
+        if (N==1)  sprintf ( S,"FORMUL  %2i  %3s    " ,compNum,hetID   );
+             else  sprintf ( S,"FORMUL  %2i  %3s %2i ",compNum,hetID,N );
+      } else  {
+        if (N==1)  sprintf ( S,"FORMUL      %3s    " ,hetID   );
+             else  sprintf ( S,"FORMUL      %3s %2i ",hetID,N );
+      }
+      S[18] = wc;
+      p2 = strchr(p1,'\n');
+      if (p2)  {
+        c   = *p2;
+        *p2 = char(0);
+      } else if (strlen(p1)>50)  {
+        while (*p1==' ')  p1++;
+        i = 0;
+        while (p1[i] && (i<50) && (p1[i]!=' '))  i++;
+        p2  = &(p1[i]);
+        c   = *p2;
+        *p2 = char(0);
+      }
+      strcat ( S,p1 );
+      if (p2)  {
+        *p2 = c;
+        p1  = p2+1;
+      }
+      PadSpaces ( S,80 );
+      f.WriteLine ( S );
+    } while (p2);
+  }
+
+
+  void  HetCompound::FormComString ( pstr & F )  {
+  pstr p;
+  int  i;
+    if (F)  {
+      delete[] F;
+      F = NULL;
+    }
+    if (comment)  {
+      CreateCopy ( F,comment );
+      i = 0;
+      p = comment;
+      while (*p)  {
+        p++;
+        if (*p=='\n')  i = 0;
+                 else  i++;
+        if (i>68)  {
+          F[i] = char(0);
+          CreateConcat ( F,pstr("\n"),p );
+          i = 0;
+        }
+      }
+    }
+  }
+
+
+  void  HetCompound::FormSynString ( pstr & F )  {
+  pstr p;
+  char c;
+  int  i,k,l;
+    if (F)  {
+      delete[] F;
+      F = NULL;
+    }
+    if (hetSynonym)  {
+      CreateCopy ( F,pstr("  ") );
+      k = 0;
+      p = &(hetSynonym[0][0]);
+      do  {
+        l = strlen(p)+2;
+        if (l<=60)  {
+          if (k<nSynonyms-1)  CreateConcat ( F,p,pstr(";\n  ") );
+                        else  CreateConcat ( F,p );
+          k++;
+          if (k<nSynonyms)  p = &(hetSynonym[k][0]);
+        } else  {
+          // too long synonym, has to be split over several lines
+          i = l-3;
+          while (i>60)  {
+            i--;
+            while ((i>0) && (p[i]!=' '))  i--;
+          }
+          if (i<2)  i = 60;  // no spaces!
+          c    = p[i];
+          p[i] = char(0);
+          CreateConcat ( F,p,pstr("\n  ") );
+          p[i] = c;
+          p    = &(p[i]);
+          while (*p==' ')  p++;
+        }
+      } while (k<nSynonyms);
+    }
+  }
+
+  void  HetCompound::FormForString ( pstr & F )  {
+  pstr p;
+  int  i;
+    if (F)  {
+      delete[] F;
+      F = NULL;
+    }
+    if (Formula)  {
+      CreateCopy ( F,Formula );
+      i = 0;
+      p = &(Formula[0]);
+      while (*p)  {
+        p++;
+        if (*p=='\n')  i = 0;
+                 else  i++;
+        if (i>68)  {
+          F[i] = char(0);
+          CreateConcat ( F,pstr("\n"),p );
+          i = 0;
+        }
+      }
+    }
+  }
+
+
+  void  HetCompound::Copy ( PHetCompound hetCompound )  {
+  int i;
+    FreeMemory ();
+    strcpy     ( hetID  ,hetCompound->hetID   );
+    CreateCopy ( comment,hetCompound->comment );
+    nSynonyms = hetCompound->nSynonyms;
+    if (nSynonyms>0) {
+      hetSynonym = new pstr[nSynonyms];
+      for (i=0;i<nSynonyms;i++)  {
+        hetSynonym[i] = NULL;
+        CreateCopy ( hetSynonym[i],hetCompound->hetSynonym[i] );
+      }
+    }
+    compNum = hetCompound->compNum;
+    wc      = hetCompound->wc;
+    CreateCopy ( Formula,hetCompound->Formula );
+  }
+
+  void  HetCompound::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte    ( &Version    );
+    f.WriteTerLine ( hetID,false );
+    f.CreateWrite  ( comment     );
+    f.WriteInt     ( &nSynonyms  );
+    for (i=0;i<nSynonyms;i++)
+      f.CreateWrite ( hetSynonym[i] );
+    f.WriteInt    ( &compNum       );
+    f.WriteFile   ( &wc,sizeof(wc) );
+    f.CreateWrite ( Formula        );
+  }
+
+  void  HetCompound::read ( io::RFile f )  {
+  int  i;
+  byte Version;
+    FreeMemory();
+    f.ReadByte    ( &Version    );
+    f.ReadTerLine ( hetID,false );
+    f.CreateRead  ( comment     );
+    f.ReadInt     ( &nSynonyms  );
+    if (nSynonyms>0) {
+      hetSynonym = new pstr[nSynonyms];
+      for (i=0;i<nSynonyms;i++)  {
+        hetSynonym[i] = NULL;
+        f.CreateRead ( hetSynonym[i] );
+      }
+    }
+    f.ReadInt    ( &compNum       );
+    f.ReadFile   ( &wc,sizeof(wc) );
+    f.CreateRead ( Formula        );
+  }
+
+  MakeStreamFunctions(HetCompound)
+
+
+  //  ====================  HetCompounds  =======================
+
+
+  HetCompounds::HetCompounds() : io::Stream()  {
+    InitHetCompounds();
+  }
+
+  HetCompounds::HetCompounds ( io::RPStream Object )
+              : io::Stream(Object)  {
+    InitHetCompounds();
+  }
+
+  HetCompounds::~HetCompounds() {
+    FreeMemory();
+  }
+
+  void  HetCompounds::InitHetCompounds()  {
+    nHets       = 0;
+    hetCompound = NULL;
+    Closed      = false;
+  }
+
+  void  HetCompounds::FreeMemory()  {
+  int i;
+    if (hetCompound)  {
+      for (i=0;i<nHets;i++)
+        if (hetCompound[i])  delete hetCompound[i];
+      delete[] hetCompound;
+      hetCompound = NULL;
+    }
+    nHets = 0;
+  }
+
+  void  HetCompounds::ConvertHETNAM ( cpstr S )  {
+  ResName hetID;
+  char    L[100];
+  int     l,i;
+    l = strlen(S);
+    if (l>12)  {
+      strcpy_n0 ( hetID,&(S[11]),3 );
+      i = AddHetName ( hetID );
+      if (l>15)  {
+        if (hetCompound[i]->comment)  strcpy ( L,"\n" );
+                                else  L[0] = char(0);
+        strcat       ( L,&(S[15])    );
+        CutSpaces    ( L,SCUTKEY_END );
+        CreateConcat ( hetCompound[i]->comment,L );
+      }
+    }
+  }
+
+  void  HetCompounds::ConvertHETSYN ( cpstr S )  {
+  ResName hetID;
+  char    L[100];
+  int     l,i,j,k;
+    l = strlen(S);
+    if (l>12)  {
+      strcpy_n0 ( hetID,&(S[11]),3 );
+      i = AddHetName ( hetID );
+      if (l>15)  {
+        j = 15;
+        do {
+          while (S[j]==' ')  j++;
+          k = 0;
+          if (S[j])  {
+            while (S[j] && (S[j]!=';'))
+              L[k++] = S[j++];
+            L[k--] = char(0);
+            while ((k>0) && (L[k]==' '))  L[k--] = char(0);
+            if (L[0])  {
+              hetCompound[i]->AddKeyWord ( L,Closed );
+              Closed = (S[j]==';');
+            }
+            if (S[j])  j++;
+          }
+        } while (S[j]);
+        /*
+        p1 = &(S[15]);
+        do  {
+          p2 = strchr ( p1,';' );
+          if (p2)  {
+            c   = *p2;
+            *p2 = char(0);
+          }
+          strcpy_css ( L,p1 );
+          if (L[0])
+            hetCompound[i]->AddKeyWord ( L,Closed );
+          if (p2) {
+            if (L[0]) Closed = true;
+            *p2 = c;
+            p1 = p2+1;
+          } else if (L[0])
+            Closed = false;
+        } while (p2);
+        */
+      }
+    }
+  }
+
+  void  HetCompounds::ConvertFORMUL ( cpstr S )  {
+  ResName hetID;
+  char    L[100];
+  int     l,i;
+    l = strlen(S);
+    if (l>13)  {
+      strcpy_n0 ( hetID,&(S[12]),3 );
+      i = AddHetName ( hetID );
+      if (l>18) {
+        GetInteger ( hetCompound[i]->compNum,&(S[9]),2 );
+        hetCompound[i]->wc = S[18];
+        if (strlen(S)>19)  {
+          if (hetCompound[i]->Formula)  strcpy ( L,"\n" );
+                                  else  L[0] = char(0);
+          strcat       ( L,&(S[19])    );
+          CutSpaces    ( L,SCUTKEY_END );
+          CreateConcat ( hetCompound[i]->Formula,L );
+        }
+      }
+    }
+  }
+  int  HetCompounds::AddHetName ( cpstr H )  {
+  PPHetCompound HC1;
+  int            i;
+    i = 0;
+    while (i<nHets)  {
+      if (hetCompound[i])  {
+        if (!strcmp(hetCompound[i]->hetID,H))  break;
+      }
+      i++;
+    }
+    if (i>=nHets)  {
+      HC1 = new PHetCompound[nHets+1];
+      for (i=0;i<nHets;i++)
+        HC1[i] = hetCompound[i];
+      if (hetCompound)  delete[] hetCompound;
+      hetCompound = HC1;
+      hetCompound[nHets] = new HetCompound ( H );
+      i = nHets;
+      nHets++;
+    }
+    return i;
+  }
+
+  void HetCompounds::PDBASCIIDump ( io::RFile f )  {
+  int  i;
+
+    for (i=0;i<nHets;i++)
+      if (hetCompound[i])
+        hetCompound[i]->HETNAM_PDBDump ( f );
+
+    for (i=0;i<nHets;i++)
+      if (hetCompound[i])
+        hetCompound[i]->HETSYN_PDBDump ( f );
+
+    for (i=0;i<nHets;i++)
+      if (hetCompound[i])
+        hetCompound[i]->FORMUL_PDBDump ( f );
+
+  }
+
+
+  void  HetCompounds::MakeCIF ( mmcif::PData CIF )  {
+  mmcif::PLoop Loop;
+  pstr        F;
+  int         RC;
+  int         i;
+
+    if (!hetCompound)  return;
+
+    RC = CIF->AddLoop ( CIFCAT_CHEM_COMP,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      Loop->AddLoopTag ( CIFTAG_ID               );
+      Loop->AddLoopTag ( CIFTAG_NAME             );
+      Loop->AddLoopTag ( CIFTAG_NDB_SYNONYMS     );
+      Loop->AddLoopTag ( CIFTAG_NDB_COMPONENT_NO );
+      Loop->AddLoopTag ( CIFTAG_FORMULA          );
+    }
+
+    F = NULL;
+    for (i=0;i<nHets;i++)
+      if (hetCompound[i])  {
+        Loop->AddString ( hetCompound[i]->hetID );
+        hetCompound[i]->FormComString ( F );
+        Loop->AddString ( F );
+        hetCompound[i]->FormSynString ( F );
+        Loop->AddString ( F );
+        if (hetCompound[i]->compNum>MinInt4)
+              Loop->AddInteger ( hetCompound[i]->compNum );
+        else  Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
+        hetCompound[i]->FormForString ( F );
+        Loop->AddString ( F );
+      }
+
+    if (F)  delete[] F;
+
+  }
+
+  ERROR_CODE HetCompounds::GetCIF ( mmcif::PData CIF )  {
+  mmcif::PLoop Loop;
+  char         L[100];
+  ResName      hetID;
+  pstr         F,p1,p2;
+  char         c;
+  int          RC,i,l,k;
+
+    FreeMemory();
+    c = char(0);  // only to supress compiler warnings
+
+    Loop = CIF->GetLoop ( CIFCAT_CHEM_COMP );
+    if (!Loop)  return Error_NoError;
+
+    l = Loop->GetLoopLength();
+    F = NULL;
+
+    for (i=0;i<l;i++)  {
+      CIFGetString    ( hetID,Loop,CIFTAG_ID,i,sizeof(hetID),
+                        pstr("---") );
+      k = AddHetName  ( hetID );
+      Loop->GetString ( hetCompound[k]->comment,CIFTAG_NAME,i,true );
+      RC = Loop->GetInteger ( hetCompound[k]->compNum,
+                                       CIFTAG_NDB_COMPONENT_NO,i,true );
+      if (RC)  hetCompound[i]->compNum = MinInt4;
+      Loop->GetString ( hetCompound[k]->Formula,CIFTAG_FORMULA,i,true );
+      RC = Loop->GetString ( F,CIFTAG_NDB_SYNONYMS,i,true );
+      if ((!RC) && F )  {
+        p1 = &(F[0]);
+        while (*p1)  {
+          if (*p1=='\n')  *p1 = ' ';
+          p1++;
+        }
+        p1 = &(F[0]);
+        do  {
+          p2 = strchr ( p1,';' );
+          if (p2)  {
+            c   = *p2;
+            *p2 = char(0);
+          }
+          strcpy_css ( L,p1 );
+          hetCompound[i]->AddKeyWord ( L,true );
+          if (p2) {
+            *p2 = c;
+            p1 = p2+1;
+          }
+        } while (p2);
+      }
+      hetCompound[i]->wc = ' ';
+    }
+
+  //  CIF->DeleteLoop ( CIFCAT_CHEM_COMP );
+
+    if (F)  delete[] F;
+
+    return Error_NoError;
+
+  }
+
+  void  HetCompounds::Copy ( PHetCompounds HetCompounds )  {
+  int i;
+    FreeMemory();
+    nHets = HetCompounds->nHets;
+    if (nHets>0)  {
+      hetCompound = new PHetCompound[nHets];
+      for (i=0;i<nHets;i++)  {
+        hetCompound[i] = new HetCompound ( "" );
+        hetCompound[i]->Copy ( HetCompounds->hetCompound[i] );
+      }
+    }
+  }
+
+  void  HetCompounds::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    f.WriteInt  ( &nHets   );
+    for (i=0;i<nHets;i++)
+      hetCompound[i]->write ( f );
+  }
+
+  void  HetCompounds::read ( io::RFile f )  {
+  int  i;
+  byte Version;
+    FreeMemory();
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &nHets   );
+    if (nHets>0)  {
+      hetCompound = new PHetCompound[nHets];
+      for (i=0;i<nHets;i++)  {
+        hetCompound[i] = new HetCompound ( "---" );
+        hetCompound[i]->read ( f );
+      }
+    }
+  }
+
+  MakeStreamFunctions(HetCompounds)
+
+
+
+  //  ====================  SSContainer  =========================
+
+  PContainerClass SSContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template : return
+                          ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_Helix    : return new Helix();
+      case ClassID_Turn     : return new Turn ();
+    }
+  }
+
+  MakeStreamFunctions(SSContainer)
+
+
+  //  ================  Helix  ===================
+
+  Helix::Helix() : ContainerClass()  {
+    InitHelix();
+  }
+
+  Helix::Helix ( cpstr S ) : ContainerClass()  {
+    InitHelix();
+    ConvertPDBASCII ( S );
+  }
+
+  Helix::Helix ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitHelix();
+  }
+
+  Helix::~Helix() {
+    if (comment)  delete[] comment;
+  }
+
+  void  Helix::InitHelix()  {
+
+    serNum = 0;                   // serial number
+    strcpy ( helixID    ,"---" ); // helix ID
+    strcpy ( initResName,"---" ); // name of the helix's initial residue
+    strcpy ( initChainID,""    ); // chain ID for the chain
+                                  // containing the helix
+    initSeqNum = 0;               // sequence number of the initial
+                                  //    residue
+    strcpy ( initICode  ,""    ); // insertion code of the initial
+                                  //    residue
+    strcpy ( endResName ,"---" ); // name of the helix's terminal residue
+    strcpy ( endChainID ,""    ); // chain ID for the chain
+                                  // containing the helix
+    endSeqNum  = 0;               // sequence number of the terminal
+                                  //    residue
+    strcpy ( endICode   ,""    ); // insertion code of the terminal
+                                  //    residue
+    helixClass = 0;               // helix class
+    comment    = NULL;            // comment about the helix
+    length     = 0;               // length of the helix
+
+  }
+
+  void  Helix::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB OBSLTE line number N
+  //  from the class' data
+    strcpy     ( S,"HELIX" );
+    PadSpaces  ( S,80 );
+    PutInteger ( &(S[7]) ,serNum     ,3  );
+    strcpy_n1  ( &(S[11]),helixID    ,3  );
+    strcpy_n1  ( &(S[15]),initResName,3  );
+    if (initChainID[0])  S[19] = initChainID[0];
+    PutIntIns  ( &(S[21]),initSeqNum ,4,initICode );
+    strcpy_n1  ( &(S[27]),endResName ,3  );
+    if (endChainID[0])   S[31] = endChainID[0];
+    PutIntIns  ( &(S[33]),endSeqNum  ,4,endICode  );
+    PutInteger ( &(S[38]),helixClass ,2  );
+    if (comment)
+      strcpy_n ( &(S[40]),comment    ,30 );
+    PutInteger ( &(S[71]),length     ,5  );
+  }
+
+  void AddStructConfTags ( mmcif::PLoop Loop )  {
+    Loop->AddLoopTag ( CIFTAG_CONF_TYPE_ID               );
+    Loop->AddLoopTag ( CIFTAG_ID                         );
+    Loop->AddLoopTag ( CIFTAG_PDB_ID                     );
+    Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID          );
+    Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID          );
+    Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID           );
+    Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
+    Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID          );
+    Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID          );
+    Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID           );
+    Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
+    Loop->AddLoopTag ( CIFTAG_NDB_HELIX_CLASS_PDB        );
+    Loop->AddLoopTag ( CIFTAG_DETAILS                    );
+    Loop->AddLoopTag ( CIFTAG_NDB_LENGTH                 );
+  }
+
+  #define  HelixTypeID  "HELX_P"
+
+  void  Helix::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop;
+  int         RC;
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
+    if (RC!=mmcif::CIFRC_Ok)
+      // the category was (re)created, provide tags
+      AddStructConfTags ( Loop );
+    Loop->AddString  ( pstr(HelixTypeID) );
+    Loop->AddInteger ( serNum      );
+    Loop->AddString  ( helixID     );
+    Loop->AddString  ( initResName );
+    Loop->AddString  ( initChainID );
+    Loop->AddInteger ( initSeqNum  );
+    Loop->AddString  ( initICode,true );
+    Loop->AddString  ( endResName  );
+    Loop->AddString  ( endChainID  );
+    Loop->AddInteger ( endSeqNum   );
+    Loop->AddString  ( endICode ,true );
+    Loop->AddInteger ( helixClass  );
+    Loop->AddString  ( comment     );
+    Loop->AddInteger ( length      );
+  }
+
+  ERROR_CODE Helix::ConvertPDBASCII ( cpstr S )  {
+  char L[100];
+    GetInteger  ( serNum     ,&(S[7]) ,3  );
+    strcpy_ncss ( helixID    ,&(S[11]),3  );
+    strcpy_ncss ( initResName,&(S[15]),3  );
+    strcpy_ncss ( initChainID,&(S[19]),1  );
+    GetIntIns   ( initSeqNum,initICode,&(S[21]),4  );
+    strcpy_ncss ( endResName ,&(S[27]),3  );
+    strcpy_ncss ( endChainID ,&(S[31]),1  );
+    GetIntIns   ( endSeqNum ,endICode ,&(S[33]),4  );
+    GetInteger  ( helixClass ,&(S[38]),2  );
+    strcpy_ncss ( L          ,&(S[40]),30 );
+    CreateCopy  ( comment    ,L           );
+    GetInteger  ( length     ,&(S[71]),5  );
+    return Error_NoError;
+  }
+
+  ERROR_CODE Helix::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  int          RC,l;
+  pstr         F;
+  bool         Done;
+  ERROR_CODE   rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+
+    l    = Loop->GetLoopLength();
+    Done = n>=l;
+    while (!Done) {
+      F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,n,RC );
+      if ((!RC) && F)  Done = (strcmp(F,HelixTypeID)==0);
+                 else  Done = false;
+      if (!Done)  {
+        n++;
+        Done = n>=l;
+      }
+    }
+
+    if (n>=l)  {
+      n = -1;  // finish processing of Helix
+      return Error_EmptyCIF;
+    }
+
+    Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,n );
+
+    rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( helixID    ,Loop,CIFTAG_PDB_ID,
+                               n,sizeof(helixID),pstr("   ") );
+
+    CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
+                               n,sizeof(initResName),pstr("   ") );
+    CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
+                               n,sizeof(initChainID),pstr("") );
+    CIFGetString ( initICode  ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
+                               n,sizeof(initICode),pstr("") );
+    if (CIFGetInteger(initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,n))
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
+                              n,sizeof(endResName),pstr("   ") );
+    CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
+                              n,sizeof(endChainID),pstr("") );
+    CIFGetString ( endICode  ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
+                              n,sizeof(endICode),pstr("") );
+    rc = CIFGetInteger(endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    rc = CIFGetInteger(helixClass,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CreateCopy     ( comment,Loop->GetString(CIFTAG_DETAILS,n,RC));
+    Loop->DeleteField ( CIFTAG_DETAILS,n );
+    rc = CIFGetInteger ( length,Loop,CIFTAG_NDB_LENGTH,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  Helix::Copy ( PContainerClass Helix )  {
+    serNum     = PHelix(Helix)->serNum;
+    initSeqNum = PHelix(Helix)->initSeqNum;
+    endSeqNum  = PHelix(Helix)->endSeqNum;
+    helixClass = PHelix(Helix)->helixClass;
+    length     = PHelix(Helix)->length;
+    strcpy ( helixID    ,PHelix(Helix)->helixID     );
+    strcpy ( initResName,PHelix(Helix)->initResName );
+    strcpy ( initChainID,PHelix(Helix)->initChainID );
+    strcpy ( initICode  ,PHelix(Helix)->initICode   );
+    strcpy ( endResName ,PHelix(Helix)->endResName  );
+    strcpy ( endChainID ,PHelix(Helix)->endChainID  );
+    strcpy ( endICode   ,PHelix(Helix)->endICode    );
+    CreateCopy ( comment,PHelix(Helix)->comment );
+  }
+
+  void  Helix::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version    );
+    f.WriteInt  ( &serNum     );
+    f.WriteInt  ( &initSeqNum );
+    f.WriteInt  ( &endSeqNum  );
+    f.WriteInt  ( &helixClass );
+    f.WriteInt  ( &length     );
+    f.WriteTerLine ( helixID    ,false );
+    f.WriteTerLine ( initResName,false );
+    f.WriteTerLine ( initChainID,false );
+    f.WriteTerLine ( initICode  ,false );
+    f.WriteTerLine ( endResName ,false );
+    f.WriteTerLine ( endChainID ,false );
+    f.WriteTerLine ( endICode   ,false );
+    f.CreateWrite ( comment );
+  }
+
+  void  Helix::read  ( io::RFile f ) {
+  byte Version;
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &serNum     );
+    f.ReadInt  ( &initSeqNum );
+    f.ReadInt  ( &endSeqNum  );
+    f.ReadInt  ( &helixClass );
+    f.ReadInt  ( &length     );
+    f.ReadTerLine ( helixID    ,false );
+    f.ReadTerLine ( initResName,false );
+    f.ReadTerLine ( initChainID,false );
+    f.ReadTerLine ( initICode  ,false );
+    f.ReadTerLine ( endResName ,false );
+    f.ReadTerLine ( endChainID ,false );
+    f.ReadTerLine ( endICode   ,false );
+    f.CreateRead ( comment );
+  }
+
+  MakeStreamFunctions(Helix)
+
+
+
+  //  ================  Strand  =====================
+
+  Strand::Strand () : io::Stream()  {
+    InitStrand();
+  }
+
+  Strand::Strand ( io::RPStream Object ) : io::Stream(Object)  {
+    InitStrand();
+  }
+
+  Strand::~Strand() {
+  }
+
+  void  Strand::InitStrand()  {
+    initSeqNum = MinInt4;
+    endSeqNum  = MinInt4;
+    sense      = 0;
+    curResSeq  = MinInt4;
+    prevResSeq = MinInt4;
+    strandNo   = 0;
+    strcpy ( sheetID    ,"sheet_0"  );
+    strcpy ( initResName,"   "      );
+    strcpy ( initChainID,""         );
+    strcpy ( initICode  ,""         );
+    strcpy ( endResName ,"   "      );
+    strcpy ( endChainID ,""         );
+    strcpy ( endICode   ,""         );
+    strcpy ( curAtom    ," "        );
+    strcpy ( curResName ,"   "      );
+    strcpy ( curChainID ,""         );
+    strcpy ( curICode   ,""         );
+    strcpy ( prevAtom   ," "        );
+    strcpy ( prevResName,"   "      );
+    strcpy ( prevChainID,""         );
+    strcpy ( prevICode  ,""         );
+  }
+
+  void  Strand::PDBASCIIDump ( pstr S )  {
+  //   Finishes making the ASCII PDB SHEET line number N
+  // from the class' data. Making is initiated by Sheet.
+
+    strcpy_n1  ( &(S[17]),initResName,3 );
+    if (initChainID[0])  S[21] = initChainID[0];
+    PutIntIns  ( &(S[22]),initSeqNum ,4,initICode );
+
+    strcpy_n1  ( &(S[28]),endResName ,3 );
+    if (endChainID[0])   S[32] = endChainID[0];
+    PutIntIns  ( &(S[33]),endSeqNum  ,4,endICode  );
+
+    PutInteger ( &(S[38]),sense      ,2 );
+
+    strcpy_n1  ( &(S[41]),curAtom    ,4 );
+    strcpy_n1  ( &(S[45]),curResName ,3 );
+    if (curChainID[0])   S[49] = curChainID[0];
+    PutIntIns  ( &(S[50]),curResSeq  ,4,curICode  );
+
+    strcpy_n1  ( &(S[56]),prevAtom   ,4 );
+    strcpy_n1  ( &(S[60]),prevResName,3 );
+    if (prevChainID[0])  S[64] = prevChainID[0];
+    PutIntIns  ( &(S[65]),prevResSeq ,4,prevICode );
+
+  }
+
+
+  void  Strand::MakeCIF ( mmcif::PData CIF )  {
+  mmcif::PLoop Loop;
+  int         RC;
+
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_RANGE,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_SHEET_ID                   );
+      Loop->AddLoopTag ( CIFTAG_ID                         );
+      Loop->AddLoopTag ( CIFTAG_BEG_LABEL_COMP_ID          );
+      Loop->AddLoopTag ( CIFTAG_BEG_LABEL_ASYM_ID          );
+      Loop->AddLoopTag ( CIFTAG_BEG_LABEL_SEQ_ID           );
+      Loop->AddLoopTag ( CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB );
+      Loop->AddLoopTag ( CIFTAG_END_LABEL_COMP_ID          );
+      Loop->AddLoopTag ( CIFTAG_END_LABEL_ASYM_ID          );
+      Loop->AddLoopTag ( CIFTAG_END_LABEL_SEQ_ID           );
+      Loop->AddLoopTag ( CIFTAG_NDB_END_LABEL_INS_CODE_PDB );
+    }
+    Loop->AddString  ( sheetID     );
+    Loop->AddInteger ( strandNo    );
+    Loop->AddString  ( initResName );
+    Loop->AddString  ( initChainID );
+    Loop->AddInteger ( initSeqNum  );
+    Loop->AddString  ( initICode,true );
+    Loop->AddString  ( endResName  );
+    Loop->AddString  ( endChainID  );
+    Loop->AddInteger ( endSeqNum   );
+    Loop->AddString  ( endICode ,true );
+
+  }
+
+
+  ERROR_CODE Strand::ConvertPDBASCII ( cpstr S )  {
+
+    GetInteger  ( strandNo   ,&(S[7])  ,3 );
+    strcpy_ncss ( sheetID    ,&(S[11]) ,3 );
+
+    strcpy_ncss ( initResName,&(S[17]) ,3 );
+    strcpy_ncss ( initChainID,&(S[21]) ,1 );
+    GetIntIns   ( initSeqNum ,initICode,&(S[22]),4 );
+
+    strcpy_ncss ( endResName ,&(S[28]) ,3 );
+    strcpy_ncss ( endChainID ,&(S[32]) ,1 );
+    GetIntIns   ( endSeqNum  ,endICode ,&(S[33]),4 );
+
+    GetInteger  ( sense      ,&(S[38]) ,2 );
+
+    GetString   ( curAtom    ,&(S[41]) ,4 );
+    strcpy_ncss ( curResName ,&(S[45]) ,3 );
+    strcpy_ncss ( curChainID ,&(S[49]) ,1 );
+    GetIntIns   ( curResSeq  ,curICode ,&(S[50]),4 );
+
+    GetString   ( prevAtom   ,&(S[56]) ,4 );
+    strcpy_ncss ( prevResName,&(S[60]) ,3 );
+    strcpy_ncss ( prevChainID,&(S[64]) ,1 );
+    GetIntIns   ( prevResSeq ,prevICode,&(S[65]),4 );
+
+    return Error_NoError;
+
+  }
+
+  int  Strand::GetCIF ( mmcif::PData CIF, cpstr sheet_id )  {
+  mmcif::PLoop Loop;
+  int         RC,l,i,sNo;
+  pstr        F;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_RANGE );
+    if (Loop)  {
+      l = Loop->GetLoopLength();
+      i = 0;
+      while (i<l)  {
+        F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+        if (F && (!RC))  {
+          if (!strcmp(F,sheet_id))  {
+            strcpy ( sheetID,sheet_id );
+            if (CIFGetInteger(sNo,Loop,CIFTAG_ID,i))  return i;
+            if (sNo==strandNo)  {
+              CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
+                             i,sizeof(initResName),pstr("   ") );
+              CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
+                             i,sizeof(initChainID),pstr("") );
+              CIFGetString ( initICode,Loop,
+                             CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
+                             i,sizeof(initICode),pstr("") );
+              if (CIFGetInteger(initSeqNum,Loop,
+                             CIFTAG_BEG_LABEL_SEQ_ID,i))
+                return i;
+              CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
+                             i,sizeof(endResName),pstr("   ") );
+              CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
+                             i,sizeof(endChainID),pstr("") );
+              CIFGetString ( endICode  ,Loop,
+                             CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
+                             i,sizeof(endICode),pstr("") );
+              if (CIFGetInteger(endSeqNum,Loop,
+                             CIFTAG_END_LABEL_SEQ_ID,i))
+                return i;
+              Loop->DeleteRow ( i );
+              i = l+100;  // break the loop
+            }
+          }
+        }
+        i++;
+      }
+    }
+
+    return 0;
+
+  }
+
+  void  Strand::Copy ( PStrand Strand )  {
+    initSeqNum = Strand->initSeqNum;
+    endSeqNum  = Strand->endSeqNum;
+    sense      = Strand->sense;
+    curResSeq  = Strand->curResSeq;
+    prevResSeq = Strand->prevResSeq;
+    strcpy ( initResName,Strand->initResName );
+    strcpy ( initChainID,Strand->initChainID );
+    strcpy ( initICode  ,Strand->initICode   );
+    strcpy ( endResName ,Strand->endResName  );
+    strcpy ( endChainID ,Strand->endChainID  );
+    strcpy ( endICode   ,Strand->endICode    );
+    strcpy ( curAtom    ,Strand->curAtom     );
+    strcpy ( curResName ,Strand->curResName  );
+    strcpy ( curChainID ,Strand->curChainID  );
+    strcpy ( curICode   ,Strand->curICode    );
+    strcpy ( prevAtom   ,Strand->prevAtom    );
+    strcpy ( prevResName,Strand->prevResName );
+    strcpy ( prevChainID,Strand->prevChainID );
+    strcpy ( prevICode  ,Strand->prevICode   );
+  }
+
+  void  Strand::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version    );
+    f.WriteInt  ( &initSeqNum );
+    f.WriteInt  ( &endSeqNum  );
+    f.WriteInt  ( &sense      );
+    f.WriteInt  ( &curResSeq  );
+    f.WriteInt  ( &prevResSeq );
+    f.WriteTerLine ( initResName,false );
+    f.WriteTerLine ( initChainID,false );
+    f.WriteTerLine ( initICode  ,false );
+    f.WriteTerLine ( endResName ,false );
+    f.WriteTerLine ( endChainID ,false );
+    f.WriteTerLine ( endICode   ,false );
+    f.WriteTerLine ( curAtom    ,false );
+    f.WriteTerLine ( curResName ,false );
+    f.WriteTerLine ( curChainID ,false );
+    f.WriteTerLine ( curICode   ,false );
+    f.WriteTerLine ( prevAtom   ,false );
+    f.WriteTerLine ( prevResName,false );
+    f.WriteTerLine ( prevChainID,false );
+    f.WriteTerLine ( prevICode  ,false );
+  }
+
+  void  Strand::read  ( io::RFile f ) {
+  byte Version;
+    f.ReadByte ( &Version    );
+    f.ReadInt  ( &initSeqNum );
+    f.ReadInt  ( &endSeqNum  );
+    f.ReadInt  ( &sense      );
+    f.ReadInt  ( &curResSeq  );
+    f.ReadInt  ( &prevResSeq );
+    f.ReadTerLine ( initResName,false );
+    f.ReadTerLine ( initChainID,false );
+    f.ReadTerLine ( initICode  ,false );
+    f.ReadTerLine ( endResName ,false );
+    f.ReadTerLine ( endChainID ,false );
+    f.ReadTerLine ( endICode   ,false );
+    f.ReadTerLine ( curAtom    ,false );
+    f.ReadTerLine ( curResName ,false );
+    f.ReadTerLine ( curChainID ,false );
+    f.ReadTerLine ( curICode   ,false );
+    f.ReadTerLine ( prevAtom   ,false );
+    f.ReadTerLine ( prevResName,false );
+    f.ReadTerLine ( prevChainID,false );
+    f.ReadTerLine ( prevICode  ,false );
+  }
+
+  MakeStreamFunctions(Strand)
+
+
+
+
+  //  ================  Sheet  ===================
+
+  Sheet::Sheet() : io::Stream()  {
+    InitSheet();
+  }
+
+  Sheet::Sheet ( io::RPStream Object ) : io::Stream(Object)  {
+    InitSheet();
+  }
+
+  Sheet::~Sheet()  {
+    FreeMemory();
+  }
+
+  void  Sheet::InitSheet()  {
+    nStrands   = 0;
+    sheetID[0] = char(0);
+    strand     = NULL;
+  }
+
+  void  Sheet::FreeMemory()  {
+  int i;
+    if (strand)  {
+      for (i=0;i<nStrands;i++)
+        if (strand[i])  delete strand[i];
+      delete[] strand;
+      strand = NULL;
+    }
+    nStrands   = 0;
+    sheetID[0] = char(0);
+  }
+
+  void  Sheet::PDBASCIIDump ( io::RFile f )  {
+  char  S[100];
+  int   i;
+    if (strand)
+      for (i=0;i<nStrands;i++)
+        if (strand[i])  {
+          strcpy      ( S,"SHEET"           );
+          PadSpaces   ( S,80                );
+          PutInteger  ( &(S[7]) ,i+1     ,3 );
+          strcpy_n1   ( &(S[11]),sheetID ,3 );
+          PutInteger  ( &(S[14]),nStrands,2 );
+          strand[i]->PDBASCIIDump ( S       );
+          f.WriteLine ( S                   );
+        }
+  }
+
+  void  Sheet::OrderSheet()  {
+  int       i,k;
+  PPStrand  strand1;
+    k = 0;
+    for (i=0;i<nStrands;i++)
+      if (strand[i])  k++;
+    if (k<nStrands)  {
+      strand1 = new PStrand[k];
+      k = 0;
+      for (i=0;i<nStrands;i++)
+        if (strand[i])  strand1[k++] = strand[i];
+      if (strand)  delete[] strand;
+      strand   = strand1;
+      nStrands = k;
+    }
+  }
+
+  void  Sheet::MakeCIF ( mmcif::PData CIF )  {
+  mmcif::PLoop Loop;
+  int          RC;
+  int          i;
+  bool         isSense;
+
+    OrderSheet();
+
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_SHEET_ID       );
+      Loop->AddLoopTag ( CIFTAG_NUMBER_STRANDS );
+    }
+    Loop->AddString  ( sheetID  );
+    Loop->AddInteger ( nStrands );
+
+    for (i=0;i<nStrands;i++)  {
+      strand[i]->MakeCIF ( CIF );
+      if (strand[i]->sense!=0)  isSense = true;
+    }
+
+    if (nStrands>1)  {
+
+      if (isSense)  {
+        RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_ORDER,Loop );
+        if (RC!=mmcif::CIFRC_Ok)  {
+          // the category was (re)created, provide tags
+          Loop->AddLoopTag ( CIFTAG_SHEET_ID   );
+          Loop->AddLoopTag ( CIFTAG_RANGE_ID_1 );
+          Loop->AddLoopTag ( CIFTAG_RANGE_ID_2 );
+          Loop->AddLoopTag ( CIFTAG_SENSE      );
+        }
+        for (i=1;i<nStrands;i++)  {
+          Loop->AddString  ( sheetID               );
+          Loop->AddInteger ( strand[i-1]->strandNo );
+          Loop->AddInteger ( strand[i]  ->strandNo );
+          if (strand[i]->sense>0)
+                Loop->AddString ( pstr("parallel")      );
+          else  Loop->AddString ( pstr("anti-parallel") );
+        }
+      }
+
+      RC = CIF->AddLoop ( CIFCAT_STRUCT_SHEET_HBOND,Loop );
+      if (RC!=mmcif::CIFRC_Ok)  {
+        // the category was (re)created, provide tags
+        Loop->AddLoopTag ( CIFTAG_SHEET_ID                       );
+        Loop->AddLoopTag ( CIFTAG_RANGE_ID_1                     );
+        Loop->AddLoopTag ( CIFTAG_RANGE_ID_2                     );
+        Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID      );
+        Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID  );
+        Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID  );
+        Loop->AddLoopTag ( CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID       );
+        Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE );
+        Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_ATOM_ID      );
+        Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID  );
+        Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID  );
+        Loop->AddLoopTag ( CIFTAG_RANGE_1_END_LABEL_SEQ_ID       );
+        Loop->AddLoopTag ( CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE );
+      }
+      for (i=1;i<nStrands;i++)  {
+        Loop->AddString  ( sheetID                );
+        Loop->AddInteger ( strand[i-1]->strandNo  );
+        Loop->AddInteger ( strand[i]->strandNo    );
+        Loop->AddString  ( strand[i]->curAtom     );
+        Loop->AddString  ( strand[i]->curResName  );
+        Loop->AddString  ( strand[i]->curChainID  );
+        Loop->AddInteger ( strand[i]->curResSeq   );
+        Loop->AddString  ( strand[i]->curICode ,true );
+        Loop->AddString  ( strand[i]->prevAtom    );
+        Loop->AddString  ( strand[i]->prevResName );
+        Loop->AddString  ( strand[i]->prevChainID );
+        Loop->AddInteger ( strand[i]->prevResSeq  );
+        Loop->AddString  ( strand[i]->prevICode,true );
+      }
+    }
+
+  }
+
+
+  ERROR_CODE Sheet::ConvertPDBASCII ( cpstr S )  {
+  int       i,k,ns;
+  SheetID   SID;
+  PPStrand  strand1;
+
+    GetInteger  ( k  ,&(S[7]) ,3 );
+    strcpy_ncss ( SID,&(S[11]),3 );
+    GetInteger  ( ns ,&(S[14]),2 );
+
+  //  if (!SID[0])  return  Error_NoSheetID;
+    if (!sheetID[0])  strcpy ( sheetID,SID );
+    else if (strcmp(sheetID,SID))
+                  return  Error_WrongSheetID;
+
+    if (k<=0)     return  Error_WrongStrandNo;
+
+    ns = IMax(k,ns);
+    if (!strand)  {
+      strand = new PStrand[ns];
+      for (i=0;i<ns;i++)
+        strand[i] = NULL;
+    } else if (ns>nStrands)  {
+      strand1 = new PStrand[ns];
+      for (i=0;i<nStrands;i++)
+        strand1[i] = strand[i];
+      for (i=nStrands;i<ns;i++)
+        strand1[i] = NULL;
+      if (strand)  delete[] strand;
+      strand = strand1;
+    }
+    nStrands = ns;
+
+    k--;
+    if (!strand[k])  strand[k] = new Strand();
+
+    return  strand[k]->ConvertPDBASCII ( S );
+
+  }
+
+  void  Sheet::TryStrand ( int strand_no )  {
+  int      i,k;
+  PPStrand strand1;
+    k = -1;
+    for (i=0;(i<nStrands) && (k<0);i++)
+      if (strand[i])
+        if (strand[i]->strandNo==strand_no)  k = i;
+    if (k<0)  {
+      strand1 = new PStrand[nStrands+1];
+      for (i=0;i<nStrands;i++)
+        strand1[i] = strand[i];
+      if (strand) delete[] strand;
+      strand = strand1;
+      strand[nStrands] = new Strand();
+      strand[nStrands]->strandNo = strand_no;
+      nStrands++;
+    }
+  }
+
+
+  void  Sheet::CIFFindStrands ( mmcif::PData CIF, cpstr Category ) {
+  // just look for all strands mentioned for the sheet
+  mmcif::PLoop Loop;
+  pstr         F;
+  int          RC,i,l,sNo;
+    Loop = CIF->GetLoop ( Category );
+    if (Loop)  {
+      l = Loop->GetLoopLength();
+      for (i=0;i<l;i++)  {
+        F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+        if (F && (!RC))  {
+          if (!strcmp(F,sheetID))  {
+            if (!Loop->GetInteger(sNo,CIFTAG_ID,i))
+              TryStrand ( sNo );
+            if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))
+              TryStrand ( sNo );
+            if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i))
+              TryStrand ( sNo );
+          }
+        }
+      }
+    }
+  }
+
+  int  Sheet::GetStrand ( int strand_no )  {
+  int i;
+    for (i=0;i<nStrands;i++)
+      if (strand[i])  {
+        if (strand[i]->strandNo==strand_no)
+          return i;
+      }
+    return -1;
+  }
+
+  int Sheet::GetCIF ( mmcif::PData CIF )  {
+  mmcif::PLoop Loop;
+  int         i,ns,l,k,k2,RC,sNo;
+  pstr        F;
+  ivector     pair;
+  bool     Ok;
+
+    pair = NULL;
+
+    //    First find all strands and create
+    // the corresponding classes. The CIF fields
+    // are not removed at this stage.
+
+    CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
+    CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
+    CIFFindStrands ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
+
+    //  Check number of strands
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET );
+    if (Loop)  {
+      l = Loop->GetLoopLength();
+      i = 0;
+      while (i<l)  {
+        F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+        if (F && (!RC))  {
+          if (!strcmp(F,sheetID))  {
+            RC = CIFGetInteger1 ( ns,Loop,CIFTAG_NUMBER_STRANDS,i );
+            if ((!RC) && (ns!=nStrands))
+              return  Error_WrongNumberOfStrands;
+            Loop->DeleteRow ( i );
+            i = l+100;  // break loop
+          }
+        }
+        i++;
+      }
+    }
+
+    //  Read each strand
+    RC = 0;
+    for (i=0;(i<nStrands) && (!RC);i++)
+      RC = strand[i]->GetCIF ( CIF,sheetID );
+
+    if (RC)  return RC;
+
+    if (nStrands>1)  {
+
+      GetVectorMemory ( pair,nStrands,0 );
+      for (i=0;i<nStrands;i++)
+        pair[i] = -1;
+
+      Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_ORDER );
+      if (Loop)  {
+        Ok = true;
+        l  = Loop->GetLoopLength();
+        for (i=0;(i<l) && Ok;i++)  {
+          F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+          if (F && (!RC))  {
+            if (!strcmp(F,sheetID))  {
+              if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))  {
+                k = GetStrand ( sNo );
+                if ((k>=0) &&
+                    (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_2,i)))  {
+                  pair[k] = GetStrand ( sNo );
+                  if (pair[k]>=0)  {
+                    F = Loop->GetString ( CIFTAG_SENSE,i,RC );
+                    if (F && (!RC))  {
+                      if (!strcasecmp(F,"anti-parallel"))
+                        strand[pair[k]]->sense = -1;
+                      else if (!strcasecmp(F,"parallel"))
+                        strand[pair[k]]->sense =  1;
+                    }
+                    Loop->DeleteRow ( i );
+                  } else
+                    Ok = false;
+                } else
+                  Ok = false;
+              } else
+                Ok = false;
+            }
+          }
+        }
+        if (!Ok)  {
+          FreeVectorMemory ( pair,0 );
+          return Error_WrongSheetOrder;
+        }
+      }
+
+      Loop = CIF->GetLoop ( CIFCAT_STRUCT_SHEET_HBOND );
+      if (Loop)  {
+        Ok = true;
+        l  = Loop->GetLoopLength();
+        for (i=0;(i<l) && Ok;i++)  {
+          F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+          if (F && (!RC))  {
+            if (!strcmp(F,sheetID))  {
+              if (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i))  {
+                k = GetStrand ( sNo );
+                if ((k>=0) &&
+                    (!Loop->GetInteger(sNo,CIFTAG_RANGE_ID_1,i)))  {
+                  k2 = GetStrand ( sNo );
+                  if (k2>=0)  {
+                    if (pair[k]==k2)  {
+                      CIFGetString ( strand[k2]->curAtom,Loop,
+                                CIFTAG_RANGE_1_BEG_LABEL_ATOM_ID,
+                                i,sizeof(strand[k2]->curAtom),
+                                pstr("    ") );
+                      CIFGetString ( strand[k2]->curResName,Loop,
+                                CIFTAG_NDB_RANGE_1_BEG_LABEL_COMP_ID,
+                                i,sizeof(strand[k2]->curResName),
+                                pstr("   ") );
+                      CIFGetString ( strand[k2]->curChainID,Loop,
+                                CIFTAG_NDB_RANGE_1_BEG_LABEL_ASYM_ID,
+                                i,sizeof(strand[k2]->curChainID),
+                                pstr(" ") );
+                      if (CIFGetInteger(strand[k2]->curResSeq,Loop,
+                                CIFTAG_RANGE_1_BEG_LABEL_SEQ_ID,i))  {
+                        FreeVectorMemory ( pair,0 );
+                        return i;
+                      }
+                      CIFGetString ( strand[k2]->curICode,Loop,
+                                CIFTAG_NDB_RANGE_1_BEG_LABEL_INS_CODE,
+                                i,sizeof(strand[k2]->curICode),
+                                pstr(" ") );
+                      CIFGetString ( strand[k2]->prevAtom,Loop,
+                                CIFTAG_RANGE_1_END_LABEL_ATOM_ID,
+                                i,sizeof(strand[k2]->prevAtom),
+                                pstr("    ") );
+                      CIFGetString ( strand[k2]->prevResName,Loop,
+                                CIFTAG_NDB_RANGE_1_END_LABEL_COMP_ID,
+                                i,sizeof(strand[k2]->prevResName),
+                                pstr("   ") );
+                      CIFGetString ( strand[k2]->prevChainID,Loop,
+                                CIFTAG_NDB_RANGE_1_END_LABEL_ASYM_ID,
+                                i,sizeof(strand[k2]->prevChainID),
+                                pstr(" ") );
+                      if (CIFGetInteger(strand[k2]->prevResSeq,Loop,
+                                CIFTAG_RANGE_1_END_LABEL_SEQ_ID,i))  {
+                        FreeVectorMemory ( pair,0 );
+                        return i;
+                      }
+                      CIFGetString ( strand[k2]->prevICode,Loop,
+                                CIFTAG_NDB_RANGE_1_END_LABEL_INS_CODE,
+                                i,sizeof(strand[k2]->prevICode),
+                                pstr(" ") );
+                      Loop->DeleteRow ( i );
+                    } else
+                        Ok = false;
+                  } else
+                    Ok = false;
+                } else
+                  Ok = false;
+              } else
+                Ok = false;
+            }
+          }
+        }
+        if (!Ok)  {
+          FreeVectorMemory ( pair,0 );
+          return Error_HBondInconsistency;
+        }
+      }
+    }
+
+    FreeVectorMemory ( pair,0 );
+
+    return 0;
+
+  }
+
+
+  void  Sheet::Copy ( PSheet Sheet )  {
+  int i;
+    FreeMemory();
+    nStrands = Sheet->nStrands;
+    if (nStrands>0)  {
+      strand = new PStrand[nStrands];
+      for (i=0;i<nStrands;i++)
+        if (Sheet->strand[i])  {
+          strand[i] = new Strand();
+          strand[i]->Copy ( Sheet->strand[i] );
+        } else
+          strand[i] = NULL;
+    }
+    strcpy ( sheetID,Sheet->sheetID );
+  }
+
+  void  Sheet::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte ( &Version  );
+    f.WriteInt  ( &nStrands );
+    for (i=0;i<nStrands;i++)
+      StreamWrite ( f,strand[i] );
+    f.WriteTerLine ( sheetID,false );
+  }
+
+  void  Sheet::read  ( io::RFile f ) {
+  int  i;
+  byte Version;
+    FreeMemory();
+    f.ReadByte ( &Version  );
+    f.ReadInt  ( &nStrands );
+    if (nStrands>0)  {
+      strand = new PStrand[nStrands];
+      for (i=0;i<nStrands;i++)  {
+        strand[i] = NULL;
+        StreamRead ( f,strand[i] );
+      }
+    }
+    f.ReadTerLine ( sheetID,false );
+  }
+
+  MakeStreamFunctions(Sheet)
+
+
+
+  //  ====================  Sheets  ============================
+
+
+  Sheets::Sheets() : io::Stream()  {
+    InitSheets();
+  }
+
+
+  Sheets::Sheets ( io::RPStream Object ) : io::Stream ( Object )  {
+    InitSheets();
+  }
+
+
+  Sheets::~Sheets()  {
+    FreeMemory();
+  }
+
+
+  void  Sheets::InitSheets()  {
+    nSheets = 0;
+    sheet   = NULL;
+  }
+
+
+  void  Sheets::FreeMemory()  {
+  int i;
+    if (sheet)  {
+      for (i=0;i<nSheets;i++)
+        if (sheet[i])  delete sheet[i];
+      delete[] sheet;
+      sheet = NULL;
+    }
+    nSheets = 0;
+  }
+
+
+  void  Sheets::PDBASCIIDump ( io::RFile f )  {
+  int i;
+    if (sheet)
+      for (i=0;i<nSheets;i++)
+        if (sheet[i])  sheet[i]->PDBASCIIDump ( f );
+  }
+
+
+  void  Sheets::MakeCIF ( mmcif::PData CIF )  {
+  int i;
+    if (sheet)
+      for (i=0;i<nSheets;i++)
+        if (sheet[i])  sheet[i]->MakeCIF ( CIF );
+  }
+
+
+  ERROR_CODE  Sheets::ConvertPDBASCII ( cpstr S )  {
+  PPSheet  sheet1;
+  SheetID  sheetID;
+  int      i,k;
+    strcpy_ncss ( sheetID,&(S[11]),3 );
+    //  if (!sheetID[0]) return  Error_NoSheetID;
+    k = -1;
+    for (i=0;i<nSheets;i++)
+      if (sheet[i])  {
+        if (!strcmp(sheetID,sheet[i]->sheetID))  {
+          k = i;
+          break;
+        }
+      }
+    if (k<0)  {
+      sheet1 = new PSheet[nSheets+1];
+      for (i=0;i<nSheets;i++)
+        sheet1[i] = sheet[i];
+      if (sheet) delete[] sheet;
+      sheet = sheet1;
+      sheet[nSheets] = new Sheet();
+      k = nSheets;
+      nSheets++;
+    }
+    return  sheet[k]->ConvertPDBASCII ( S );
+  }
+
+
+  void  Sheets::CIFFindSheets ( mmcif::PData CIF, cpstr Category ) {
+  mmcif::PLoop Loop;
+  int          RC,i,j,k,l;
+  pstr         F;
+  PPSheet      sheet1;
+    Loop = CIF->GetLoop ( Category );
+    if (Loop)  {
+      l = Loop->GetLoopLength();
+      for (i=0;i<l;i++)  {
+        F = Loop->GetString ( CIFTAG_SHEET_ID,i,RC );
+        if (F && (!RC))  {
+          k = -1;
+          j = 0;
+          while ((j<nSheets) && (k<0))  {
+            if (sheet[j])  {
+              if (!strcmp(F,sheet[j]->sheetID))  k = j;
+            }
+            j++;
+          }
+          if (k<0)  {
+            sheet1 = new PSheet[nSheets+1];
+            for (i=0;i<nSheets;i++)
+              sheet1[i] = sheet[i];
+            if (sheet) delete[] sheet;
+            sheet = sheet1;
+            sheet[nSheets] = new Sheet();
+            strcpy ( sheet[nSheets]->sheetID,F );
+            nSheets++;
+          }
+        }
+      }
+    }
+  }
+
+  int Sheets::GetCIF ( mmcif::PData CIF )  {
+  int i,RC;
+
+    FreeMemory();
+
+    //  First find all sheet names and create
+    // the corresponding classes. The CIF fields
+    // are not removed at this stage.
+
+    CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET       );
+    CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_ORDER );
+    CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_RANGE );
+    CIFFindSheets ( CIF,CIFCAT_STRUCT_SHEET_HBOND );
+
+    //  Read each sheet
+    i  = 0;
+    RC = 0;
+    while ((i<nSheets) && (!RC))  {
+      RC = sheet[i]->GetCIF ( CIF );
+      i++;
+    }
+
+    return RC;
+
+  }
+
+
+  void  Sheets::Copy ( PSheets Sheets )  {
+  int i;
+    FreeMemory();
+    if (Sheets->nSheets>0)  {
+      nSheets = Sheets->nSheets;
+      sheet = new PSheet[nSheets];
+      for (i=0;i<nSheets;i++)
+        if (Sheets->sheet[i]) {
+          sheet[i] = new Sheet();
+          sheet[i]->Copy ( Sheets->sheet[i] );
+        } else
+          sheet[i] = NULL;
+    }
+  }
+
+
+  void  Sheets::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    f.WriteInt  ( &nSheets );
+    for (i=0;i<nSheets;i++)
+      StreamWrite ( f,sheet[i] );
+  }
+
+
+  void  Sheets::read ( io::RFile f )  {
+  int  i;
+  byte Version;
+    FreeMemory();
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &nSheets );
+    if (nSheets>0)  {
+      sheet = new PSheet[nSheets];
+      for (i=0;i<nSheets;i++)  {
+        sheet[i] = NULL;
+        StreamRead ( f,sheet[i] );
+      }
+    }
+  }
+
+
+  MakeStreamFunctions(Sheets)
+
+
+
+  //  ================  Turn  ===================
+
+  Turn::Turn() : ContainerClass()  {
+    InitTurn();
+  }
+
+  Turn::Turn ( cpstr S ) : ContainerClass()  {
+    InitTurn();
+    ConvertPDBASCII ( S );
+  }
+
+  Turn::Turn ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitTurn();
+  }
+
+  Turn::~Turn() {
+    if (comment)  delete[] comment;
+  }
+
+  void  Turn::InitTurn()  {
+    serNum = 0;                   // serial number
+    strcpy ( turnID     ,"---" ); // turn ID
+    strcpy ( initResName,"---" ); // name of the turn's initial residue
+    strcpy ( initChainID," "   ); // chain ID for the chain
+                                  // containing the turn
+    initSeqNum = 0;               // sequence number of the initial
+                                  //    residue
+    strcpy ( initICode  ," "   ); // insertion code of the initial
+                                  //    residue
+    strcpy ( endResName ,"---" ); // name of the turn's terminal residue
+    strcpy ( endChainID ," "   ); // chain ID for the chain
+                                  // containing the turn
+    endSeqNum  = 0;               // sequence number of the terminal
+                                  //    residue
+    strcpy ( endICode   ," "   ); // insertion code of the terminal
+                                  //    residue
+    comment    = NULL;            // comment about the helix
+  }
+
+  void  Turn::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB OBSLTE line number N
+  //  from the class' data
+    strcpy     ( S,"TURN" );
+    PadSpaces  ( S,80 );
+    PutInteger ( &(S[7]) ,serNum     ,3  );
+    strcpy_n1  ( &(S[11]),turnID     ,3  );
+    strcpy_n1  ( &(S[15]),initResName,3  );
+    strcpy_n1  ( &(S[19]),initChainID,1  );
+    PutIntIns  ( &(S[20]),initSeqNum ,4,initICode );
+    strcpy_n1  ( &(S[26]),endResName ,3  );
+    strcpy_n1  ( &(S[30]),endChainID ,1  );
+    PutIntIns  ( &(S[31]),endSeqNum  ,4,endICode  );
+    if (comment)
+      strcpy_n ( &(S[40]),comment    ,30 );
+  }
+
+
+  #define  TurnTypeID  "TURN_P"
+
+  void  Turn::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop;
+  int         RC;
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_CONF,Loop );
+    if (RC!=mmcif::CIFRC_Ok)
+      // the category was (re)created, provide tags
+      AddStructConfTags ( Loop );
+    Loop->AddString  ( pstr(TurnTypeID) );
+    Loop->AddInteger ( serNum      );
+    Loop->AddString  ( turnID      );
+    Loop->AddString  ( initResName );
+    Loop->AddString  ( initChainID );
+    Loop->AddInteger ( initSeqNum  );
+    Loop->AddString  ( initICode,true );
+    Loop->AddString  ( endResName  );
+    Loop->AddString  ( endChainID  );
+    Loop->AddInteger ( endSeqNum   );
+    Loop->AddString  ( endICode ,true );
+    Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
+    Loop->AddString  ( comment     );
+    Loop->AddNoData  ( mmcif::CIF_NODATA_QUESTION );
+  }
+
+  ERROR_CODE Turn::ConvertPDBASCII ( cpstr S )  {
+  char L[100];
+    GetInteger   ( serNum     ,&(S[7]) ,3  );
+    strcpy_ncss  ( turnID     ,&(S[11]),3  );
+    strcpy_ncss  ( initResName,&(S[15]),3  );
+    strcpy_ncss  ( initChainID,&(S[19]),1  );
+    GetIntIns    ( initSeqNum,initICode,&(S[20]),4 );
+    strcpy_ncss  ( endResName ,&(S[26]),3  );
+    strcpy_ncss  ( endChainID ,&(S[30]),1  );
+    GetIntIns    ( endSeqNum ,endICode ,&(S[31]),4 );
+    strcpy_ncss  ( L          ,&(S[40]),30 );
+    CreateCopy   ( comment    ,L           );
+    return Error_NoError;
+  }
+
+  ERROR_CODE Turn::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  int          RC,l;
+  pstr         F;
+  bool         Done;
+  ERROR_CODE   rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONF );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+
+    l    = Loop->GetLoopLength();
+    Done = n>=l;
+    while (!Done) {
+      F = Loop->GetString ( CIFTAG_CONF_TYPE_ID,n,RC );
+      if ((!RC) && F)  Done = (strcmp(F,TurnTypeID)==0);
+                 else  Done = false;
+      if (!Done)  {
+        n++;
+        Done = n>=l;
+      }
+    }
+
+    if (n>=l)  {
+      n = -1;  // finish processing of Turn
+      return Error_EmptyCIF;
+    }
+
+    Loop->DeleteField ( CIFTAG_CONF_TYPE_ID,n );
+
+    rc = CIFGetInteger ( serNum,Loop,CIFTAG_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( turnID,Loop,CIFTAG_PDB_ID,n,
+                   sizeof(turnID),pstr("   ") );
+
+    CIFGetString ( initResName,Loop,CIFTAG_BEG_LABEL_COMP_ID,
+                               n,sizeof(initResName),pstr("   ") );
+    CIFGetString ( initChainID,Loop,CIFTAG_BEG_LABEL_ASYM_ID,
+                               n,sizeof(initChainID),pstr(" ") );
+    CIFGetString ( initICode  ,Loop,CIFTAG_NDB_BEG_LABEL_INS_CODE_PDB,
+                               n,sizeof(initICode),pstr(" ") );
+    rc = CIFGetInteger ( initSeqNum,Loop,CIFTAG_BEG_LABEL_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( endResName,Loop,CIFTAG_END_LABEL_COMP_ID,
+                              n,sizeof(endResName),pstr("   ") );
+    CIFGetString ( endChainID,Loop,CIFTAG_END_LABEL_ASYM_ID,
+                              n,sizeof(endChainID),pstr(" ") );
+    CIFGetString ( endICode  ,Loop,CIFTAG_NDB_END_LABEL_INS_CODE_PDB,
+                              n,sizeof(endICode),pstr(" ") );
+    rc = CIFGetInteger ( endSeqNum,Loop,CIFTAG_END_LABEL_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CreateCopy      ( comment,Loop->GetString(CIFTAG_DETAILS,n,RC));
+    Loop->DeleteField ( CIFTAG_DETAILS,n );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  Turn::Copy ( PContainerClass Turn )  {
+    serNum     = PTurn(Turn)->serNum;
+    initSeqNum = PTurn(Turn)->initSeqNum;
+    endSeqNum  = PTurn(Turn)->endSeqNum;
+    strcpy ( turnID     ,PTurn(Turn)->turnID      );
+    strcpy ( initResName,PTurn(Turn)->initResName );
+    strcpy ( initChainID,PTurn(Turn)->initChainID );
+    strcpy ( initICode  ,PTurn(Turn)->initICode   );
+    strcpy ( endResName ,PTurn(Turn)->endResName  );
+    strcpy ( endChainID ,PTurn(Turn)->endChainID  );
+    strcpy ( endICode   ,PTurn(Turn)->endICode    );
+    CreateCopy ( comment,PTurn(Turn)->comment );
+  }
+
+  void  Turn::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version    );
+    f.WriteInt  ( &serNum     );
+    f.WriteInt  ( &initSeqNum );
+    f.WriteInt  ( &endSeqNum  );
+    f.WriteTerLine ( turnID     ,false );
+    f.WriteTerLine ( initResName,false );
+    f.WriteTerLine ( initChainID,false );
+    f.WriteTerLine ( initICode  ,false );
+    f.WriteTerLine ( endResName ,false );
+    f.WriteTerLine ( endChainID ,false );
+    f.WriteTerLine ( endICode   ,false );
+    f.CreateWrite ( comment );
+  }
+
+  void  Turn::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &serNum     );
+    f.ReadInt  ( &initSeqNum );
+    f.ReadInt  ( &endSeqNum  );
+    f.ReadTerLine ( turnID     ,false );
+    f.ReadTerLine ( initResName,false );
+    f.ReadTerLine ( initChainID,false );
+    f.ReadTerLine ( initICode  ,false );
+    f.ReadTerLine ( endResName ,false );
+    f.ReadTerLine ( endChainID ,false );
+    f.ReadTerLine ( endICode   ,false );
+    f.CreateRead ( comment );
+  }
+
+  MakeStreamFunctions(Turn)
+
+
+  //  ===================  LinkContainer  ========================
+
+  PContainerClass LinkContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template : return
+                          ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_Link    : return new Link();
+    }
+  }
+
+  MakeStreamFunctions(LinkContainer)
+
+
+
+  //  ========================  Link  ===========================
+
+  Link::Link() : ContainerClass()  {
+    InitLink();
+  }
+
+  Link::Link ( cpstr S ) : ContainerClass()  {
+    InitLink();
+    ConvertPDBASCII ( S );
+  }
+
+  Link::Link ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitLink();
+  }
+
+  Link::~Link() {}
+
+  void  Link::InitLink()  {
+    strcpy ( atName1 ,"----" );  // name of 1st linked atom
+    strcpy ( aloc1   ," "    );  // alternative location of 1st atom
+    strcpy ( resName1,"---"  );  // residue name of 1st linked atom
+    strcpy ( chainID1," "    );  // chain ID of 1st linked atom
+    seqNum1 = 0;                 // sequence number of 1st linked atom
+    strcpy ( insCode1," "    );  // insertion code of 1st linked atom
+    strcpy ( atName2 ,"----" );  // name of 2nd linked atom
+    strcpy ( aloc2   ," "    );  // alternative location of 2nd atom
+    strcpy ( resName2,"---"  );  // residue name of 2nd linked atom
+    strcpy ( chainID2," "    );  // chain ID of 2nd linked atom
+    seqNum2 = 0;                 // sequence number of 2nd linked atom
+    strcpy ( insCode2," "    );  // insertion code of 2nd linked atom
+    s1 = 1;  // sym id of 1st atom
+    i1 = 5;
+    j1 = 5;
+    k1 = 5;
+    s2 = 1;  // sym id of 2nd atom
+    i2 = 5;
+    j2 = 5;
+    k2 = 5;
+  }
+
+
+  void  Link::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB OBSLTE line number N
+  //  from the class' data
+
+    strcpy     ( S,"LINK" );
+    PadSpaces  ( S,80 );
+
+    strcpy_n1  ( &(S[12]),atName1 ,4 );
+    strcpy_n1  ( &(S[16]),aloc1   ,1 );
+    strcpy_n1  ( &(S[17]),resName1,3 );
+    strcpy_n1  ( &(S[21]),chainID1,1 );
+    PutIntIns  ( &(S[22]),seqNum1 ,4,insCode1 );
+
+    strcpy_n1  ( &(S[42]),atName2 ,4 );
+    strcpy_n1  ( &(S[46]),aloc2   ,1 );
+    strcpy_n1  ( &(S[47]),resName2,3 );
+    strcpy_n1  ( &(S[51]),chainID2,1 );
+    PutIntIns  ( &(S[52]),seqNum2 ,4,insCode2 );
+
+    PutInteger ( &(S[59]),s1,3 );
+    PutInteger ( &(S[62]),i1,1 );
+    PutInteger ( &(S[63]),j1,1 );
+    PutInteger ( &(S[64]),k1,1 );
+
+    PutInteger ( &(S[66]),s2,3 );
+    PutInteger ( &(S[69]),i2,1 );
+    PutInteger ( &(S[70]),j2,1 );
+    PutInteger ( &(S[71]),k2,1 );
+
+  }
+
+
+  #define  LinkTypeID  "LINK"
+
+  void AddStructConnTags ( mmcif::PLoop Loop )  {
+
+    Loop->AddLoopTag ( CIFTAG_ID                           );
+    Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID                 );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID  );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID       );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID  );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID       );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_SYMMETRY );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_SYMMETRY );
+
+  }
+
+
+  void  Link::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop;
+  char        S[100];
+  int         RC;
+
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_CONN,Loop );
+    if (RC!=mmcif::CIFRC_Ok) // the category was (re)created, provide tags
+      AddStructConnTags ( Loop );
+
+    Loop->AddString  ( "1"      );  // should be a counter
+    Loop->AddString  ( pstr(LinkTypeID) );
+
+    Loop->AddString  ( atName1  );
+    Loop->AddString  ( aloc1    );
+    Loop->AddString  ( resName1 );
+    Loop->AddString  ( chainID1 );
+    Loop->AddInteger ( seqNum1  );
+    Loop->AddString  ( insCode1 );
+
+    Loop->AddString  ( atName2  );
+    Loop->AddString  ( aloc2    );
+    Loop->AddString  ( resName2 );
+    Loop->AddString  ( chainID2 );
+    Loop->AddInteger ( seqNum2  );
+    Loop->AddString  ( insCode2 );
+
+    sprintf ( S,"%i%i%i%i",s1,i1,j1,k1 );
+    Loop->AddString  ( S );
+    sprintf ( S,"%i%i%i%i",s2,i2,j2,k2 );
+    Loop->AddString  ( S );
+
+  }
+
+  ERROR_CODE Link::ConvertPDBASCII ( cpstr S )  {
+
+    GetString    ( atName1 ,&(S[12]),4 );
+    strcpy_ncss  ( aloc1   ,&(S[16]),1 );
+    strcpy_ncss  ( resName1,&(S[17]),3 );
+    strcpy_ncss  ( chainID1,&(S[21]),1 );
+    GetIntIns    ( seqNum1,insCode1,&(S[22]),4 );
+
+    GetString    ( atName2 ,&(S[42]),4 );
+    strcpy_ncss  ( aloc2   ,&(S[46]),1 );
+    strcpy_ncss  ( resName2,&(S[47]),3 );
+    strcpy_ncss  ( chainID2,&(S[51]),1 );
+    GetIntIns    ( seqNum2,insCode2,&(S[52]),4 );
+
+    GetInteger   ( s1,&(S[59]),3 );
+    GetInteger   ( i1,&(S[62]),1 );
+    GetInteger   ( j1,&(S[63]),1 );
+    GetInteger   ( k1,&(S[64]),1 );
+
+    GetInteger   ( s2,&(S[66]),3 );
+    GetInteger   ( i2,&(S[69]),1 );
+    GetInteger   ( j2,&(S[70]),1 );
+    GetInteger   ( k2,&(S[71]),1 );
+
+    return Error_NoError;
+
+  }
+
+  ERROR_CODE Link::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  pstr         F;
+  char         S[100];
+  int          RC,l;
+  bool         Done;
+  ERROR_CODE   rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+
+    l    = Loop->GetLoopLength();
+    Done = (n>=l);
+    while (!Done) {
+      F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
+      if ((!RC) && F)  Done = (strcmp(F,LinkTypeID)==0);
+                 else  Done = false;
+      if (!Done)  {
+        n++;
+        Done = (n>=l);
+      }
+    }
+
+    if (n>=l)  {
+      n = -1;  // finish processing of Turn
+      return Error_EmptyCIF;
+    }
+
+    Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
+
+  //  CIFGetInteger ( l,Loop,CIFTAG_ID,n );
+
+    CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,n,
+                   sizeof(atName1),pstr("    ") );
+    CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,n,
+                   sizeof(aloc1),pstr(" ") );
+    CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,n,
+                   sizeof(resName1),pstr("   ") );
+    CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,n,
+                   sizeof(chainID1),pstr(" ") );
+    rc = CIFGetInteger ( seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
+                   n,sizeof(insCode1),pstr(" ") );
+
+    CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,n,
+                   sizeof(atName2),pstr("    ") );
+    CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,n,
+                   sizeof(aloc2),pstr(" ") );
+    CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,n,
+                   sizeof(resName2),pstr("   ") );
+    CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,n,
+                   sizeof(chainID2),pstr(" ") );
+    rc = CIFGetInteger ( seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
+                   n,sizeof(insCode2),pstr(" ") );
+
+    CIFGetString ( S,Loop,CIFTAG_CONN_PTNR1_SYMMETRY,n,
+                   sizeof(S),pstr("") );
+    if (S[0])  {
+      l  = strlen(S)-1;
+      k1 = int(S[l--]) - int('0');
+      j1 = int(S[l--]) - int('0');
+      i1 = int(S[l--]) - int('0');
+      S[l] = char(0);
+      s1 = atoi(S);
+    }
+
+    CIFGetString ( S,Loop,CIFTAG_CONN_PTNR2_SYMMETRY,n,
+                   sizeof(S),pstr("") );
+    if (S[0])  {
+      l  = strlen(S)-1;
+      k2 = int(S[l--]) - int('0');
+      j2 = int(S[l--]) - int('0');
+      i2 = int(S[l--]) - int('0');
+      S[l] = char(0);
+      s2 = atoi(S);
+    }
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  Link::Copy ( PContainerClass Link )  {
+
+    strcpy ( atName1 ,PLink(Link)->atName1  );
+    strcpy ( aloc1   ,PLink(Link)->aloc1    );
+    strcpy ( resName1,PLink(Link)->resName1 );
+    strcpy ( chainID1,PLink(Link)->chainID1 );
+    seqNum1 = PLink(Link)->seqNum1;
+    strcpy ( insCode1,PLink(Link)->insCode1 );
+
+    strcpy ( atName2 ,PLink(Link)->atName2  );
+    strcpy ( aloc2   ,PLink(Link)->aloc2    );
+    strcpy ( resName2,PLink(Link)->resName2 );
+    strcpy ( chainID2,PLink(Link)->chainID2 );
+    seqNum2 = PLink(Link)->seqNum2;
+    strcpy ( insCode2,PLink(Link)->insCode2 );
+
+    s1 = PLink(Link)->s1;
+    i1 = PLink(Link)->i1;
+    j1 = PLink(Link)->j1;
+    k1 = PLink(Link)->k1;
+
+    s2 = PLink(Link)->s2;
+    i2 = PLink(Link)->i2;
+    j2 = PLink(Link)->j2;
+    k2 = PLink(Link)->k2;
+
+  }
+
+  void  Link::write ( io::RFile f )  {
+  byte Version=1;
+
+    f.WriteByte ( &Version    );
+
+    f.WriteTerLine ( atName1 ,false );
+    f.WriteTerLine ( aloc1   ,false );
+    f.WriteTerLine ( resName1,false );
+    f.WriteTerLine ( chainID1,false );
+    f.WriteInt     ( &seqNum1 );
+    f.WriteTerLine ( insCode1,false );
+
+    f.WriteTerLine ( atName2 ,false );
+    f.WriteTerLine ( aloc2   ,false );
+    f.WriteTerLine ( resName2,false );
+    f.WriteTerLine ( chainID2,false );
+    f.WriteInt     ( &seqNum2 );
+    f.WriteTerLine ( insCode2,false );
+
+    f.WriteInt ( &s1 );
+    f.WriteInt ( &i1 );
+    f.WriteInt ( &j1 );
+    f.WriteInt ( &k1 );
+
+    f.WriteInt ( &s2 );
+    f.WriteInt ( &i2 );
+    f.WriteInt ( &j2 );
+    f.WriteInt ( &k2 );
+
+  }
+
+  void  Link::read ( io::RFile f )  {
+  byte Version;
+
+    f.ReadByte ( &Version    );
+
+    f.ReadTerLine ( atName1 ,false );
+    f.ReadTerLine ( aloc1   ,false );
+    f.ReadTerLine ( resName1,false );
+    f.ReadTerLine ( chainID1,false );
+    f.ReadInt     ( &seqNum1 );
+    f.ReadTerLine ( insCode1,false );
+
+    f.ReadTerLine ( atName2 ,false );
+    f.ReadTerLine ( aloc2   ,false );
+    f.ReadTerLine ( resName2,false );
+    f.ReadTerLine ( chainID2,false );
+    f.ReadInt     ( &seqNum2 );
+    f.ReadTerLine ( insCode2,false );
+
+    f.ReadInt ( &s1 );
+    f.ReadInt ( &i1 );
+    f.ReadInt ( &j1 );
+    f.ReadInt ( &k1 );
+
+    f.ReadInt ( &s2 );
+    f.ReadInt ( &i2 );
+    f.ReadInt ( &j2 );
+    f.ReadInt ( &k2 );
+
+  }
+
+  MakeStreamFunctions(Link)
+
+
+  //  ===================  LinkRContainer  =======================
+
+  PContainerClass LinkRContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template : return
+                           ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_LinkR    : return new LinkR();
+    }
+  }
+
+  MakeStreamFunctions(LinkRContainer)
+
+
+  //  ========================  LinkR  ===========================
+
+  LinkR::LinkR() : ContainerClass()  {
+    InitLinkR();
+  }
+
+  LinkR::LinkR ( cpstr S ) : ContainerClass()  {
+    InitLinkR();
+    ConvertPDBASCII ( S );
+  }
+
+  LinkR::LinkR ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitLinkR();
+  }
+
+  LinkR::~LinkR() {}
+
+  void  LinkR::InitLinkR()  {
+    strcpy ( linkRID ,"----" );  // link name
+    strcpy ( atName1 ,"----" );  // name of 1st linked atom
+    strcpy ( aloc1   ," "    );  // alternative location of 1st atom
+    strcpy ( resName1,"---"  );  // residue name of 1st linked atom
+    strcpy ( chainID1," "    );  // chain ID of 1st linked atom
+    seqNum1 = 0;                 // sequence number of 1st linked atom
+    strcpy ( insCode1," "    );  // insertion code of 1st linked atom
+    strcpy ( atName2 ,"----" );  // name of 2nd linked atom
+    strcpy ( aloc2   ," "    );  // alternative location of 2nd atom
+    strcpy ( resName2,"---"  );  // residue name of 2nd linked atom
+    strcpy ( chainID2," "    );  // chain ID of 2nd linked atom
+    seqNum2 = 0;                 // sequence number of 2nd linked atom
+    strcpy ( insCode2," "    );  // insertion code of 2nd linked atom
+    dist    = 0.0;               // link distance
+  }
+
+  /*
+  LINK             LYS A  27                     PLP A 255                PLPLYS
+  LINK             MAN S   3                     MAN S   4                BETA1-4
+  LINK        C6  BBEN B   1                O1  BMAF S   2                BEN-MAF
+  LINK        OE2 AGLU A 320                C1  AMAF S   2                GLU-MAF
+  LINK        OE2  GLU A  67        1.895   ZN   ZN  R   5                GLU-ZN
+  LINK        NE2  HIS A  71        2.055   ZN   ZN  R   5                HIS-ZN
+  LINK        O    ARG A  69        2.240   NA   NA  R   9                ARG-NA
+  012345678901234567890123456789012345678901234567890123456789012345678901234567890
+            1         2         3         4         5         6         7
+  */
+
+  void  LinkR::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+  //  makes the ASCII PDB OBSLTE line number N
+  //  from the class' data
+
+    strcpy     ( S,"LINKR" );
+    PadSpaces  ( S,80 );
+
+    strcpy_n1  ( &(S[12]),atName1 ,4 );
+    strcpy_n1  ( &(S[16]),aloc1   ,1 );
+    strcpy_n1  ( &(S[17]),resName1,3 );
+    strcpy_n1  ( &(S[21]),chainID1,1 );
+    PutIntIns  ( &(S[22]),seqNum1 ,4,insCode1 );
+
+    if (dist>0.0)
+      PutRealF ( &(S[32]),dist,7,3 );
+
+    strcpy_n1  ( &(S[42]),atName2 ,4 );
+    strcpy_n1  ( &(S[46]),aloc2   ,1 );
+    strcpy_n1  ( &(S[47]),resName2,3 );
+    strcpy_n1  ( &(S[51]),chainID2,1 );
+    PutIntIns  ( &(S[52]),seqNum2 ,4,insCode2 );
+
+    strcpy_ns  ( &(S[72]),linkRID,8 );
+
+  }
+
+
+  #define  LinkRTypeID  "LINKR"
+
+  void AddStructConnLinkRTags ( mmcif::PLoop Loop )  {
+
+    Loop->AddLoopTag ( CIFTAG_ID                           );
+    Loop->AddLoopTag ( CIFTAG_CONN_TYPE_ID                 );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ATOM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID  );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_COMP_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_ASYM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR1_AUTH_SEQ_ID       );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_DIST );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ATOM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID  );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_COMP_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_ASYM_ID      );
+    Loop->AddLoopTag ( CIFTAG_CONN_PTNR2_AUTH_SEQ_ID       );
+    Loop->AddLoopTag ( CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE );
+
+    Loop->AddLoopTag ( CIFTAG_CONN_NAME );
+
+  }
+
+  void  LinkR::MakeCIF ( mmcif::PData CIF, int N )  {
+  UNUSED_ARGUMENT(N);
+  mmcif::PLoop Loop;
+  int         RC;
+
+    RC = CIF->AddLoop ( CIFCAT_STRUCT_LINKR,Loop );
+    if (RC!=mmcif::CIFRC_Ok) // the category was (re)created, provide tags
+      AddStructConnLinkRTags ( Loop );
+
+    Loop->AddString  ( "1"      );  // should be a counter
+    Loop->AddString  ( pstr(LinkTypeID) );
+
+    Loop->AddString  ( atName1  );
+    Loop->AddString  ( aloc1    );
+    Loop->AddString  ( resName1 );
+    Loop->AddString  ( chainID1 );
+    Loop->AddInteger ( seqNum1  );
+    Loop->AddString  ( insCode1 );
+
+    Loop->AddReal    ( dist     );
+
+    Loop->AddString  ( atName2  );
+    Loop->AddString  ( aloc2    );
+    Loop->AddString  ( resName2 );
+    Loop->AddString  ( chainID2 );
+    Loop->AddInteger ( seqNum2  );
+    Loop->AddString  ( insCode2 );
+
+    Loop->AddString  ( linkRID  );
+
+  }
+
+  ERROR_CODE LinkR::ConvertPDBASCII ( cpstr S )  {
+
+    GetString    ( atName1 ,&(S[12]),4 );
+    strcpy_ncss  ( aloc1   ,&(S[16]),1 );
+    strcpy_ncss  ( resName1,&(S[17]),3 );
+    strcpy_ncss  ( chainID1,&(S[21]),1 );
+    GetIntIns    ( seqNum1,insCode1,&(S[22]),4 );
+
+    if (!GetReal(dist,&(S[32]),7)) dist = 0.0;
+
+    GetString    ( atName2 ,&(S[42]),4 );
+    strcpy_ncss  ( aloc2   ,&(S[46]),1 );
+    strcpy_ncss  ( resName2,&(S[47]),3 );
+    strcpy_ncss  ( chainID2,&(S[51]),1 );
+    GetIntIns    ( seqNum2,insCode2,&(S[52]),4 );
+
+    strcpy_ncss  ( linkRID,&(S[72]),8 );
+
+    return Error_NoError ;
+
+  }
+
+  ERROR_CODE LinkR::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  pstr         F;
+  int          RC,l;
+  bool         Done;
+  ERROR_CODE   rc;
+
+    Loop = CIF->GetLoop ( CIFCAT_STRUCT_CONN );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+
+    l    = Loop->GetLoopLength();
+    Done = (n>=l);
+    while (!Done) {
+      F = Loop->GetString ( CIFTAG_CONN_TYPE_ID,n,RC );
+      if ((!RC) && F)  Done = (strcmp(F,LinkTypeID)==0);
+                 else  Done = false;
+      if (!Done)  {
+        n++;
+        Done = (n>=l);
+      }
+    }
+
+    if (n>=l)  {
+      n = -1;  // finish processing of Turn
+      return Error_EmptyCIF;
+    }
+
+    Loop->DeleteField ( CIFTAG_CONN_TYPE_ID,n );
+
+    //  CIFGetInteger ( l,Loop,CIFTAG_ID,n );
+
+    CIFGetString ( atName1,Loop,CIFTAG_CONN_PTNR1_AUTH_ATOM_ID,n,
+                   sizeof(atName1),pstr("    ") );
+    CIFGetString ( aloc1,Loop,CIFTAG_CONN_PDBX_PTNR1_AUTH_ALT_ID,n,
+                   sizeof(aloc1),pstr(" ") );
+    CIFGetString ( resName1,Loop,CIFTAG_CONN_PTNR1_AUTH_COMP_ID,n,
+                   sizeof(resName1),pstr("   ") );
+    CIFGetString ( chainID1,Loop,CIFTAG_CONN_PTNR1_AUTH_ASYM_ID,n,
+                   sizeof(chainID1),pstr(" ") );
+    rc = CIFGetInteger ( seqNum1,Loop,CIFTAG_CONN_PTNR1_AUTH_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( insCode1,Loop,CIFTAG_CONN_PDBX_PTNR1_PDB_INS_CODE,
+                   n,sizeof(insCode1),pstr(" ") );
+
+    rc = CIFGetReal ( dist,Loop,CIFTAG_CONN_DIST,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( atName2,Loop,CIFTAG_CONN_PTNR2_AUTH_ATOM_ID,n,
+                   sizeof(atName2),pstr("    ") );
+    CIFGetString ( aloc2,Loop,CIFTAG_CONN_PDBX_PTNR2_AUTH_ALT_ID,n,
+                   sizeof(aloc2),pstr(" ") );
+    CIFGetString ( resName2,Loop,CIFTAG_CONN_PTNR2_AUTH_COMP_ID,n,
+                   sizeof(resName2),pstr("   ") );
+    CIFGetString ( chainID2,Loop,CIFTAG_CONN_PTNR2_AUTH_ASYM_ID,n,
+                   sizeof(chainID2),pstr(" ") );
+    rc = CIFGetInteger ( seqNum2,Loop,CIFTAG_CONN_PTNR2_AUTH_SEQ_ID,n );
+    if (rc==Error_NoData)   return Error_EmptyCIF;
+    if (rc!=Error_NoError)  return rc;
+
+    CIFGetString ( insCode2,Loop,CIFTAG_CONN_PDBX_PTNR2_PDB_INS_CODE,
+                   n,sizeof(insCode2),pstr(" ") );
+
+    CIFGetString ( linkRID,Loop,CIFTAG_CONN_NAME,n,
+                   sizeof(linkRID),pstr(" ") );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  LinkR::Copy ( PContainerClass LinkR )  {
+
+    strcpy ( atName1 ,PLinkR(LinkR)->atName1  );
+    strcpy ( aloc1   ,PLinkR(LinkR)->aloc1    );
+    strcpy ( resName1,PLinkR(LinkR)->resName1 );
+    strcpy ( chainID1,PLinkR(LinkR)->chainID1 );
+    seqNum1 = PLinkR(LinkR)->seqNum1;
+    strcpy ( insCode1,PLinkR(LinkR)->insCode1 );
+
+    dist = PLinkR(LinkR)->dist;
+
+    strcpy ( atName2 ,PLinkR(LinkR)->atName2  );
+    strcpy ( aloc2   ,PLinkR(LinkR)->aloc2    );
+    strcpy ( resName2,PLinkR(LinkR)->resName2 );
+    strcpy ( chainID2,PLinkR(LinkR)->chainID2 );
+    seqNum2 = PLinkR(LinkR)->seqNum2;
+    strcpy ( insCode2,PLinkR(LinkR)->insCode2 );
+
+    strcpy ( linkRID,PLinkR(LinkR)->linkRID );
+
+  }
+
+  void  LinkR::write ( io::RFile f )  {
+  byte Version=1;
+
+    f.WriteByte ( &Version    );
+
+    f.WriteTerLine ( atName1 ,false );
+    f.WriteTerLine ( aloc1   ,false );
+    f.WriteTerLine ( resName1,false );
+    f.WriteTerLine ( chainID1,false );
+    f.WriteInt     ( &seqNum1 );
+    f.WriteTerLine ( insCode1,false );
+
+    f.WriteReal    ( &dist );
+
+    f.WriteTerLine ( atName2 ,false );
+    f.WriteTerLine ( aloc2   ,false );
+    f.WriteTerLine ( resName2,false );
+    f.WriteTerLine ( chainID2,false );
+    f.WriteInt     ( &seqNum2 );
+    f.WriteTerLine ( insCode2,false );
+
+    f.WriteTerLine ( linkRID,false );
+
+  }
+
+  void  LinkR::read ( io::RFile f )  {
+  byte Version;
+
+    f.ReadByte ( &Version    );
+
+    f.ReadTerLine ( atName1 ,false );
+    f.ReadTerLine ( aloc1   ,false );
+    f.ReadTerLine ( resName1,false );
+    f.ReadTerLine ( chainID1,false );
+    f.ReadInt     ( &seqNum1 );
+    f.ReadTerLine ( insCode1,false );
+
+    f.ReadReal    ( &dist );
+
+    f.ReadTerLine ( atName2 ,false );
+    f.ReadTerLine ( aloc2   ,false );
+    f.ReadTerLine ( resName2,false );
+    f.ReadTerLine ( chainID2,false );
+    f.ReadInt     ( &seqNum2 );
+    f.ReadTerLine ( insCode2,false );
+
+    f.ReadTerLine ( linkRID,false );
+
+  }
+
+  MakeStreamFunctions(LinkR)
+
+
+  //  ===================  CisPepContainer  ======================
+
+  PContainerClass CisPepContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template : return
+                          ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_CisPep   : return new CisPep();
+    }
+  }
+
+  MakeStreamFunctions(CisPepContainer)
+
+
+  //  ========================  CisPep  ==========================
+
+  CisPep::CisPep() : ContainerClass()  {
+    InitCisPep();
+  }
+
+  CisPep::CisPep ( cpstr S ) : ContainerClass()  {
+    InitCisPep();
+    ConvertPDBASCII ( S );
+  }
+
+  CisPep::CisPep ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitCisPep();
+  }
+
+  CisPep::~CisPep() {}
+
+  void CisPep::InitCisPep()  {
+    serNum  = 1;                //  record serial number
+    strcpy ( pep1    ,"---" );  //  residue name
+    strcpy ( chainID1," "   );  //  chain identifier 1
+    seqNum1 = 0;                //  residue sequence number 1
+    strcpy ( icode1  ," "   );  //  insertion code 1
+    strcpy ( pep2    ,"---" );  //  residue name 2
+    strcpy ( chainID2," "   );  //  chain identifier 2
+    seqNum2 = 0;                //  residue sequence number 2
+    strcpy ( icode2  ," "   );  //  insertion code 2
+    modNum  = 0;                //  model number
+    measure = 0.0;              //  measure of the angle in degrees.
+  }
+
+  void  CisPep::PDBASCIIDump ( pstr S, int N )  {
+  UNUSED_ARGUMENT(N);
+
+    strcpy     ( S,"CISPEP" );
+    PadSpaces  ( S,80 );
+
+    PutInteger ( &(S[7]),serNum,3 );
+
+    strcpy_n1  ( &(S[11]),pep1    ,3 );
+    strcpy_n1  ( &(S[15]),chainID1,1 );
+    PutIntIns  ( &(S[17]),seqNum1 ,4,icode1 );
+
+    strcpy_n1  ( &(S[25]),pep2    ,3 );
+    strcpy_n1  ( &(S[29]),chainID2,1 );
+    PutIntIns  ( &(S[31]),seqNum2 ,4,icode1 );
+
+    PutInteger ( &(S[43]),modNum,3 );
+    PutRealF   ( &(S[53]),measure,6,2 );
+
+  }
+
+
+  ERROR_CODE CisPep::ConvertPDBASCII ( cpstr S )  {
+
+    GetInteger   ( serNum  ,&(S[7]) ,3 );
+
+    strcpy_ncss  ( pep1    ,&(S[11]),3 );
+    strcpy_ncss  ( chainID1,&(S[15]),1 );
+    GetIntIns    ( seqNum1,icode1,&(S[17]),4 );
+
+    strcpy_ncss  ( pep2    ,&(S[25]),3 );
+    strcpy_ncss  ( chainID2,&(S[29]),1 );
+    GetIntIns    ( seqNum2,icode2,&(S[31]),4 );
+
+    GetInteger   ( modNum  ,&(S[43]),3 );
+    GetReal      ( measure ,&(S[53]),6 );
+
+    return Error_NoError;
+
+  }
+
+
+  void  CisPep::Copy ( PContainerClass CisPep )  {
+
+    serNum  = PCisPep(CisPep)->serNum;
+
+    strcpy ( pep1    ,PCisPep(CisPep)->pep1     );
+    strcpy ( chainID1,PCisPep(CisPep)->chainID1 );
+    seqNum1 = PCisPep(CisPep)->seqNum1;
+    strcpy ( icode1  ,PCisPep(CisPep)->icode1   );
+
+    strcpy ( pep2    ,PCisPep(CisPep)->pep2     );
+    strcpy ( chainID2,PCisPep(CisPep)->chainID2 );
+    seqNum2 = PCisPep(CisPep)->seqNum2;
+    strcpy ( icode2  ,PCisPep(CisPep)->icode2   );
+
+    modNum  = PCisPep(CisPep)->modNum;
+    measure = PCisPep(CisPep)->measure;
+
+  }
+
+  void  CisPep::write ( io::RFile f )  {
+  byte Version=1;
+
+    f.WriteByte    ( &Version   );
+
+    f.WriteInt     ( &serNum );
+
+    f.WriteTerLine ( pep1    ,false );
+    f.WriteTerLine ( chainID1,false );
+    f.WriteInt     ( &seqNum1 );
+    f.WriteTerLine ( icode1  ,false );
+
+    f.WriteTerLine ( pep2    ,false );
+    f.WriteTerLine ( chainID2,false );
+    f.WriteInt     ( &seqNum2 );
+    f.WriteTerLine ( icode2  ,false );
+
+    f.WriteInt     ( &modNum  );
+    f.WriteReal    ( &measure );
+
+  }
+
+  void  CisPep::read ( io::RFile f )  {
+  byte Version;
+
+    f.ReadByte    ( &Version   );
+
+    f.ReadInt     ( &serNum );
+
+    f.ReadTerLine ( pep1    ,false );
+    f.ReadTerLine ( chainID1,false );
+    f.ReadInt     ( &seqNum1 );
+    f.ReadTerLine ( icode1  ,false );
+
+    f.ReadTerLine ( pep2    ,false );
+    f.ReadTerLine ( chainID2,false );
+    f.ReadInt     ( &seqNum2 );
+    f.ReadTerLine ( icode2  ,false );
+
+    f.ReadInt     ( &modNum  );
+    f.ReadReal    ( &measure );
+
+  }
+
+  MakeStreamFunctions(CisPep)
+
+
+
+  //  =====================   Model   =======================
+
+  Model::Model() : ProModel() {
+    InitModel();
+  }
+
+  Model::Model ( PManager MMDBM, int serialNum ) : ProModel() {
+    InitModel();
+    manager = MMDBM;
+    serNum  = serialNum;
+  }
+
+  Model::Model ( io::RPStream Object ) : ProModel(Object)  {
+    InitModel();
+  }
+
+  void  Model::InitModel()  {
+    serNum       = 0;
+    nChains      = 0;
+    nChainsAlloc = 0;
+    chain        = NULL;
+    manager      = NULL;
+    Exclude      = true;
+  }
+
+  Model::~Model()  {
+    FreeMemory();
+    if (manager)  manager->_ExcludeModel ( serNum );
+  }
+
+  void Model::FreeMemory()  {
+
+    DeleteAllChains();
+    if (chain)  delete[] chain;
+    chain        = NULL;
+    nChains      = 0;
+    nChainsAlloc = 0;
+
+    RemoveSecStructure();
+    RemoveHetInfo     ();
+    RemoveLinks       ();
+    RemoveLinkRs      ();
+    RemoveCisPeps     ();
+
+  }
+
+
+  void  Model::SetMMDBManager ( PManager MMDBM, int serialNum )  {
+    manager = MMDBM;
+    serNum  = serialNum;
+  }
+
+  void  Model::CheckInAtoms()  {
+  int i;
+    if (manager)
+      for (i=0;i<nChains;i++)
+        if (chain[i])
+          chain[i]->CheckInAtoms();
+  }
+
+
+  int  Model::GetNumberOfAtoms ( bool countTers )  {
+  // returns number of atoms in the model
+  int i,na;
+    na = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  na += chain[i]->GetNumberOfAtoms ( countTers );
+    return na;
+  }
+
+  int  Model::GetNumberOfResidues()  {
+  // returns number of residues in the model
+  PChain   chn;
+  int      ic,ir,nr;
+    nr = 0;
+    for (ic=0;ic<nChains;ic++)  {
+      chn = chain[ic];
+      if (chn)
+        for (ir=0;ir<chn->nResidues;ir++)
+          if (chn->residue[ir])  nr++;
+    }
+    return nr;
+  }
+
+
+  //  ----------------  Extracting chains  --------------------------
+
+  int  Model::GetNumberOfChains()  {
+    return nChains;
+  }
+
+  PChain Model::GetChain ( int chainNo )  {
+    if ((0<=chainNo) && (chainNo<nChains))
+          return chain[chainNo];
+    else  return NULL;
+  }
+
+
+  void Model::ExpandChainArray ( int nOfChains )  {
+  PPChain chain1;
+  int     i;
+    if (nOfChains>=nChainsAlloc)  {
+      nChainsAlloc = nOfChains+10;
+      chain1 = new PChain[nChainsAlloc];
+      for (i=0;i<nChains;i++)
+        chain1[i] = chain[i];
+      for (i=nChains;i<nChainsAlloc;i++)
+        chain1[i] = NULL;
+      if (chain)  delete[] chain;
+      chain = chain1;
+    }
+  }
+
+  PChain Model::GetChainCreate ( const ChainID chID,
+                                 bool enforceUniqueChainID )  {
+  //   Returns pointer on chain, whose identifier is
+  // given in chID. If such a chain is absent in the
+  // model, it is created.
+  PChain  chn;
+  ChainID chainID;
+  int     i,k;
+
+    // check if such a chain is already in the model
+    chn = NULL;
+    if (enforceUniqueChainID)  {
+      k = 0;
+      for (i=0;i<nChains;i++)
+        if (chain[i])  {
+          // here we check only first letter as it is kept in all
+          // derived names
+          if (chID[0]==chain[i]->chainID[0])  {
+            chn = chain[i];
+            if (chn->GetNumberOfResidues()>0)  k++;
+          }
+        }
+      if (k)          sprintf ( chainID,"%s%i",chID,k-1 );
+      else if (!chn)  strcpy  ( chainID,chID ); // chain is absent
+                else  return chn;  // the only empty chain
+    } else  {
+      if (chID[0])  {
+        for (i=0;(i<nChains) && (!chn);i++)
+          if (chain[i])  {
+            if (!strcmp(chID,chain[i]->chainID))
+              chn = chain[i]; // it is there; just return the pointer
+          }
+      } else  {
+        for (i=0;(i<nChains) && (!chn);i++)
+          if (chain[i])  {
+            if (!chain[i]->chainID[0])
+              chn = chain[i]; // it is there; just return the pointer
+          }
+      }
+      if (chn)  return chn;
+      strcpy ( chainID,chID );
+    }
+
+    ExpandChainArray ( nChains );
+
+    // create new chain
+    chain[nChains] = newChain();
+    chain[nChains]->SetChain ( chainID );
+    chain[nChains]->SetModel ( this );
+    nChains++;
+
+    return chain[nChains-1];
+
+  }
+
+  PChain Model::CreateChain ( const ChainID chID )  {
+  //   CreateChain() creates a new chain with chain ID regardless
+  // the presence of same-ID chains in the model. This function
+  // was introduced only for compatibility with older CCP4
+  // applications and using it in any new developments should be
+  // strictly discouraged.
+
+    ExpandChainArray ( nChains );
+
+    // create new chain
+    chain[nChains] = newChain();
+    chain[nChains]->SetChain ( chID );
+    chain[nChains]->SetModel ( this );
+    nChains++;
+
+    return chain[nChains-1];
+
+  }
+
+
+  void  Model::GetChainTable ( PPChain & chainTable,
+                               int & NumberOfChains )  {
+    chainTable     = chain;
+    NumberOfChains = nChains;
+  }
+
+  bool Model::GetNewChainID ( ChainID chID, int length )  {
+  int     i,k;
+  bool found;
+
+    memset ( chID,0,sizeof(ChainID) );
+    chID[0] = 'A';
+
+    do  {
+      found = false;
+      for (i=0;(i<nChains) && (!found);i++)
+        if (chain[i])
+          found = (!strcmp(chID,chain[i]->chainID));
+      if (found)  {
+        k = 0;
+        while (k<length)
+          if (!chID[k])  {
+            chID[k] = 'A';
+            break;
+          } else if (chID[k]<'Z')  {
+            chID[k]++;
+            break;
+          } else  {
+            chID[k] = 'A';
+            k++;
+          }
+      } else
+        k = 0;
+    } while (found && (k<length));
+
+    if (found)  {
+      k = strlen(chID);
+      while (k<length)
+        chID[k++] = 'A';
+    }
+
+    return (!found);
+
+  }
+
+
+  PChain Model::GetChain ( const ChainID chID )  {
+  //   Returns pointer on chain, whose identifier is
+  // given in chID. If such a chain is absent in the
+  // model, returns NULL.
+  int     i;
+  bool isChainID;
+    if (chID)  isChainID = (chID[0]!=char(0));
+         else  isChainID = false;
+    if (isChainID)  {
+      for (i=0;i<nChains;i++)
+        if (chain[i])  {
+          if (!strcmp(chID,chain[i]->chainID))
+            return chain[i]; // it is there; just return the pointer
+        }
+    } else  {
+      for (i=0;i<nChains;i++)
+        if (chain[i])  {
+          if (!chain[i]->chainID[0])
+            return chain[i]; // it is there; just return the pointer
+        }
+    }
+    return NULL;
+  }
+
+
+  //  ------------------  Deleting chains  --------------------------
+
+  int Model::DeleteChain ( int chainNo )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])  {
+        Exclude = false;
+        delete chain[chainNo];
+        chain[chainNo] = NULL;
+        Exclude = true;
+        return 1;
+      }
+    }
+    return 0;
+  }
+
+  int Model::DeleteChain ( const ChainID chID )  {
+  int i;
+    if (chID[0])  {
+      for (i=0;i<nChains;i++)
+        if (chain[i])  {
+          if (!strcmp(chID,chain[i]->chainID))  {
+            Exclude  = false;
+            delete chain[i];
+            chain[i] = NULL;
+            Exclude  = true;
+            return 1;
+          }
+        }
+    } else  {
+      for (i=0;i<nChains;i++)
+        if (chain[i])  {
+          if (!chain[i]->chainID[0])  {
+            Exclude  = false;
+            delete chain[i];
+            chain[i] = NULL;
+            Exclude  = true;
+            return 1;
+          }
+        }
+    }
+    return 0;
+  }
+
+
+  int Model::DeleteAllChains()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  {
+        delete chain[i];
+        chain[i] = NULL;
+        k++;
+      }
+    nChains = 0;
+    Exclude = true;
+    return k;
+  }
+
+  int Model::DeleteSolventChains()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  {
+        if (chain[i]->isSolventChain())  {
+          delete chain[i];
+          chain[i] = NULL;
+          k++;
+        }
+      }
+    Exclude = true;
+    return k;
+  }
+
+  void Model::TrimChainTable()  {
+  int i,j;
+    Exclude = false;
+    j = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  {
+        if (chain[i]->nResidues>0)  {
+          if (j<i)  {
+            chain[j] = chain[i];
+            chain[i] = NULL;
+          }
+          j++;
+        } else  {
+          delete chain[i];
+          chain[i] = NULL;
+        }
+      }
+    nChains = j;
+    Exclude = true;
+  }
+
+
+  int  Model::GetNumberOfResidues ( const ChainID chainID )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)  return chn->nResidues;
+    return 0;
+  }
+
+  int  Model::GetNumberOfResidues ( int chainNo )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->nResidues;
+    }
+    return 0;
+  }
+
+  PResidue Model::GetResidue ( const ChainID chainID, int seqNo,
+                                 const InsCode insCode )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)
+      return chn->GetResidue ( seqNo,insCode );
+    return NULL;
+  }
+
+  PResidue Model::GetResidue ( const ChainID chainID, int resNo )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)  {
+      if ((0<=resNo) && (resNo<chn->nResidues))
+        return chn->residue[resNo];
+    }
+    return NULL;
+  }
+
+  PResidue Model::GetResidue ( int chainNo, int seqNo,
+                                 const InsCode insCode )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->GetResidue ( seqNo,insCode );
+    }
+    return NULL;
+  }
+
+  PResidue Model::GetResidue ( int chainNo, int resNo )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo]) {
+        if ((0<=resNo) && (resNo<chain[chainNo]->nResidues))
+          return chain[chainNo]->residue[resNo];
+      }
+    }
+    return NULL;
+  }
+
+  int Model::GetResidueNo ( const ChainID chainID, int seqNo,
+                            const InsCode insCode )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)
+      return chn->GetResidueNo ( seqNo,insCode );
+    return -2;
+  }
+
+  int Model::GetResidueNo ( int  chainNo, int seqNo,
+                             const InsCode insCode )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->GetResidueNo ( seqNo,insCode );
+    }
+    return -2;
+  }
+
+
+  void Model::GetResidueTable ( PPResidue & resTable,
+                                 int & NumberOfResidues )  {
+  // resTable has to be NULL or it will be reallocated. The application
+  // is responsible for deallocating the resTable (but not of its
+  // residues!). This does not apply to other GetResidueTable
+  // functions.
+  PPChain   chn;
+  PPResidue res;
+  int       i,j,k,nChns,nResidues;
+
+    if (resTable)  {
+      delete[] resTable;
+      resTable = NULL;
+    }
+
+    NumberOfResidues = 0;
+    GetChainTable ( chn,nChns );
+    for (i=0;i<nChns;i++)
+      if (chn[i])  {
+        chn[i]->GetResidueTable ( res,nResidues );
+        NumberOfResidues += nResidues;
+      }
+
+    if (NumberOfResidues>0)  {
+      resTable = new PResidue[NumberOfResidues];
+      k = 0;
+      GetChainTable ( chn,nChns );
+      for (i=0;i<nChns;i++)
+        if (chn[i])  {
+          chn[i]->GetResidueTable ( res,nResidues );
+          for (j=0;j<nResidues;j++)
+            if (res[j])  resTable[k++] = res[j];
+        }
+      NumberOfResidues = k;
+    }
+
+  }
+
+  void Model::GetResidueTable ( const ChainID chainID,
+                                 PPResidue & resTable,
+                                 int & NumberOfResidues )  {
+  PChain chn;
+    resTable         = NULL;
+    NumberOfResidues = 0;
+    chn = GetChain ( chainID );
+    if (chn)  {
+      resTable         = chn->residue;
+      NumberOfResidues = chn->nResidues;
+    }
+  }
+
+  void Model::GetResidueTable ( int chainNo, PPResidue & resTable,
+                                 int & NumberOfResidues )  {
+    resTable         = NULL;
+    NumberOfResidues = 0;
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])  {
+        resTable         = chain[chainNo]->residue;
+        NumberOfResidues = chain[chainNo]->nResidues;
+      }
+    }
+  }
+
+
+  int Model::DeleteResidue ( const ChainID chainID, int seqNo,
+                              const InsCode insCode )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)  return chn->DeleteResidue ( seqNo,insCode );
+    return 0;
+  }
+
+  int Model::DeleteResidue ( const ChainID chainID, int resNo )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)  return chn->DeleteResidue ( resNo );
+    return 0;
+  }
+
+  int Model::DeleteResidue ( int  chainNo, int seqNo,
+                              const InsCode insCode )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->DeleteResidue ( seqNo,insCode );
+    }
+    return 0;
+  }
+
+  int Model::DeleteResidue ( int chainNo, int resNo )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->DeleteResidue ( resNo );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAllResidues ( const ChainID chainID )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)  return chn->DeleteAllResidues();
+    return 0;
+  }
+
+  int Model::DeleteAllResidues ( int chainNo )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->DeleteAllResidues();
+    }
+    return 0;
+  }
+
+  int Model::DeleteAllResidues()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        k += chain[i]->DeleteAllResidues();
+    return k;
+  }
+
+
+  int Model::DeleteSolvent()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  {
+        k += chain[i]->DeleteSolvent();
+        chain[i]->TrimResidueTable();
+        if (chain[i]->nResidues<=0)  {
+          delete chain[i];
+          chain[i] = NULL;
+        }
+      }
+    Exclude = true;
+    return k;
+  }
+
+
+  int Model::AddResidue ( const ChainID chainID, PResidue res )  {
+  PChain chn;
+    chn = GetChain ( chainID );
+    if (chn)  return chn->AddResidue ( res );
+    return 0;
+  }
+
+  int Model::AddResidue ( int chainNo, PResidue res )  {
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      if (chain[chainNo])
+        return chain[chainNo]->AddResidue ( res );
+    }
+    return 0;
+  }
+
+
+  int  Model::_ExcludeChain ( const ChainID chainID )  {
+  //   _ExcludeChain(..) excludes (but does not dispose!) a chain
+  // from the model. Returns 1 if the model gets empty and 0 otherwise.
+  int  i,k;
+
+    if (!Exclude)  return 0;
+
+    // find the chain
+    k = -1;
+    for (i=0;(i<nChains) && (k<0);i++)
+      if (!strcmp(chainID,chain[i]->chainID))
+        k = i;
+
+    if (k>=0)  {
+      for (i=k+1;i<nChains;i++)
+        chain[i-1] = chain[i];
+      nChains--;
+      chain[nChains] = NULL;
+    }
+
+    if (nChains<=0)  return 1;
+               else  return 0;
+
+  }
+
+
+  //  --------------------  Sort chains  ----------------------------
+
+  DefineClass(QSortChains)
+
+  class QSortChains : public QuickSort  {
+    public :
+      QSortChains() : QuickSort() { sKey = 0; }
+      int  Compare ( int i, int j );
+      void Swap    ( int i, int j );
+      void Sort    ( PPChain chain, int nChains, int sortKey );
+    private :
+      int sKey;
+  };
+
+  int QSortChains::Compare ( int i, int j )  {
+  int diff;
+
+    diff = strcmp ( (PPChain(data))[i]->GetChainID(),
+                    (PPChain(data))[j]->GetChainID() );
+    if (diff>0)  diff =  1;
+    if (diff<0)  diff = -1;
+
+    if (sKey==SORT_CHAIN_ChainID_Desc) return -diff;
+
+    return diff;
+
+  }
+
+  void QSortChains::Swap ( int i, int j )  {
+  PChain chn;
+    chn = ((PPChain)data)[i];
+    ((PPChain)data)[i] = ((PPChain)data)[j];
+    ((PPChain)data)[j] = chn;
+  }
+
+  void QSortChains::Sort ( PPChain chain, int nChains, int sortKey )  {
+    sKey = sortKey;
+    QuickSort::Sort ( &(chain[0]),nChains );
+  }
+
+  void Model::SortChains ( int sortKey )  {
+  QSortChains SC;
+    TrimChainTable();
+    SC.Sort ( chain,nChains,sortKey );
+  }
+
+
+  // --------------------  Extracting atoms  -----------------------
+
+
+  int  Model::GetNumberOfAtoms ( const ChainID chainID, int seqNo,
+                                  const InsCode insCode )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chainID );
+    if (chn)  {
+      res = chn->GetResidue ( seqNo,insCode );
+      if (res)  return res->nAtoms;
+    }
+    return 0;
+  }
+
+  int  Model::GetNumberOfAtoms ( int chainNo, int seqNo,
+                                  const InsCode insCode )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chainNo );
+    if (chn)  {
+      res = chn->GetResidue ( seqNo,insCode );
+      if (res)  return res->nAtoms;
+    }
+    return 0;
+  }
+
+  int  Model::GetNumberOfAtoms ( const ChainID chainID, int resNo )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chainID );
+    if (chn)  {
+      if ((0<=resNo) && (resNo<chn->nResidues))  {
+        res = chn->residue[resNo];
+        if (res)  return res->nAtoms;
+      }
+    }
+    return 0;
+  }
+
+  int  Model::GetNumberOfAtoms ( int chainNo, int resNo )  {
+  PChain   chn;
+  PResidue res;
+    if ((0<=chainNo) && (chainNo<nChains))  {
+      chn = chain[chainNo];
+      if (chn)  {
+        if ((0<=resNo) && (resNo<chn->nResidues))  {
+          res = chn->residue[resNo];
+          if (res)  return res->nAtoms;
+        }
+      }
+    }
+    return 0;
+  }
+
+  PAtom  Model::GetAtom ( const ChainID  chID,
+                            int            seqNo,
+                            const InsCode  insCode,
+                            const AtomName aname,
+                            const Element  elmnt,
+                            const AltLoc   aloc
+                          )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chID );
+    if (chn)  {
+      res = chn->GetResidue ( seqNo,insCode );
+      if (res)
+        return res->GetAtom ( aname,elmnt,aloc );
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( const ChainID chID,    int seqNo,
+                           const InsCode insCode, int   atomNo )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chID );
+    if (chn)  {
+      res = chn->GetResidue ( seqNo,insCode );
+      if (res)  {
+        if ((0<=atomNo) && (atomNo<res->nAtoms))
+          return res->atom[atomNo];
+      }
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( const ChainID  chID,
+                           int            resNo,
+                           const AtomName aname,
+                           const Element  elmnt,
+                           const AltLoc   aloc )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chID );
+    if (chn)  {
+      if ((0<=resNo) && (resNo<chn->nResidues))  {
+        res = chn->residue[resNo];
+        if (res)
+          return res->GetAtom ( aname,elmnt,aloc );
+      }
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( const ChainID chID, int resNo, int atomNo )  {
+  PChain   chn;
+  PResidue res;
+    chn = GetChain ( chID );
+    if (chn)  {
+      if ((0<=resNo) && (resNo<chn->nResidues))  {
+        res = chn->residue[resNo];
+        if (res)  {
+          if ((0<=atomNo) && (atomNo<res->nAtoms))
+            return res->atom[atomNo];
+        }
+      }
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( int chNo, int seqNo,
+                           const InsCode  insCode,
+                           const AtomName aname,
+                           const Element  elmnt,
+                           const AltLoc   aloc )  {
+  PResidue res;
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])  {
+        res = chain[chNo]->GetResidue ( seqNo,insCode );
+        if (res)
+          return res->GetAtom ( aname,elmnt,aloc );
+      }
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( int chNo, int seqNo, const InsCode insCode,
+                           int atomNo )  {
+  PResidue res;
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])  {
+        res = chain[chNo]->GetResidue ( seqNo,insCode );
+        if (res)  {
+          if ((0<=atomNo) && (atomNo<res->nAtoms))
+            return res->atom[atomNo];
+        }
+      }
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( int chNo, int resNo,
+                           const AtomName aname,
+                           const Element  elmnt,
+                           const AltLoc   aloc )  {
+  PResidue res;
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])  {
+        if ((0<=resNo) && (resNo<chain[chNo]->nResidues))  {
+          res = chain[chNo]->residue[resNo];
+          if (res)
+            return res->GetAtom ( aname,elmnt,aloc );
+        }
+      }
+    }
+    return NULL;
+  }
+
+  PAtom Model::GetAtom ( int chNo, int resNo, int atomNo )  {
+  PResidue res;
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])  {
+        if ((0<=resNo) && (resNo<chain[chNo]->nResidues))  {
+          res = chain[chNo]->residue[resNo];
+          if (res)  {
+            if ((0<=atomNo) && (atomNo<res->nAtoms))
+              return res->atom[atomNo];
+          }
+        }
+      }
+    }
+    return NULL;
+  }
+
+
+  void Model::GetAtomTable ( const ChainID chainID, int seqNo,
+                              const InsCode insCode,
+                              PPAtom & atomTable,
+                              int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    res = GetResidue ( chainID,seqNo,insCode );
+    if (res)  {
+      atomTable     = res->atom;
+      NumberOfAtoms = res->nAtoms;
+    }
+  }
+
+  void Model::GetAtomTable ( int chainNo, int seqNo,
+                              const InsCode insCode,
+                              PPAtom & atomTable,
+                              int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    res = GetResidue ( chainNo,seqNo,insCode );
+    if (res)  {
+      atomTable     = res->atom;
+      NumberOfAtoms = res->nAtoms;
+    }
+  }
+
+  void Model::GetAtomTable ( const ChainID chainID, int resNo,
+                              PPAtom & atomTable,
+                              int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    res = GetResidue ( chainID,resNo );
+    if (res)  {
+      atomTable     = res->atom;
+      NumberOfAtoms = res->nAtoms;
+    }
+  }
+
+  void Model::GetAtomTable ( int chainNo, int resNo,
+                              PPAtom & atomTable,
+                              int & NumberOfAtoms )  {
+  PResidue res;
+    atomTable     = NULL;
+    NumberOfAtoms = 0;
+    res = GetResidue ( chainNo,resNo );
+    if (res)  {
+      atomTable     = res->atom;
+      NumberOfAtoms = res->nAtoms;
+    }
+  }
+
+
+  void Model::GetAtomTable1 ( const ChainID chainID, int seqNo,
+                               const InsCode insCode,
+                               PPAtom & atomTable,
+                               int & NumberOfAtoms )  {
+  PResidue res;
+    res = GetResidue ( chainID,seqNo,insCode );
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void Model::GetAtomTable1 ( int chainNo, int seqNo,
+                               const InsCode insCode,
+                               PPAtom & atomTable,
+                               int & NumberOfAtoms )  {
+  PResidue res;
+    res = GetResidue ( chainNo,seqNo,insCode );
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void Model::GetAtomTable1 ( const ChainID chainID, int resNo,
+                               PPAtom & atomTable,
+                               int & NumberOfAtoms )  {
+  PResidue res;
+    res = GetResidue ( chainID,resNo );
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+  void Model::GetAtomTable1 ( int chainNo, int resNo,
+                               PPAtom & atomTable,
+                               int & NumberOfAtoms )  {
+  PResidue res;
+    res = GetResidue ( chainNo,resNo );
+    if (res)
+      res->GetAtomTable1 ( atomTable,NumberOfAtoms );
+    else  {
+      if (atomTable)  delete[] atomTable;
+      atomTable     = NULL;
+      NumberOfAtoms = 0;
+    }
+  }
+
+
+
+  int  Model::DeleteAtom ( const ChainID  chID,
+                            int            seqNo,
+                            const InsCode  insCode,
+                            const AtomName aname,
+                            const Element  elmnt,
+                            const AltLoc   aloc
+                          )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)
+      return  chn->DeleteAtom ( seqNo,insCode,aname,elmnt,aloc );
+    return 0;
+  }
+
+  int  Model::DeleteAtom ( const ChainID chID,    int seqNo,
+                            const InsCode insCode, int   atomNo )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->DeleteAtom ( seqNo,insCode,atomNo );
+    return 0;
+  }
+
+  int  Model::DeleteAtom ( const ChainID  chID,
+                            int            resNo,
+                            const AtomName aname,
+                            const Element  elmnt,
+                            const AltLoc   aloc )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->DeleteAtom ( resNo,aname,elmnt,aloc );
+    return 0;
+  }
+
+  int  Model::DeleteAtom ( const ChainID chID, int resNo, int atomNo ) {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->DeleteAtom ( resNo,atomNo );
+    return 0;
+  }
+
+  int  Model::DeleteAtom ( int chNo, int seqNo,
+                            const InsCode  insCode,
+                            const AtomName aname,
+                            const Element  elmnt,
+                            const AltLoc   aloc )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->DeleteAtom ( seqNo,insCode,aname,
+                                         elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAtom ( int chNo, int seqNo, const InsCode insCode,
+                           int atomNo )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return  chain[chNo]->DeleteAtom ( seqNo,insCode,atomNo );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAtom ( int chNo, int resNo,
+                           const AtomName aname,
+                           const Element  elmnt,
+                           const AltLoc   aloc )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->DeleteAtom ( resNo,aname,elmnt,aloc );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAtom ( int chNo, int resNo, int atomNo )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->DeleteAtom ( resNo,atomNo );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms ( const ChainID chID, int seqNo,
+                               const InsCode insCode )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->DeleteAllAtoms ( seqNo,insCode );
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms ( const ChainID chID, int resNo )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->DeleteAllAtoms ( resNo );
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms ( const ChainID chID )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->DeleteAllAtoms();
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms ( int chNo, int seqNo,
+                               const InsCode insCode )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->DeleteAllAtoms ( seqNo,insCode );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms ( int chNo, int resNo )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->DeleteAllAtoms ( resNo );
+    }
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms ( int chNo )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->DeleteAllAtoms();
+    }
+    return 0;
+  }
+
+  int Model::DeleteAllAtoms()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  k += chain[i]->DeleteAllAtoms();
+    return k;
+  }
+
+  int Model::DeleteAltLocs()  {
+  //  This function leaves only alternative location with maximal
+  // occupancy, if those are equal or unspecified, the one with
+  // "least" alternative location indicator.
+  //  The function returns the number of deleted. All tables remain
+  // untrimmed, so that explicit trimming or calling FinishStructEdit()
+  // is required.
+  int i,n;
+
+    n = 0;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  n += chain[i]->DeleteAltLocs();
+
+    return n;
+
+  }
+
+
+  int Model::AddAtom ( const ChainID chID, int seqNo,
+                        const InsCode insCode,
+                        PAtom atom )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->AddAtom ( seqNo,insCode,atom );
+    return 0;
+  }
+
+  int Model::AddAtom ( const ChainID chID, int resNo, PAtom  atom )  {
+  PChain chn;
+    chn = GetChain ( chID );
+    if (chn)  return chn->AddAtom ( resNo,atom );
+    return 0;
+  }
+
+  int Model::AddAtom ( int chNo, int seqNo, const InsCode insCode,
+                        PAtom atom )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->AddAtom ( seqNo,insCode,atom );
+    }
+    return 0;
+  }
+
+  int Model::AddAtom ( int chNo, int resNo, PAtom atom )  {
+    if ((0<=chNo) && (chNo<nChains))  {
+      if (chain[chNo])
+        return chain[chNo]->AddAtom ( resNo,atom );
+    }
+    return 0;
+  }
+
+
+
+  void  Model::GetAtomStatistics ( RAtomStat AS )  {
+    AS.Init();
+    CalAtomStatistics ( AS );
+    AS.Finish();
+  }
+
+  void  Model::CalAtomStatistics ( RAtomStat AS )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->CalAtomStatistics ( AS );
+  }
+
+
+
+  ERROR_CODE Model::ConvertPDBString ( pstr PDBString ) {
+  //   Interprets PDB records DBREF, SEQADV, SEQRES, MODRES.
+  //   Returns zero if the line was converted, otherwise returns a
+  // non-negative value of Error_XXXX.
+  //   PDBString must be not shorter than 81 characters.
+  ChainID    chainID;
+  PChain     chn;
+  PHelix     helix;
+  PTurn      turn;
+  PLink      link;
+  PLinkR     linkR;
+  PCisPep    cispep;
+  ERROR_CODE RC;
+
+    //  pad input line with spaces, if necessary
+    PadSpaces ( PDBString,80 );
+
+    chainID[0] = char(0);
+    chainID[1] = char(0);
+
+    if (!strncmp(PDBString,"DBREF ",6))  {
+
+      if (PDBString[12]!=' ')  chainID[0] = PDBString[12];
+      chn = GetChainCreate ( chainID,false );
+      return chn->ConvertDBREF ( PDBString );
+
+    } else if (!strncmp(PDBString,"SEQADV",6))  {
+
+      if (PDBString[16]!=' ')  chainID[0] = PDBString[16];
+      chn = GetChainCreate ( chainID,false );
+      return chn->ConvertSEQADV ( PDBString );
+
+    } else if (!strncmp(PDBString,"SEQRES",6))  {
+
+      if (PDBString[11]!=' ')  chainID[0] = PDBString[11];
+      chn = GetChainCreate ( chainID,false );
+      return chn->ConvertSEQRES ( PDBString );
+
+    } else if (!strncmp(PDBString,"MODRES",6))  {
+
+      if (PDBString[16]!=' ')  chainID[0] = PDBString[16];
+      chn = GetChainCreate ( chainID,false );
+      return chn->ConvertMODRES ( PDBString );
+
+    } else if (!strncmp(PDBString,"HET   ",6))  {
+
+      if (PDBString[12]!=' ')  chainID[0] = PDBString[12];
+      chn = GetChainCreate ( chainID,false );
+      return chn->ConvertHET ( PDBString );
+
+    } else if (!strncmp(PDBString,"HETNAM",6))  {
+
+      hetCompounds.ConvertHETNAM ( PDBString );
+      return Error_NoError;
+
+    } else if (!strncmp(PDBString,"HETSYN",6))  {
+
+      hetCompounds.ConvertHETSYN ( PDBString );
+      return Error_NoError;
+
+    } else if (!strncmp(PDBString,"FORMUL",6))  {
+
+      hetCompounds.ConvertFORMUL ( PDBString );
+      return Error_NoError;
+
+    } else if (!strncmp(PDBString,"HELIX ",6))  {
+
+      helix = new Helix();
+      RC    = helix->ConvertPDBASCII(PDBString);
+      if (RC==0)  helices.AddData ( helix );
+            else  delete helix;
+      return RC;
+
+    } else if (!strncmp(PDBString,"SHEET ",6))  {
+
+      return sheets.ConvertPDBASCII ( PDBString );
+
+    } else if (!strncmp(PDBString,"TURN  ",6))  {
+
+      turn = new Turn();
+      RC   = turn->ConvertPDBASCII(PDBString);
+      if (RC==0)  turns.AddData ( turn );
+            else  delete turn;
+      return RC;
+
+    } else if (!strncmp(PDBString,"LINK  ",6))  {
+
+      link = new Link();
+      RC   = link->ConvertPDBASCII(PDBString);
+      if (RC==0)  links.AddData ( link );
+            else  delete link;
+      return RC;
+
+
+    } else if (!strncmp(PDBString,"LINKR ",6))  {
+
+      linkR = new LinkR();
+      RC   = linkR->ConvertPDBASCII(PDBString);
+      if (RC==0)  linkRs.AddData ( linkR );
+            else  delete linkR;
+      return RC;
+
+    } else if (!strncmp(PDBString,"CISPEP",6))  {
+
+      cispep = new CisPep();
+      RC   = cispep->ConvertPDBASCII(PDBString);
+      if (RC==0)  cisPeps.AddData ( cispep );
+            else  delete cispep;
+      return RC;
+
+    } else
+      return Error_WrongSection;
+
+  }
+
+
+  void  Model::PDBASCIIDumpPS ( io::RFile f )  {
+  int i;
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->DBRef.PDBASCIIDump ( f );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->seqAdv.PDBASCIIDump ( f );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->seqRes.PDBASCIIDump ( f );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->modRes.PDBASCIIDump ( f );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->Het.PDBASCIIDump ( f );
+
+    hetCompounds.PDBASCIIDump ( f );
+    helices     .PDBASCIIDump ( f );
+    sheets      .PDBASCIIDump ( f );
+    turns       .PDBASCIIDump ( f );
+    links       .PDBASCIIDump ( f );
+    linkRs      .PDBASCIIDump ( f );
+
+  }
+
+  void  Model::PDBASCIIDumpCP ( io::RFile f )  {
+    cisPeps.PDBASCIIDump ( f );
+  }
+
+  void  Model::PDBASCIIDump ( io::RFile f )  {
+  char  S[100];
+  int   i;
+  bool  singleModel = true;
+
+    if (manager)
+      singleModel = (manager->nModels<=1);
+
+    if (!singleModel)  {
+      strcpy      ( S,"MODEL " );
+      PadSpaces   ( S,80 );
+      PutInteger  ( &(S[10]),serNum,4 );
+      f.WriteLine ( S );
+    }
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->PDBASCIIAtomDump ( f );
+
+    if (!singleModel)  {
+      strcpy      ( S,"ENDMDL" );
+      PadSpaces   ( S,80 );
+      f.WriteLine ( S );
+    }
+
+  }
+
+
+  void  Model::MakeAtomCIF ( mmcif::PData CIF )  {
+  int  i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->MakeAtomCIF ( CIF );
+  }
+
+
+  void  Model::MakePSCIF ( mmcif::PData CIF )  {
+  int  i;
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->DBRef.MakeCIF ( CIF );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->seqAdv.MakeCIF ( CIF );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->seqRes.MakeCIF ( CIF );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->modRes.MakeCIF ( CIF );
+
+    for (i=0;i<nChains;i++)
+      if (chain[i])
+        chain[i]->Het.MakeCIF ( CIF );
+
+    hetCompounds.MakeCIF ( CIF );
+    helices     .MakeCIF ( CIF );
+    sheets      .MakeCIF ( CIF );
+    turns       .MakeCIF ( CIF );
+    links       .MakeCIF ( CIF );
+    linkRs      .MakeCIF ( CIF );
+
+  }
+
+  ERROR_CODE Model::GetCIFPSClass ( mmcif::PData CIF, int ClassID )  {
+  ChainContainer  PSClass;
+  PChainContainer Dest;
+  ERROR_CODE      RC;
+  cpstr           chainID;
+  PChain          chn;
+    PSClass.SetChain ( NULL );
+    RC = PSClass.GetCIF ( CIF,ClassID );
+    if (RC!=Error_NoError)  return RC;
+    chainID = PSClass.Get1stChainID();
+    while (chainID)  {
+      chn = GetChainCreate ( chainID,false );
+      switch (ClassID)  {
+        case ClassID_DBReference : Dest = &(chn->DBRef);   break;
+        case ClassID_SeqAdv      : Dest = &(chn->seqAdv);  break;
+        case ClassID_ModRes      : Dest = &(chn->modRes);  break;
+        case ClassID_Het         : Dest = &(chn->Het);     break;
+        default                  : Dest = NULL;
+      }
+      if (Dest)  {
+        PSClass.MoveByChainID ( chainID,Dest );
+        Dest->SetChain ( chn );
+      } else
+        printf ( " **** PROGRAM ERROR: wrong call to"
+                 " Model::GetCIFPSClass(..)\n" );
+      chainID = PSClass.Get1stChainID();
+    }
+    return Error_NoError;
+  }
+
+  ERROR_CODE Model::GetCIF ( mmcif::PData CIF ) {
+  SeqRes     seqRes;
+  ERROR_CODE RC;
+  PChain     chn;
+
+    RC = GetCIFPSClass ( CIF,ClassID_DBReference );
+    if (RC!=Error_NoError)  return RC;
+
+    RC = GetCIFPSClass ( CIF,ClassID_SeqAdv );
+    if (RC!=Error_NoError)  return RC;
+
+    RC = seqRes.GetCIF ( CIF );
+    while (RC==Error_NoError)  {
+      chn = GetChainCreate ( seqRes.chainID,false );
+      chn->seqRes.Copy ( &seqRes );
+      RC  = seqRes.GetCIF ( CIF );
+    }
+
+    RC = GetCIFPSClass ( CIF,ClassID_ModRes );
+    if (RC!=Error_NoError)  return RC;
+
+    RC = GetCIFPSClass ( CIF,ClassID_Het );
+    if (RC!=Error_NoError)  return RC;
+
+    hetCompounds.GetCIF ( CIF );
+    helices     .GetCIF ( CIF,ClassID_Helix );
+    sheets      .GetCIF ( CIF );
+    turns       .GetCIF ( CIF,ClassID_Turn  );
+    links       .GetCIF ( CIF,ClassID_Link  );
+    linkRs      .GetCIF ( CIF,ClassID_LinkR );
+
+    return RC;
+
+  }
+
+  cpstr  Model::GetEntryID()  {
+    if (manager)  return manager->title.idCode;
+            else  return pstr("");
+  }
+
+  void  Model::SetEntryID ( const IDCode idCode )  {
+    if (manager)
+      manager->SetEntryID ( idCode );
+  }
+
+  int   Model::GetNumberOfAllAtoms()  {
+    if (manager)  return manager->nAtoms;
+            else  return 0;
+  }
+
+  int   Model::GetSerNum()  {
+    return serNum;
+  }
+
+  PAtom * Model::GetAllAtoms()  {
+    if (manager)  return manager->atom;
+            else  return NULL;
+  }
+
+
+  cpstr  Model::GetModelID ( pstr modelID )  {
+    modelID[0] = char(0);
+    sprintf ( modelID,"/%i",serNum );
+    return modelID;
+  }
+
+  int   Model::GetNumberOfModels()  {
+    if (manager)  return manager->nModels;
+            else  return 0;
+  }
+
+
+  void  Model::Copy ( PModel model )  {
+  //  modify both Model::_copy and Model::Copy methods simultaneously!
+  int i;
+
+    FreeMemory();
+
+    if (model)  {
+
+      serNum       = model->serNum;
+      nChains      = model->nChains;
+      nChainsAlloc = nChains;
+      if (nChains>0)  {
+        chain = new PChain[nChainsAlloc];
+        for (i=0;i<nChains;i++)  {
+          if (model->chain[i])  {
+            chain[i] = newChain();
+            chain[i]->SetModel ( this );
+            chain[i]->Copy ( model->chain[i] );
+          } else
+            chain[i] = NULL;
+        }
+      }
+
+      hetCompounds.Copy ( &(model->hetCompounds) );
+      helices     .Copy ( &(model->helices)      );
+      sheets      .Copy ( &(model->sheets)       );
+      turns       .Copy ( &(model->turns)        );
+      links       .Copy ( &(model->links)        );
+      linkRs      .Copy ( &(model->linkRs)       );
+      cisPeps     .Copy ( &(model->cisPeps)      );
+
+    }
+
+  }
+
+  void  Model::CopyHets ( PModel model )  {
+    if (model)  hetCompounds.Copy ( &(model->hetCompounds) );
+  }
+
+  void  Model::CopySecStructure ( PModel model )  {
+    if (model)  {
+      helices.Copy ( &(model->helices) );
+      sheets .Copy ( &(model->sheets)  );
+      turns  .Copy ( &(model->turns)   );
+    }
+  }
+
+  void  Model::CopyLinks ( PModel model )  {
+    if (model)links.Copy ( &(model->links) );
+  }
+
+  void  Model::CopyLinkRs ( PModel model )  {
+    if (model)  linkRs.Copy ( &(model->linkRs) );
+  }
+
+  void  Model::CopyCisPeps ( PModel model )  {
+    if (model)  cisPeps.Copy ( &(model->cisPeps) );
+  }
+
+  void  Model::_copy ( PModel model )  {
+  //  modify both Model::_copy and Model::Copy methods simultaneously!
+  int i;
+
+    FreeMemory();
+
+    if (model)  {
+
+      serNum       = model->serNum;
+      nChains      = model->nChains;
+      nChainsAlloc = nChains;
+      if (nChains>0)  {
+        chain = new PChain[nChainsAlloc];
+        for (i=0;i<nChains;i++)  {
+          if (model->chain[i])  {
+            chain[i] = newChain();
+            chain[i]->SetModel ( this );
+            chain[i]->_copy ( model->chain[i] );
+          } else
+            chain[i] = NULL;
+        }
+      }
+
+      hetCompounds.Copy ( &(model->hetCompounds) );
+      helices     .Copy ( &(model->helices)      );
+      sheets      .Copy ( &(model->sheets)       );
+      turns       .Copy ( &(model->turns)        );
+      links       .Copy ( &(model->links)        );
+      linkRs      .Copy ( &(model->linkRs)       );
+      cisPeps     .Copy ( &(model->cisPeps)      );
+
+    }
+
+  }
+
+
+  void  Model::_copy ( PModel model, PPAtom atom, int & atom_index ) {
+  //  modify both Model::_copy and Model::Copy methods simultaneously!
+  //
+  //  _copy(PModel,PPAtom,int&) does copy atoms into array 'atom'
+  // starting from position atom_index. 'atom' should be able to
+  // accept all new atoms - no checks on the length of 'atom'
+  // is being made. This function should not be used in applications.
+  int i;
+
+    FreeMemory();
+
+    if (model)  {
+
+      serNum       = model->serNum;
+      nChains      = model->nChains;
+      nChainsAlloc = nChains;
+      if (nChains>0)  {
+        chain = new PChain[nChainsAlloc];
+        for (i=0;i<nChains;i++)  {
+          if (model->chain[i])  {
+            chain[i] = newChain();
+            chain[i]->SetModel ( this );
+            chain[i]->_copy ( model->chain[i],atom,atom_index );
+          } else
+            chain[i] = NULL;
+        }
+      }
+
+      hetCompounds.Copy ( &(model->hetCompounds) );
+      helices     .Copy ( &(model->helices)      );
+      sheets      .Copy ( &(model->sheets)       );
+      turns       .Copy ( &(model->turns)        );
+      links       .Copy ( &(model->links)        );
+      linkRs      .Copy ( &(model->linkRs)       );
+
+    }
+
+  }
+
+
+  int  Model::AddChain ( PChain chn )  {
+  //  modify both Model::Copy methods simultaneously!
+  //
+  //  Copy(PModel,PPAtom,int&) copies atoms into array 'atom'
+  // starting from position atom_index. 'atom' should be able to
+  // accept all new atoms - no checks on the length of 'atom'
+  // is being made. This function should not be used in applications.
+  PModel  model1;
+  int     i;
+
+    for (i=0;i<nChains;i++)
+      if (chain[i]==chn)  return -i;  // this chain is already there
+
+    if (chn)  {
+
+      // get space for new chain
+      ExpandChainArray ( nChains );
+
+      if (chn->GetCoordHierarchy())  {
+        // The chain is associated with a coordinate hierarchy. It should
+        // remain there, therefore we physically copy all its residues
+        // and atoms.
+        chain[nChains] = newChain();
+        chain[nChains]->SetModel ( this );
+        if (manager)  {
+          // get space for new atoms
+          manager->AddAtomArray ( chn->GetNumberOfAtoms(true) );
+          chain[nChains]->_copy ( chn,manager->atom,manager->nAtoms );
+        } else  {
+          for (i=0;i<chn->nResidues;i++)
+            chain[nChains]->AddResidue ( chn->residue[i] );
+        }
+      } else  {
+        // The chain is not associated with a coordinate hierarchy. Such
+        // unregistered objects are simply taken over, i.e. moved into
+        // the new destination (model).
+        chain[nChains] = chn;
+        // remove chain from its model:
+        model1 = chn->GetModel();
+        if (model1)
+          for (i=0;i<model1->nChains;i++)
+            if (model1->chain[i]==chn)  {
+              model1->chain[i] = NULL;
+              break;
+            }
+        chain[nChains]->SetModel ( this );
+        if (manager)
+          chain[nChains]->CheckInAtoms();
+      }
+
+      nChains++;
+
+    }
+
+    return nChains;
+
+  }
+
+
+  void  Model::MoveChain ( PChain & m_chain, PPAtom m_atom,
+                            PPAtom  atom, int & atom_index,
+                            int  chain_ext )  {
+  //   MoveChain(..) adds chain m_chain on the top Chain array.
+  // The pointer on chain is then set to NULL (m_chain=NULL).
+  // If chain_ext is greater than 0, the moved chain will be
+  // forcefully renamed; the new name is composed as the previous
+  // one + underscore + chain_ext (e.g. A_1). If thus generated
+  // name duplicates any of existing chain IDs, or if chain_ext
+  // was set to 0 and there is a duplication of chain IDs, the
+  // name is again modified as above, with the extension number
+  // generated automatically (this may result in IDs like
+  // A_1_10).
+  //   m_atom must give pointer to the Atom array, from which
+  // the atoms belonging to m_chain, are moved to Atom array
+  // given by 'atom', starting from poisition 'atom_index'.
+  // 'atom_index' is then automatically updated to the next
+  // free position in 'atom'.
+  //   Note1: the moved atoms will occupy a continuous range
+  // in 'atom' array; no checks on whether the corresponding
+  // cells are occupied or not, are performed.
+  //   Note2: the 'atom_index' is numbered from 0 on, i.e.
+  // it is equal to atom[atom_index]->index-1; atom[]->index
+  // is assigned automatically.
+  ChainID   chainID;
+  int       i,j,k,Ok;
+  PPChain   chain1;
+  PResidue  crRes;
+
+    if (!m_chain)  return;
+
+    // modify chain ID with the extension given
+    if (chain_ext>0)
+          sprintf ( chainID,"%s_%i",m_chain->chainID,chain_ext );
+    else  strcpy  ( chainID,m_chain->chainID );
+
+    // Choose the chain ID. If a chain with such ID is
+    // already present in the model, it will be assigned
+    // a new ID 'ID_n', where 'ID' stands for the original
+    // chain ID and 'n' is the minimum (integer) number
+    // chosen such that 'name_n' represents a new chain ID
+    // (in the model).
+    k = 0;
+    do {
+      Ok = true;
+      for (i=0;(i<nChains) && (Ok);i++)
+        if (chain[i])
+          if (!strcmp(chainID,chain[i]->chainID))  Ok = false;
+      if (!Ok)  {
+        k++;
+        if (chain_ext>0)
+              sprintf ( chainID,"%s_%i_%i",m_chain->chainID,
+                                           chain_ext,k );
+        else  sprintf ( chainID,"%s_%i",m_chain->chainID,k );
+      }
+    } while (!Ok);
+
+    // add chain on the top of Chain array.
+    strcpy ( m_chain->chainID,chainID );
+    if (nChains>=nChainsAlloc)  {
+      nChainsAlloc = nChains+10;
+      chain1 = new PChain[nChainsAlloc];
+      k = 0;
+      for (i=0;i<nChains;i++)
+        if (chain[i])  chain1[k++] = chain[i];
+      for (i=k;i<nChainsAlloc;i++)
+        chain1[i] = NULL;
+      if (chain)  delete[] chain;
+      chain = chain1;
+    }
+    chain[nChains] = m_chain;
+    chain[nChains]->SetModel ( this );
+    nChains++;
+
+    // Move all atoms of the chain. While residues belong
+    // atoms belong to the chain's manager class. Therefore
+    // they should be moved from one manager to another.
+    for (i=0;i<m_chain->nResidues;i++)  {
+      crRes = m_chain->residue[i];
+      if (crRes)
+        for (j=0;j<crRes->nAtoms;j++)
+          if (crRes->atom[j])  {
+            k = crRes->atom[j]->index-1;
+            atom[atom_index] = m_atom[k];
+            atom[atom_index]->index = atom_index+1;
+            atom_index++;
+            m_atom[k] = NULL;  // moved!
+          }
+    }
+
+    m_chain = NULL;  // moved!
+
+  }
+
+  void Model::GetAIndexRange ( int & i1, int & i2 )  {
+  PChain    chn;
+  PResidue  res;
+  int       ic,ir,ia;
+    i1 = MaxInt4;
+    i2 = MinInt4;
+    for (ic=0;ic<nChains;ic++)  {
+      chn = chain[ic];
+      if (chn)  {
+        for (ir=0;ir<chn->nResidues;ir++)  {
+          res = chn->residue[ir];
+          if (res)  {
+            for (ia=0;ia<res->nAtoms;ia++)
+              if (res->atom[ia])  {
+                if (res->atom[ia]->index<i1)  i1 = res->atom[ia]->index;
+                if (res->atom[ia]->index>i2)  i2 = res->atom[ia]->index;
+              }
+          }
+        }
+      }
+    }
+
+  }
+
+
+  void  Model::MaskAtoms ( PMask Mask )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->MaskAtoms ( Mask );
+  }
+
+  void  Model::MaskResidues ( PMask Mask )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->MaskResidues ( Mask );
+  }
+
+  void  Model::MaskChains ( PMask Mask )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->SetMask ( Mask );
+  }
+
+  void  Model::UnmaskAtoms ( PMask Mask )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->UnmaskAtoms ( Mask );
+  }
+
+  void  Model::UnmaskResidues ( PMask Mask )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->UnmaskResidues ( Mask );
+  }
+
+  void  Model::UnmaskChains ( PMask Mask )  {
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->RemoveMask ( Mask );
+  }
+
+
+  // ------ Getting Secondary Structure Elements
+
+  int  Model::GetNumberOfHelices()  {
+    return  helices.Length();
+  }
+
+  int  Model::GetNumberOfSheets()  {
+    return  sheets.nSheets;
+  }
+
+  PHelix  Model::GetHelix ( int serialNum )  {
+    return (PHelix)helices.GetContainerClass ( serialNum-1 );
+  }
+
+  void  Model::GetSheetID ( int serialNum, SheetID sheetID )  {
+    if ((1<=serialNum) && (serialNum<=sheets.nSheets))  {
+      if (sheets.sheet[serialNum-1])  {
+        strcpy ( sheetID,sheets.sheet[serialNum-1]->sheetID );
+        return;
+      }
+    }
+    sheetID[0] = char(0);
+  }
+
+  PSheet Model::GetSheet ( int serialNum )  {
+    if ((1<=serialNum) && (serialNum<=sheets.nSheets))
+          return  sheets.sheet[serialNum-1];
+    else  return  NULL;
+  }
+
+  PSheet Model::GetSheet ( const SheetID sheetID )  {
+  int i;
+    for (i=0;i<sheets.nSheets;i++)
+      if (sheets.sheet[i])  {
+        if (!strcmp(sheets.sheet[i]->sheetID,sheetID))
+          return sheets.sheet[i];
+      }
+    return NULL;
+  }
+
+  int  Model::GetNumberOfStrands ( int sheetSerNum )  {
+    if ((1<=sheetSerNum) && (sheetSerNum<=sheets.nSheets))  {
+      if (sheets.sheet[sheetSerNum-1])
+        return  sheets.sheet[sheetSerNum-1]->nStrands;
+    }
+    return 0;
+  }
+
+  int  Model::GetNumberOfStrands ( const SheetID sheetID )  {
+  int i;
+    for (i=0;i<sheets.nSheets;i++)
+      if (sheets.sheet[i])  {
+        if (!strcmp(sheets.sheet[i]->sheetID,sheetID))
+          return sheets.sheet[i]->nStrands;
+      }
+    return 0;
+  }
+
+  PStrand Model::GetStrand ( int sheetSerNum, int strandSerNum )  {
+  PSheet sheet;
+    if ((1<=sheetSerNum) && (sheetSerNum<=sheets.nSheets))  {
+      sheet = sheets.sheet[sheetSerNum-1];
+      if (sheet)  {
+        if ((1<=strandSerNum) && (strandSerNum<=sheet->nStrands))
+        return  sheet->strand[strandSerNum-1];
+      }
+    }
+    return NULL;
+  }
+
+  PStrand Model::GetStrand ( const SheetID sheetID,
+                             int strandSerNum )  {
+  int    i;
+  PSheet sheet;
+    for (i=0;i<sheets.nSheets;i++)
+      if (sheets.sheet[i])  {
+        if (!strcmp(sheets.sheet[i]->sheetID,sheetID))  {
+          sheet = sheets.sheet[i];
+          if (sheet)  {
+            if ((1<=strandSerNum) && (strandSerNum<=sheet->nStrands))
+              return  sheet->strand[strandSerNum-1];
+          }
+        }
+      }
+    return NULL;
+  }
+
+  void  Model::RemoveSecStructure()  {
+    helices.FreeContainer();
+    sheets .FreeMemory   ();
+    turns  .FreeContainer();
+  }
+
+  void  Model::RemoveHetInfo()  {
+    hetCompounds.FreeMemory();
+  }
+
+
+  int  Model::GetNumberOfLinks()  {
+    return  links.Length();
+  }
+
+  PLink  Model::GetLink ( int serialNum )  {
+    return (PLink)links.GetContainerClass ( serialNum-1 );
+  }
+
+  void  Model::RemoveLinks()  {
+    links.FreeContainer();
+  }
+
+  void  Model::AddLink ( PLink link )  {
+    links.AddData ( link );
+  }
+
+
+  int  Model::GetNumberOfLinkRs()  {
+    return  linkRs.Length();
+  }
+
+  PLinkR  Model::GetLinkR ( int serialNum )  {
+    return (PLinkR)linkRs.GetContainerClass ( serialNum-1 );
+  }
+
+  void  Model::RemoveLinkRs()  {
+    linkRs.FreeContainer();
+  }
+
+  void  Model::AddLinkR ( PLinkR linkR )  {
+    linkRs.AddData ( linkR );
+  }
+
+
+
+  int  Model::GetNumberOfCisPeps()  {
+    return  cisPeps.Length();
+  }
+
+  PCisPep Model::GetCisPep ( int CisPepNum )  {
+    return (PCisPep)cisPeps.GetContainerClass ( CisPepNum-1 );
+  }
+
+  void  Model::RemoveCisPeps()  {
+    cisPeps.FreeContainer();
+  }
+
+  void  Model::AddCisPep ( PCisPep cisPep )  {
+    cisPeps.AddData ( cisPep );
+  }
+
+
+  void  Model::ApplyTransform ( mat44 & TMatrix )  {
+  // transforms all coordinates by multiplying with matrix TMatrix
+  int i;
+    for (i=0;i<nChains;i++)
+      if (chain[i])  chain[i]->ApplyTransform ( TMatrix );
+  }
+
+  bool Model::isInSelection ( int selHnd )  {
+  PMask  mask;
+    if (manager)  {
+      mask = PRoot(manager)->GetSelMask ( selHnd );
+      if (mask)  return CheckMask ( mask );
+    }
+    return false;
+  }
+
+
+
+  // -------  user-defined data handlers
+
+  int  Model::PutUDData ( int UDDhandle, int iudd )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::putUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Model::PutUDData ( int UDDhandle, realtype rudd )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::putUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Model::PutUDData ( int UDDhandle, cpstr sudd )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::putUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Model::GetUDData ( int UDDhandle, int & iudd )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::getUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Model::GetUDData ( int UDDhandle, realtype & rudd )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::getUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Model::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::getUDData ( UDDhandle,sudd,maxLen );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Model::GetUDData ( int UDDhandle, pstr & sudd )  {
+    if (UDDhandle & UDRF_MODEL)
+          return  UDData::getUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+
+  // -------  calculation of Secondary Structure
+
+
+  int Model::CalcSecStructure ( bool flagBulge, int aminoSelHnd )  {
+  // This function is contributed by Liz Potterton, University of York
+  //------------------------------------------------------------------
+  // Define a secondary structure type of each amino acid residue in the
+  // structure.
+  // Procedure:
+  // Find all amino acids
+  // Find all pairs of amino acids which have inter-Ca distance  < 10.0A
+  // Test for hydrogen bonds between the main chain N and O of the close
+  // residues and store the information in the hbonds matrix
+  // Analyse the info in hbonds matrix to assign secondary structure to
+  // secstr vector
+  PPResidue Res;
+  PPAtom    Ca;
+  PChain    chn;
+  PContact  contact;
+  imatrix   hbonds;
+  PPAtom *  hbond_atoms;
+  int       nres, ncontacts;
+  int       ir1,ir2, irdif;
+  int       i,j,k,l;
+
+    // 1a. Get protein residues from selection handle
+
+    if (aminoSelHnd>=0) {
+
+      manager->GetSelIndex(aminoSelHnd,Res,nres);
+  //   printf ( " nres    %3i " ,nres   );
+      if (nres<=0)  return  SSERC_noResidues;
+
+    } else {
+
+      //  1b. Get all protein residues
+
+      nres = 0;
+      for (i=0;i<nChains;i++)
+        if (chain[i])
+          nres += chain[i]->nResidues;
+
+      if (nres<=0)  return  SSERC_noResidues;
+
+      Res  = new PResidue[nres];
+      nres = 0;
+      for (i=0;i<nChains;i++)  {
+        chn = chain[i];
+        if (chn)  {
+          k = chn->nResidues;
+          for (j=0;j<k;j++)
+            Res[nres++] = chn->residue[j];
+        }
+      }
+
+
+      if (nres<=0)  {
+        delete[]  Res;
+        return  SSERC_noResidues;
+      }
+
+   }
+
+    //  2. Get C-alphas of all aminoacids
+
+    Ca = new PAtom[nres];
+    k  = 0;
+    for (i=0;i<nres;i++)
+      if (Res[i])  {
+        if (aminoSelHnd>=0 || Res[i]->isAminoacid())  {
+          Ca[i] = Res[i]->GetAtom("CA", " C", "*");
+          k++;
+        } else
+          Ca[i] = NULL;
+        Res[i]->SSE = SSE_None;
+      } else
+        Ca[i] = NULL;
+
+    if (k<=0)  {
+      delete[] Res;
+      delete[] Ca;
+      return   SSERC_noAminoacids;
+    }
+
+
+    //  3. Find all close Calphas - i.e. find the contacts between
+    //     the two equivalent sets of Ca atoms
+
+    contact   = NULL;
+    ncontacts = 0;
+    manager->SeekContacts ( Ca,nres, Ca,nres, 2.0,10.0, 2,
+                            contact,ncontacts,0 );
+    if (ncontacts<=0)  {
+      delete[] Res;
+      delete[] Ca;
+      if (contact)  delete[] contact;
+      return  SSERC_noSSE;
+    }
+
+
+    //  4. Get and initialize memory for analysing the SSE
+
+    GetMatrixMemory ( hbonds,nres,3,0,0 );
+    hbond_atoms = new PPAtom[nres];
+    for (i=0;i<nres;i++)  {
+      hbond_atoms[i] = new PAtom[6];
+      for (j=0;j<6;j++) hbond_atoms[i][j] = NULL;
+      for (j=0;j<3;j++) hbonds     [i][j] = 0;
+    }
+
+
+    //  5.  Loop over all close (in space) residues - excluding those
+    //      that are close in sequence
+
+    for (i=0;i<ncontacts;i++)  {
+      ir1   = contact[i].id2;
+      ir2   = contact[i].id1;
+      irdif = ir1 - ir2;
+      if (irdif>2)  {
+        //  test if there is donor Hbond from residue ir1
+        if (Res[ir1]->isMainchainHBond(Res[ir2]))  {
+          k = 0;
+          while ((hbonds[ir1][k]!=0) && (k<2))  k++;
+          hbonds     [ir1][k]   = -irdif;
+      hbond_atoms[ir1][k]   = Res[ir1]->GetAtom ( "N" );
+      hbond_atoms[ir1][k+3] = Res[ir2]->GetAtom ( "O" );
+        }
+        //  test if there is donor Hbond from residue ir2
+        if (Res[ir2]->isMainchainHBond(Res[ir1]))  {
+      k = 0;
+          while ((hbonds[ir2][k]!=0) && (k<2))  k++;
+          hbonds     [ir2][k]   = irdif;
+      hbond_atoms[ir2][k]   = Res[ir2]->GetAtom ( "N" );
+      hbond_atoms[ir2][k+3] = Res[ir1]->GetAtom ( "O" );
+        }
+      }
+    }
+
+    //  6. Assign the turns - if there is bifurcated bond then the 4-turn
+    //     takes precedence - read the paper to make sense of this
+
+    for (i=0;i<nres;i++)  {
+      k = 0;
+      while ((k<=2) && (hbonds[i][k]!=0))  {
+        if (hbonds[i][k]==-5)  {
+      Res[i-1]->SSE = SSE_5Turn;
+      Res[i-2]->SSE = SSE_5Turn;
+      Res[i-3]->SSE = SSE_5Turn;
+      Res[i-4]->SSE = SSE_5Turn;
+        }
+        if (hbonds[i][k]==-3)  {
+      Res[i-1]->SSE = SSE_3Turn;
+      Res[i-2]->SSE = SSE_3Turn;
+        }
+        k++;
+      }
+    }
+    for (i=0;i<nres;i++)  {
+      k = 0;
+      while ((k<=2) && (hbonds[i][k]!=0))  {
+        if (hbonds[i][k]==-4)  {
+          Res[i-1]->SSE = SSE_4Turn;
+          Res[i-2]->SSE = SSE_4Turn;
+          Res[i-3]->SSE = SSE_4Turn;
+        }
+        k++;
+      }
+    }
+
+
+    //  7. Look for consecutive 4-turns which make alpha helix
+
+    for (i=1;i<nres-3;i++) {
+      if (((Res[i  ]->SSE==SSE_Helix) || (Res[i  ]->SSE==SSE_4Turn)) &&
+          ((Res[i+1]->SSE==SSE_Helix) || (Res[i+1]->SSE==SSE_4Turn)) &&
+          ((Res[i+2]->SSE==SSE_Helix) || (Res[i+2]->SSE==SSE_4Turn)) &&
+          ((Res[i+3]->SSE==SSE_Helix) || (Res[i+3]->SSE==SSE_4Turn)))
+        for (j=i;j<=i+3;j++)  Res[j]->SSE = SSE_Helix;
+    }
+
+    for (i=0;i<nres;i++)  {
+
+      k = 0;
+      while ((k<=2) && (hbonds[i][k]!=0))  {
+
+        irdif = hbonds[i][k];
+        // Test for 'close' hbond
+        j = i + irdif;
+        l = 0;
+        while ((l<=2) && (hbonds[j][l]!=0))  {
+          // Antiparallel strands
+          if (hbonds[j][l]==-irdif)  {
+            Res[i]->SSE = SSE_Strand;
+            Res[j]->SSE = SSE_Strand;
+          }
+          // Parallel strand
+          if (hbonds[j][l]==-irdif-2)  {
+            Res[i-1]->SSE = SSE_Strand;
+            Res[j  ]->SSE = SSE_Strand;
+          }
+          // Parallel beta bulge
+          if (hbonds[j][l]==-irdif-3)  {
+            if (flagBulge) {
+              if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Bulge;
+              if (Res[i-2]->SSE==SSE_None)  Res[i-2]->SSE = SSE_Bulge;
+              if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Bulge;
+            } else  {
+              if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Strand;
+              if (Res[i-2]->SSE==SSE_None)  Res[i-2]->SSE = SSE_Strand;
+              if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Strand;
+            }
+          }
+          l++;
+        }
+        // Test for 'wide' hbond
+        j = i + hbonds[i][k] + 2;
+        if (j<nres)  {
+          l = 0;
+          while ((l<=2) && (hbonds[j][l]!=0))  {
+            // Antiaprallel strands
+            if (hbonds[j][l]==-irdif-4)  {
+              Res[i-1]->SSE = SSE_Strand;
+              Res[j-1]->SSE = SSE_Strand;
+            }
+            // Parallel strands
+            if (hbonds[j][l]==-irdif-2)  {
+              Res[i  ]->SSE = SSE_Strand;
+          Res[j-1]->SSE = SSE_Strand;
+            }
+            l++;
+          }
+        }
+
+        // test for anti-parallel B-bulge between 'close' hbonds
+        j = i + hbonds[i][k] - 1;
+        if (j>=0)  {
+          l = 0;
+          while ((l<=2) && (hbonds[j][l]!=0))  {
+            if (hbonds[j][l]==-irdif+1)  {
+              if (flagBulge)  {
+            if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Bulge;
+            if (Res[j+1]->SSE==SSE_None)  Res[j+1]->SSE = SSE_Bulge;
+            if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Bulge;
+              } else  {
+                if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Strand;
+                if (Res[j+1]->SSE==SSE_None)  Res[j+1]->SSE = SSE_Strand;
+                if (Res[j  ]->SSE==SSE_None)  Res[j  ]->SSE = SSE_Strand;
+              }
+            }
+            l++;
+          }
+        }
+
+        // test for anti-parallel B-bulge between 'wide' hbonds
+        j = i + hbonds[i][k] + 3;
+        if (j<nres)  {
+          l = 0;
+          while ((l<=2) && (hbonds[j][l]!=0))  {
+            if ((hbonds[j][l]==-irdif+5) && (i>0))  {
+              if (flagBulge)  {
+                if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Bulge;
+                if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Bulge;
+                if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Bulge;
+              } else  {
+                if (Res[i-1]->SSE==SSE_None)  Res[i-1]->SSE = SSE_Strand;
+                if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Strand;
+                if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Strand;
+              }
+            } else if (hbonds[j][l]==-irdif-3)  {
+              // and bulge in parallel strand
+          if (flagBulge)  {
+                if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Bulge;
+                if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Bulge;
+                if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Bulge;
+              }
+              else {
+                if (Res[i  ]->SSE==SSE_None)  Res[i  ]->SSE = SSE_Strand;
+                if (Res[j-1]->SSE==SSE_None)  Res[j-1]->SSE = SSE_Strand;
+                if (Res[j-2]->SSE==SSE_None)  Res[j-2]->SSE = SSE_Strand;
+              }
+            }
+            l++;
+          }
+        }
+        k++;
+
+      } // Finish looping over Hbonds for residue (k loop)
+
+    }  // Finish looping over residues ( i loop)
+
+
+    //  8. Free memory
+
+    if (hbond_atoms)  {
+      for (i=0;i<nres;i++)
+        if (hbond_atoms[i])  delete[] hbond_atoms[i];
+      delete[] hbond_atoms;
+    }
+    FreeMatrixMemory ( hbonds,nres,0,0 );
+    if (contact) delete[] contact;
+    if (Res && aminoSelHnd<0) delete[] Res;
+    if (Ca)      delete[] Ca;
+
+    return  SSERC_Ok;
+
+  }
+
+
+  // -------  streaming
+
+  void  Model::write ( io::RFile f )  {
+  int  i,k;
+  byte Version=3;
+
+    f.WriteByte ( &Version );
+
+    ProModel::write ( f );
+
+    f.WriteInt ( &serNum  );
+    f.WriteInt ( &nChains );
+
+    for (i=0;i<nChains;i++)  {
+      if (chain[i])  k = 1;
+               else  k = 0;
+      f.WriteInt ( &k );
+      if (chain[i]) chain[i]->write ( f );
+    }
+
+    hetCompounds.write ( f );
+    helices     .write ( f );
+    sheets      .write ( f );
+    turns       .write ( f );
+    links       .write ( f );
+    linkRs      .write ( f );
+
+  }
+
+  void  Model::read ( io::RFile f )  {
+  int  i,k;
+  byte Version;
+
+    FreeMemory();
+
+    f.ReadByte ( &Version );
+
+    ProModel::read ( f );
+
+    f.ReadInt ( &serNum  );
+    f.ReadInt ( &nChains );
+    nChainsAlloc = nChains;
+    if (nChains>0)  {
+      chain = new PChain[nChainsAlloc];
+      for (i=0;i<nChains;i++)  {
+        f.ReadInt ( &k );
+        if (k)  {
+          chain[i] = newChain();
+          chain[i]->SetModel ( this );
+          chain[i]->read ( f );
+        }
+      }
+    }
+
+    hetCompounds.read ( f );
+    helices     .read ( f );
+    sheets      .read ( f );
+    turns       .read ( f );
+    if (Version>1)  links .read ( f );
+    if (Version>2)  linkRs.read ( f );
+
+  }
+
+  MakeFactoryFunctions(Model)
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_model.h b/mmdb2/mmdb_model.h
new file mode 100644
index 0000000..3e184a9
--- /dev/null
+++ b/mmdb2/mmdb_model.h
@@ -0,0 +1,1073 @@
+//  $Id: mmdb_model.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Model <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::HetCompound  ( description of het compounds  )
+//       ~~~~~~~~~  mmdb::HetCompounds (HETNAM, HETSYN, FORMULA records)
+//                  mmdb::SSContainer  (container for helixes and turns)
+//                  mmdb::Helix        ( helix info                    )
+//                  mmdb::Strand       ( strand info                   )
+//                  mmdb::Sheet        ( sheet info                    )
+//                  mmdb::Sheets       ( container for sheets          )
+//                  mmdb::Turn         ( turn info                     )
+//                  mmdb::LinkContainer   ( container for link data    )
+//                  mmdb::Link            ( link data                  )
+//                  mmdb::LinkRContainer  ( container for refmac link  )
+//                  mmdb::LinkR           ( link data                  )
+//                  mmdb::CisPepContainer ( container for CisPep data  )
+//                  mmdb::CisPep          ( CisPep data                )
+//                  mmdb::Model        ( PDB model                     )
+//
+//  Copyright (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Model__
+#define __MMDB_Model__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_utils.h"
+#include "mmdb_chain.h"
+#include "mmdb_defs.h"
+
+namespace mmdb  {
+
+  //  ====================  HetCompound  =======================
+
+  DefineClass(HetCompound);
+  DefineStreamFunctions(HetCompound);
+
+  class HetCompound : public io::Stream  {
+
+    public :
+
+      ResName  hetID;      // Het identifiers, right-justified
+      pstr     comment;
+      int      nSynonyms;
+      psvector hetSynonym; // synonyms
+      int      compNum;    // component number
+      char     wc;         // '*' for water, otherwise space
+      pstr     Formula;    // formulas
+
+      HetCompound ( cpstr HetName );
+      HetCompound ( io::RPStream Object );
+      ~HetCompound();
+
+      void  AddKeyWord     ( cpstr W, bool Closed );
+      void  HETNAM_PDBDump ( io::RFile f );
+      void  HETSYN_PDBDump ( io::RFile f );
+      void  FORMUL_PDBDump ( io::RFile f );
+
+      void  FormComString  ( pstr & F );
+      void  FormSynString  ( pstr & F );
+      void  FormForString  ( pstr & F );
+
+      void  Copy  ( PHetCompound hetCompound );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void  InitHetCompound ( cpstr HetName );
+      void  FreeMemory      ();
+
+  };
+
+
+  //  ====================  SSContainer  ======================
+
+  DefineClass(SSContainer);
+  DefineStreamFunctions(SSContainer);
+
+  class SSContainer : public ClassContainer  {
+
+    public :
+
+      SSContainer  () : ClassContainer() {}
+      SSContainer  ( io::RPStream Object )
+                      : ClassContainer ( Object ) {}
+      ~SSContainer () {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+  };
+
+
+  //  ====================  Helix  ============================
+
+  DefineClass(Helix);
+  DefineStreamFunctions(Helix);
+
+  class Helix : public ContainerClass  {
+
+    public :
+      int     serNum;      // serial number
+      HelixID helixID;     // helix ID
+      ResName initResName; // name of the helix's initial residue
+      ChainID initChainID; // chain ID for the chain containing the helix
+      int     initSeqNum;  // sequence number of the initial residue
+      InsCode initICode;   // insertion code of the initial residue
+      ResName endResName;  // name of the helix's terminal residue
+      ChainID endChainID;  // chain ID for the chain containing the helix
+      int     endSeqNum;   // sequence number of the terminal residue
+      InsCode endICode;    // insertion code of the terminal residue
+      int     helixClass;  // helix class
+      pstr    comment;     // comment about the helix
+      int     length;      // length of the helix
+
+      Helix ();
+      Helix ( cpstr S );
+      Helix ( io::RPStream Object );
+      ~Helix();
+
+      void       PDBASCIIDump    ( pstr S, int N   );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_Helix; }
+
+      void  Copy  ( PContainerClass Helix );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitHelix();
+
+  };
+
+
+
+  //  ====================  Strand  ============================
+
+  DefineClass(Strand);
+  DefineStreamFunctions(Strand);
+
+  class Strand : public io::Stream  {
+
+    public :
+
+      StrandID sheetID;     // sheet ID
+      int      strandNo;    // strand number
+      ResName  initResName; // name of the strand's initial residue
+      ChainID  initChainID; // chain ID of initial residue in the strand
+      int      initSeqNum;  // sequence number of the initial residue
+      InsCode  initICode;   // insertion code of the initial residue
+      ResName  endResName;  // name of the strand's terminal residue
+      ChainID  endChainID;  // chain ID of terminal residue in the strand
+      int      endSeqNum;   // sequence number of the terminal residue
+      InsCode  endICode;    // insertion code of the terminal residue
+      int      sense;       // sense of strand with respect to previous
+                            //    strand
+      AtomName curAtom;     // registration; atom name in current strand
+      ResName  curResName;  // registration; residue name in current
+                            //    strand
+      ChainID  curChainID;  // registration; chain ID in current strand
+      int      curResSeq;   // registration; res-e seq numb in current
+                            //    strand
+      InsCode  curICode;    // registration; ins code in current strand
+      AtomName prevAtom;    // registration; atom name in previous strand
+      ResName  prevResName; // registration; residue name in previous
+                            //    strand
+      ChainID  prevChainID; // registration; chain ID in previous strand
+      int      prevResSeq;  // registration; res-e seq numb in previous
+                            //    strand
+      InsCode  prevICode;   // registration; ins code in previous strand
+
+      Strand ();
+      Strand ( io::RPStream Object );
+      ~Strand();
+
+      void       PDBASCIIDump    ( pstr  S );
+      void       MakeCIF         ( mmcif::PData CIF );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      int        GetCIF          ( mmcif::PData CIF, cpstr sheet_id );
+
+      void  Copy  ( PStrand Strand );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitStrand();
+
+  };
+
+
+  //  ====================  Sheet  ============================
+
+  DefineClass(Sheet);
+  DefineStreamFunctions(Sheet);
+
+  class Sheet : public io::Stream  {
+
+    public :
+      SheetID  sheetID;   // sheet ID
+      int      nStrands;  // number of strands in the sheet
+      PPStrand strand;    // array of strands
+
+      Sheet ();
+      Sheet ( io::RPStream Object );
+      ~Sheet();
+
+      void  FreeMemory();
+      void  OrderSheet();
+
+      void       PDBASCIIDump    ( io::RFile f );
+      void       MakeCIF         ( mmcif::PData CIF );
+      ERROR_CODE ConvertPDBASCII ( cpstr  S    );
+      int        GetCIF          ( mmcif::PData CIF );
+
+      void  Copy  ( PSheet sheet );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      void  InitSheet      ();
+      void  CIFFindStrands ( mmcif::PData CIF, cpstr Category );
+      void  TryStrand      ( int strand_no );
+      int   GetStrand      ( int strand_no );
+
+  };
+
+
+  //  ====================  Sheets  ============================
+
+  DefineClass(Sheets);
+  DefineStreamFunctions(Sheets);
+
+  class Sheets : public io::Stream  {
+
+    public :
+      int     nSheets;
+      PPSheet sheet;
+
+      Sheets ();
+      Sheets ( io::RPStream Object );
+      ~Sheets();
+
+      void  FreeMemory();
+
+      void       PDBASCIIDump    ( io::RFile f );
+      void       MakeCIF         ( mmcif::PData CIF );
+      ERROR_CODE ConvertPDBASCII ( cpstr  S    );
+      int        GetCIF          ( mmcif::PData CIF );
+
+      void  Copy  ( PSheets Sheets );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      void  InitSheets    ();
+      void  CIFFindSheets ( mmcif::PData CIF, cpstr Category );
+
+  };
+
+
+  //  ====================  Turn  ============================
+
+  DefineClass(Turn);
+  DefineStreamFunctions(Turn);
+
+  class Turn : public ContainerClass  {
+
+    public :
+      int     serNum;      // serial number
+      TurnID  turnID;      // turn ID
+      ResName initResName; // name of the turn's initial residue
+      ChainID initChainID; // chain ID for the chain containing the turn
+      int     initSeqNum;  // sequence number of the initial residue
+      InsCode initICode;   // insertion code of the initial residue
+      ResName endResName;  // name of the turn's terminal residue
+      ChainID endChainID;  // chain ID for the chain containing the turn
+      int     endSeqNum;   // sequence number of the terminal residue
+      InsCode endICode;    // insertion code of the terminal residue
+      pstr    comment;     // comment about the helix
+
+      Turn ();
+      Turn ( cpstr S );
+      Turn ( io::RPStream Object );
+      ~Turn();
+
+      void       PDBASCIIDump    ( pstr S, int N   );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_Turn; }
+
+      void  Copy  ( PContainerClass turn );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitTurn();
+
+  };
+
+
+
+  //  ====================  HetCompounds  =======================
+
+  DefineClass(HetCompounds);
+  DefineStreamFunctions(HetCompounds);
+
+  class HetCompounds : public io::Stream  {
+
+    public :
+
+      int            nHets;
+      PPHetCompound  hetCompound;
+
+      HetCompounds ();
+      HetCompounds ( io::RPStream Object );
+      ~HetCompounds();
+
+      void  FreeMemory    ();
+
+      void  PDBASCIIDump  ( io::RFile f );
+      void  ConvertHETNAM ( cpstr S );
+      void  ConvertHETSYN ( cpstr S );
+      void  ConvertFORMUL ( cpstr S );
+
+      void  MakeCIF       ( mmcif::PData CIF );
+      ERROR_CODE GetCIF   ( mmcif::PData CIF );
+
+      void  Copy  ( PHetCompounds hetCompounds );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      bool Closed;
+
+      void  InitHetCompounds();
+      int   AddHetName      ( cpstr H );
+
+  };
+
+
+  //  ===================  LinkContainer  =====================
+
+  DefineClass(LinkContainer);
+  DefineStreamFunctions(LinkContainer);
+
+  class LinkContainer : public ClassContainer  {
+
+    public :
+
+      LinkContainer  () : ClassContainer() {}
+      LinkContainer  ( io::RPStream Object )
+                       : ClassContainer ( Object ) {}
+      ~LinkContainer () {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+  };
+
+
+  //  ====================  Link  ============================
+
+  DefineClass(Link);
+  DefineStreamFunctions(Link);
+
+  class Link : public ContainerClass  {
+
+    public :
+      AtomName atName1;   // name of 1st linked atom
+      AltLoc   aloc1;     // alternative location of 1st linked atom
+      ResName  resName1;  // residue name of 1st linked atom
+      ChainID  chainID1;  // chain ID of 1st linked atom
+      int      seqNum1;   // sequence number of 1st linked atom
+      InsCode  insCode1;  // insertion code of 1st linked atom
+      AtomName atName2;   // name of 2nd linked atom
+      AltLoc   aloc2;     // alternative location of 2nd linked atom
+      ResName  resName2;  // residue name of 2nd linked atom
+      ChainID  chainID2;  // chain ID of 2nd linked atom
+      int      seqNum2;   // sequence number of 2nd linked atom
+      InsCode  insCode2;  // insertion code of 2nd linked atom
+      int      s1,i1,j1,k1;  // sym id of 1st atom
+      int      s2,i2,j2,k2;  // sym id of 2nd atom
+
+      Link ();
+      Link ( cpstr S );
+      Link ( io::RPStream Object );
+      ~Link();
+
+      void       PDBASCIIDump    ( pstr S, int N   );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_Link; }
+
+      void  Copy  ( PContainerClass link );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitLink();
+
+  };
+
+  //  ===================  LinkRContainer  ====================
+
+  DefineClass(LinkRContainer);
+  DefineStreamFunctions(LinkRContainer);
+
+  class LinkRContainer : public ClassContainer  {
+
+    public :
+
+      LinkRContainer  () : ClassContainer() {}
+      LinkRContainer  ( io::RPStream Object )
+                       : ClassContainer ( Object ) {}
+      ~LinkRContainer () {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+  };
+
+
+  //  ====================  LinkR  ============================
+
+  DefineClass(LinkR);
+  DefineStreamFunctions(LinkR);
+
+  /*
+
+  Garib's
+  LINK             LYS A  27                     PLP A 255                PLPLYS
+  LINK             MAN S   3                     MAN S   4                BETA1-4
+  LINK        C6  BBEN B   1                O1  BMAF S   2                BEN-MAF
+  LINK        OE2 AGLU A 320                C1  AMAF S   2                GLU-MAF
+  LINK        OE2  GLU A  67        1.895   ZN   ZN  R   5                GLU-ZN
+  LINK        NE2  HIS A  71        2.055   ZN   ZN  R   5                HIS-ZN
+  LINK        O    ARG A  69        2.240   NA   NA  R   9                ARG-NA
+
+  Coot's
+  LINKR        O   VAL C 103                NA    NA C 401                VAL-NA
+  LINKR        OD1 ASP D  58                NA    NA D 401                ASP-NA
+  LINKR        O   ALA D  97                NA    NA D 401                ALA-NA
+  LINKR        OG1 THR D  99                NA    NA D 401                THR-NA
+  LINKR        O   SER D 101                NA    NA D 401                SER-NA
+  LINKR        O   VAL D 103                NA    NA D 401                VAL-NA
+
+  PDB's
+  LINK         O   GLY A  49                NA    NA A6001     1555   1555  2.98
+  LINK         OG1 THR A  51                NA    NA A6001     1555   1555  2.72
+  LINK         OD2 ASP A  66                NA    NA A6001     1555   1555  2.72
+  LINK         NE  ARG A  68                NA    NA A6001     1555   1555  2.93
+
+  LINK         NE  ARG A  68                NA    NA A6001     1555   1555  2.93
+  LINK         C21 2EG A   7                 C22 2EG B  19     1555   1555  1.56
+  */
+
+  class LinkR : public ContainerClass  {
+
+    public :
+      LinkRID  linkRID;   // link name
+      AtomName atName1;   // name of 1st linked atom
+      AltLoc   aloc1;     // alternative location of 1st linked atom
+      ResName  resName1;  // residue name of 1st linked atom
+      ChainID  chainID1;  // chain ID of 1st linked atom
+      int      seqNum1;   // sequence number of 1st linked atom
+      InsCode  insCode1;  // insertion code of 1st linked atom
+      AtomName atName2;   // name of 2nd linked atom
+      AltLoc   aloc2;     // alternative location of 2nd linked atom
+      ResName  resName2;  // residue name of 2nd linked atom
+      ChainID  chainID2;  // chain ID of 2nd linked atom
+      int      seqNum2;   // sequence number of 2nd linked atom
+      InsCode  insCode2;  // insertion code of 2nd linked atom
+      realtype dist;      // link distance
+
+      LinkR ();
+      LinkR ( cpstr S );
+      LinkR ( io::RPStream Object );
+      ~LinkR();
+
+      void       PDBASCIIDump    ( pstr S, int N   );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_LinkR; }
+
+      void  Copy  ( PContainerClass LinkR );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitLinkR();
+
+  };
+
+
+
+  //  ===================  CisPepContainer  =====================
+
+  DefineClass(CisPepContainer);
+  DefineStreamFunctions(CisPepContainer);
+
+  class CisPepContainer : public ClassContainer  {
+
+    public :
+
+      CisPepContainer  () : ClassContainer() {}
+      CisPepContainer  ( io::RPStream Object )
+                       : ClassContainer ( Object ) {}
+      ~CisPepContainer () {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+  };
+
+
+  //  =====================  CisPep  ===========================
+
+  DefineClass(CisPep);
+  DefineStreamFunctions(CisPep);
+
+  class CisPep : public ContainerClass  {
+
+    public :
+      int      serNum;   //  record serial number
+      ResName  pep1;     //  residue name
+      ChainID  chainID1; //  chain identifier 1
+      int      seqNum1;  //  residue sequence number 1
+      InsCode  icode1;   //  insertion code 1
+      ResName  pep2;     //  residue name 2
+      ChainID  chainID2; //  chain identifier 2
+      int      seqNum2;  //  residue sequence number 2
+      InsCode  icode2;   //  insertion code 2
+      int      modNum;   //  model number
+      realtype measure;  //  measure of the angle in degrees.
+
+      CisPep ();
+      CisPep ( cpstr S );
+      CisPep ( io::RPStream Object );
+      ~CisPep();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_CisPep; }
+
+      void  Copy  ( PContainerClass cisPep );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitCisPep();
+
+  };
+
+
+
+  //  ====================  Model  ===============================
+
+  enum SSE_RC  {
+    SSERC_Ok           = 0,
+    SSERC_noResidues   = 1,
+    SSERC_noAminoacids = 2,
+    SSERC_noSSE        = 3
+  };
+
+  enum SORT_CHAIN_DIR  {
+    SORT_CHAIN_ChainID_Asc  = 0,
+    SORT_CHAIN_ChainID_Desc = 1
+  };
+
+  DefineFactoryFunctions(Model);
+
+  class Model : public ProModel  {
+
+    friend class Manager;
+    friend class BondManager;
+    friend class SelManager;
+    friend class CoorManager;
+    friend class Root;
+    friend class Chain;
+    friend class Residue;
+    friend class Atom;
+
+    public :
+
+      Model ();  // SetMMDBFile() MUST be used after this constructor!
+      Model ( PManager MMDBF, int serialNum );
+      Model ( io::RPStream Object );
+      ~Model();
+
+      void   SetMMDBManager ( PManager MMDBM, int serialNum );
+      PManager GetCoordHierarchy() { return manager; }
+
+      //   GetChainCreate() returns pointer on chain, whose identifier
+      // is given in chID. If such a chain is absent in the model,
+      // it is created. If enforceUniqueChainID is true and chain with
+      // the same first letter in chain ID already exists in the model,
+      // then the new chain ID will be appended with a serial number
+      // in order to keep it unique. The model will contain chains like
+      // A, A0, A1, A2, ... in such cases.
+      PChain GetChainCreate ( const ChainID chID,
+                              bool enforceUniqueChainID );
+
+      //   CreateChain() creates a new chain with chain ID regardless
+      // the presence of same-ID chains in the model. This function
+      // was introduced only for compatibility with older CCP4
+      // applications and using it in any new developments should be
+      // strictly discouraged.
+      PChain CreateChain    ( const ChainID chID );
+
+      cpstr  GetEntryID ();
+      void   SetEntryID ( const IDCode idCode );
+
+      int    GetSerNum  (); // returns the model's serial number
+
+      cpstr  GetModelID ( pstr modelID );  // returns "/mdl"
+
+      int    GetNumberOfModels  (); // returns TOTAL number of models
+      int    GetNumberOfAtoms   ( bool countTers ); // returns number
+                                                // of atoms in the model
+      int    GetNumberOfResidues(); // returns number of residues in
+                                    // the model
+
+
+      //  ----------------  Extracting chains  --------------------------
+
+      int  GetNumberOfChains();  // returns number of chains in the model
+      bool GetNewChainID ( ChainID chID, int length=1 );
+      //   GetChain() returns pointer on chain, whose identifier
+      // is given in chID. If such a chain is absent in the model,
+      // returns NULL.
+      PChain GetChain ( const ChainID chID );
+      PChain GetChain ( int chainNo ); // returns chainNo-th chain
+                                        // in the model;
+                                        // 0<=chainNo<nChains
+      void GetChainTable ( PPChain & chainTable,
+                           int & NumberOfChains );
+
+      //  ------------------  Deleting chains  --------------------------
+
+      int  DeleteChain        ( const ChainID chID );
+      int  DeleteChain        ( int chainNo );
+      int  DeleteAllChains    ();
+      int  DeleteSolventChains();
+      void TrimChainTable     ();
+
+      //  -------------------  Adding chains  ---------------------------
+
+      int  AddChain ( PChain chn );
+
+      //  --------------------  Sort chains  ----------------------------
+
+      void SortChains ( int sortKey ); // SORT_CHAIN_XXXX
+
+      //  ----------------  Extracting residues  ------------------------
+
+      int GetNumberOfResidues ( const ChainID chainID );
+      int GetNumberOfResidues ( int   chainNo );
+      PResidue GetResidue ( const ChainID chainID, int seqNo,
+                             const InsCode insCode );
+      PResidue GetResidue ( const ChainID chainID, int resNo );
+      PResidue GetResidue ( int   chainNo, int seqNo,
+                             const InsCode insCode );
+      PResidue GetResidue ( int   chainNo, int resNo );
+      int     GetResidueNo ( const ChainID chainID, int seqNo,
+                             const InsCode insCode );
+      int     GetResidueNo ( int   chainNo, int seqNo,
+                             const InsCode insCode );
+      void GetResidueTable ( PPResidue & resTable,
+                             int & NumberOfResidues );
+      void GetResidueTable ( const ChainID chainID,
+                             PPResidue & resTable,
+                             int & NumberOfResidues );
+      void GetResidueTable ( int   chainNo, PPResidue & resTable,
+                             int & NumberOfResidues );
+
+      //  -----------------  Deleting residues  -------------------------
+
+      int DeleteResidue ( const ChainID chainID, int seqNo,
+                          const InsCode insCode );
+      int DeleteResidue ( const ChainID chainID, int resNo );
+      int DeleteResidue ( int   chainNo, int seqNo,
+                          const InsCode insCode );
+      int DeleteResidue ( int   chainNo, int resNo );
+      int DeleteAllResidues ( const ChainID chainID );
+      int DeleteAllResidues ( int   chainNo );
+      int DeleteSolvent     (); // in difference of DeleteSolventChains,
+                                // this will remove all solvent molecules
+                                // from the file rather then
+                                // solely-solvent chains
+      int DeleteAllResidues ();
+
+      //  ------------------  Adding residues  --------------------------
+
+      int AddResidue ( const ChainID chainID, PResidue res );
+      int AddResidue ( int   chainNo, PResidue res );
+
+      //  -------------------  Extracting atoms  ------------------------
+
+      int GetNumberOfAllAtoms(); // returns TOTAL number of atoms in all
+                                 //    models
+      PPAtom    GetAllAtoms (); // returns pointer to Atom array
+
+      int   GetNumberOfAtoms ( const ChainID chainID, int seqNo,
+                               const InsCode insCode );
+      int   GetNumberOfAtoms ( int   chainNo, int seqNo,
+                               const InsCode insCode );
+      int   GetNumberOfAtoms ( const ChainID chainID, int resNo );
+      int   GetNumberOfAtoms ( int   chainNo, int resNo );
+
+      PAtom GetAtom ( const ChainID  chID,
+                      int            seqNo,
+                      const InsCode  insCode,
+                      const AtomName aname,
+                      const Element  elmnt,
+                      const AltLoc   aloc );
+      PAtom GetAtom ( const ChainID  chID,    int seqNo,
+                      const InsCode  insCode, int atomNo );
+      PAtom GetAtom ( const ChainID  chID,
+                      int            resNo,
+                      const AtomName aname,
+                      const Element  elmnt,
+                      const AltLoc   aloc );
+      PAtom GetAtom ( const ChainID  chID,  int resNo, int atomNo );
+      PAtom GetAtom ( int chNo,  int seqNo,
+                      const InsCode  insCode,
+                      const AtomName aname,
+                      const Element  elmnt,
+                      const AltLoc   aloc );
+      PAtom GetAtom ( int chNo,  int seqNo, const InsCode insCode,
+                      int atomNo );
+      PAtom GetAtom ( int chNo,  int resNo,
+                      const AtomName aname,
+                      const Element  elmnt,
+                      const AltLoc aloc );
+      PAtom GetAtom ( int chNo,  int resNo, int atomNo );
+
+      void GetAtomTable ( const ChainID chainID, int seqNo,
+                          const InsCode insCode,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int   chainNo,       int seqNo,
+                          const InsCode insCode,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( const ChainID chainID, int resNo,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable ( int     chainNo,     int resNo,
+                          PPAtom & atomTable, int & NumberOfAtoms );
+
+      //   GetAtomTable1(..) returns atom table without TER atoms and
+      // without NULL atom pointers. NumberOfAtoms returns the actual
+      // number of atom pointers in atomTable.
+      //   atomTable is allocated withing the function. If it was
+      // not set to NULL before calling the function, the latter will
+      // attempt to deallocate it first.
+      //   The application is responsible for deleting atomTable,
+      // however it must not touch atom pointers, i.e. use simply
+      // "delete atomTable;". Never pass atomTable from GetAtomTable(..)
+      // into this function, unless you set it to NULL before doing that.
+      void GetAtomTable1 ( const ChainID chainID, int seqNo,
+                           const InsCode insCode,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int   chainNo, int seqNo,
+                           const InsCode insCode,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( const ChainID chainID, int resNo,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+      void GetAtomTable1 ( int     chainNo,     int resNo,
+                           PPAtom & atomTable, int & NumberOfAtoms );
+
+      void  GetAtomStatistics ( RAtomStat AS );
+      void  CalAtomStatistics ( RAtomStat AS );
+
+
+      //  --------------------  Deleting atoms  -------------------------
+
+      int DeleteAtom ( const ChainID  chID,
+                       int            seqNo,
+                       const InsCode  insCode,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( const ChainID  chID,    int seqNo,
+                       const InsCode  insCode, int atomNo );
+      int DeleteAtom ( const ChainID  chID,
+                       int            resNo,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( const ChainID  chID,  int resNo, int atomNo );
+      int DeleteAtom ( int chNo,  int seqNo,
+                       const InsCode  insCode,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int chNo,  int seqNo, const InsCode insCode,
+                       int atomNo );
+      int DeleteAtom ( int chNo,  int resNo,
+                       const AtomName aname,
+                       const Element  elmnt,
+                       const AltLoc   aloc );
+      int DeleteAtom ( int chNo,  int resNo, int atomNo );
+
+      int DeleteAllAtoms ( const ChainID chID, int seqNo,
+                           const InsCode insCode );
+      int DeleteAllAtoms ( const ChainID chID, int resNo );
+      int DeleteAllAtoms ( const ChainID chID );
+      int DeleteAllAtoms ( int chNo, int seqNo, const InsCode insCode );
+      int DeleteAllAtoms ( int chNo, int resNo );
+      int DeleteAllAtoms ( int chNo );
+      int DeleteAllAtoms ();
+
+      //  DeleteAltLocs() leaves only alternative location with maximal
+      // occupancy, if those are equal or unspecified, the one with
+      // "least" alternative location indicator.
+      //  The function returns the number of deleted. All tables remain
+      // untrimmed, so that explicit trimming or calling
+      // FinishStructEdit() is required.
+      int DeleteAltLocs();
+
+
+      //  ---------------------  Adding atoms  --------------------------
+
+      int AddAtom ( const ChainID chID, int seqNo,
+                    const InsCode insCode, PAtom atom );
+      int AddAtom ( const ChainID chID, int resNo, PAtom  atom );
+      int AddAtom ( int   chNo, int seqNo, const InsCode insCode,
+                    PAtom atom );
+      int AddAtom ( int   chNo, int resNo, PAtom  atom );
+
+
+      //  ---------------------------------------------------------------
+
+      //   ConvertPDBString(..) interprets PDB records DBREF, SEQADV,
+      // SEQRES, MODRES.
+      //   Returns zero if the line was converted, otherwise returns a
+      // non-negative value of Error_XXXX.
+      //   PDBString must be not shorter than 81 characters.
+      ERROR_CODE ConvertPDBString ( pstr PDBString );
+
+      // PDBASCIIDumpPS(..) makes output of PDB primary structure records
+      // excluding cispeps
+      void  PDBASCIIDumpPS   ( io::RFile f );
+
+      // PDBASCIIDumpCP(..) makes output of cispep records
+      void  PDBASCIIDumpCP   ( io::RFile f );
+
+      // PDBASCIIDump(..) makes output of PDB coordinate (ATOM etc.)
+      // records
+      void  PDBASCIIDump     ( io::RFile f );
+
+      void  MakeAtomCIF      ( mmcif::PData CIF );
+      void  MakePSCIF        ( mmcif::PData CIF );
+      ERROR_CODE GetCIF      ( mmcif::PData CIF );
+
+      //   MoveChain(..) adds chain m_chain on the top Chain array.
+      // The pointer on chain is then set to NULL (m_chain=NULL).
+      // If chain_ext is greater than 0, the moved chain will be
+      // forcefully renamed; the new name is composed as the previous
+      // one + underscore + chain_ext (e.g. A_1). If thus generated
+      // name duplicates any of existing chain IDs, or if chain_ext
+      // was set to 0 and there is a duplication of chain IDs, the
+      // name is again modified as above, with the extension number
+      // generated automatically (this may result in IDs like
+      // A_1_10).
+      //   m_atom must give pointer to the Atom array, from which
+      // the atoms belonging to m_chain, are moved to Atom array
+      // given by 'atom', starting from poisition 'atom_index'.
+      // 'atom_index' is then automatically updated to the next
+      // free position in 'atom'.
+      //   Note1: the moved atoms will occupy a continuous range
+      // in 'atom' array; no checks on whether the corresponding
+      // cells are occupied or not, are performed.
+      //   Note2: the 'atom_index' is numbered from 0 on, i.e.
+      // it is equal to atom[atom_index]->index-1; atom[]->index
+      // is assigned automatically.
+      void  MoveChain ( PChain & m_chain, PPAtom m_atom,
+                        PPAtom  atom, int & atom_index,
+                        int  chain_ext );
+
+      void  GetAIndexRange ( int & i1, int & i2 );
+
+      void  MaskAtoms      ( PMask mask );
+      void  MaskResidues   ( PMask mask );
+      void  MaskChains     ( PMask mask );
+      void  UnmaskAtoms    ( PMask mask );
+      void  UnmaskResidues ( PMask mask );
+      void  UnmaskChains   ( PMask mask );
+
+
+      //  ----  Getting Secondary Structure Elements
+
+      int  GetNumberOfHelices ();
+      int  GetNumberOfSheets  ();
+
+      PHelix   GetHelix      ( int serialNum ); // 1<=serNum<=NofHelices
+
+      void     GetSheetID    ( int serialNum, SheetID sheetID );
+                                                   // '\0' for none
+
+      PSheet   GetSheet      ( int   serialNum ); //1<=serNum<=NofSheets
+      PSheet   GetSheet      ( const SheetID sheetID ); // NULL for none
+      int  GetNumberOfStrands ( int   sheetSerNum );
+      int  GetNumberOfStrands ( const SheetID sheetID );
+      PStrand  GetStrand     ( int   sheetSerNum,
+                               int strandSerNum );
+      PStrand  GetStrand     ( const SheetID sheetID,
+                               int strandSerNum );
+
+      inline PSSContainer GetHelices() { return &helices; }
+      inline PSheets      GetSheets () { return &sheets;  }
+
+      void  RemoveSecStructure();
+      int   CalcSecStructure  ( bool flagBulge=true,
+                                int aminoSelHnd=-1 );
+  //    int   CalcSecStructure  ( bool flagBulge=true );
+
+      PHetCompounds GetHetInfo() { return &hetCompounds; }
+      void  RemoveHetInfo     ();
+
+
+      //  ----  Working Links
+
+      int    GetNumberOfLinks ();
+      PLink          GetLink ( int serialNum ); // 1<=serNum<=NofLinks
+      PLinkContainer GetLinks() { return &links; }
+
+      void   RemoveLinks();
+      void   AddLink    ( PLink link );
+
+      //  ----  Working Refmac Links
+
+      int    GetNumberOfLinkRs ();
+      PLinkR          GetLinkR ( int serialNum ); // 1<=serNum<=NofLinks
+      PLinkRContainer GetLinkRs() { return &linkRs; }
+
+      void   RemoveLinkRs();
+      void   AddLinkR   ( PLinkR linkR );
+
+
+      //  ----  Working CisPeps
+
+      int       GetNumberOfCisPeps();
+      PCisPep          GetCisPep ( int CisPepNum );
+      PCisPepContainer GetCisPeps() { return &cisPeps; }
+
+      void  RemoveCisPeps();
+      void  AddCisPep    ( PCisPep cisPep );
+
+
+
+      void  ApplyTransform ( mat44 & TMatrix );  // transforms all
+                                        // coordinates by multiplying
+                                        // with matrix TMatrix
+
+      bool isInSelection ( int selHnd );
+
+
+      // -------  user-defined data handlers
+      int   PutUDData ( int UDDhandle, int      iudd );
+      int   PutUDData ( int UDDhandle, realtype rudd );
+      int   PutUDData ( int UDDhandle, cpstr    sudd );
+
+      int   GetUDData ( int UDDhandle, int      & iudd );
+      int   GetUDData ( int UDDhandle, realtype & rudd );
+      int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+      int   GetUDData ( int UDDhandle, pstr     & sudd );
+
+
+      void  Copy             ( PModel model );
+      void  CopyHets         ( PModel model );
+      void  CopySecStructure ( PModel model );
+      void  CopyLinks        ( PModel model );
+      void  CopyLinkRs       ( PModel model );
+      void  CopyCisPeps      ( PModel model );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      int             serNum;       // the model serial number
+      PManager        manager;      // pointer to mmdbmanager class
+
+      HetCompounds    hetCompounds; // information on heterocompounds
+      SSContainer     helices;      // information on helices
+      Sheets          sheets;       // information on sheets
+      SSContainer     turns;        // information on turns
+      LinkContainer   links;        // information on links
+      LinkRContainer  linkRs;       // information on refmac links
+      CisPepContainer cisPeps;      // information on cispeps
+
+      int             nChains;      // number of chains
+      int             nChainsAlloc; // actual length of Chain[]
+      PPChain         chain;        // array of chains
+
+      bool            Exclude;      // used internally
+
+      void  InitModel        ();
+      void  FreeMemory       ();
+      void  ExpandChainArray ( int nOfChains );
+      ERROR_CODE GetCIFPSClass ( mmcif::PData CIF, int ClassID );
+
+      //   _ExcludeChain(..) excludes (but does not dispose!) a chain
+      // from the model. Returns 1 if the chain gets empty and 0
+      // otherwise.
+      int   _ExcludeChain ( const ChainID chainID );
+
+      //  _copy(PModel) does not copy atoms! -- not for use in
+      // applications
+      void  _copy ( PModel Model );
+
+      //  _copy(PModel,PPAtom,int&) does copy atoms into array 'atom'
+      // starting from position atom_index. 'atom' should be able to
+      // accept all new atoms - no checks on the length of 'atom'
+      // is being made. This function should not be used in applications.
+      void  _copy ( PModel Model, PPAtom  atom, int & atom_index );
+
+      void  CheckInAtoms  ();
+
+  };
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_root.cpp b/mmdb2/mmdb_root.cpp
new file mode 100644
index 0000000..3a98edb
--- /dev/null
+++ b/mmdb2/mmdb_root.cpp
@@ -0,0 +1,3054 @@
+//  $Id: mmdb_root.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    14.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Root <implementation>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Root
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include "string.h"
+#include "stdlib.h"
+
+#include "mmdb_root.h"
+#include "mmdb_atom.h"
+#include "mmdb_mmcif_.h"
+#include "mmdb_cifdefs.h"
+#include "mmdb_tables.h"
+#include "mmdb_defs.h"
+
+
+namespace mmdb  {
+
+  //  =====================   Root   =======================
+
+  Root::Root() : UDData()  {
+    InitMMDBRoot();
+  }
+
+  Root::Root ( io::RPStream Object ) : UDData(Object)  {
+    InitMMDBRoot();
+  }
+
+  Root::~Root()  {
+    FreeFileMemory();
+  }
+
+  void  Root::InitMMDBRoot()  {
+    nModels = 0;
+    model   = NULL;
+    nAtoms  = 0;
+    atmLen  = 0;
+    atom    = NULL;
+    CIF     = NULL;
+    crModel = NULL;
+    crChain = NULL;
+    crRes   = NULL;
+    lcount  = 0;
+    strcpy ( S,"" );
+  //  Flags   = 0x00000000;           // no special effects
+    Flags   = MMDBF_IgnoreElement;  // done at request for default
+    FType   = MMDB_FILE_Undefined;  // undefined file operation
+    Exclude = true;
+    ignoreRemarks     = false;  // used temporarily
+    allowDuplChID     = false;  // used temporarily
+    enforceUniqueChID = false;  // used temporarily
+    modelCnt          = 0;      // used only at reading files
+  }
+
+
+  void  Root::FreeCoordMemory()  {
+    //int i;
+
+  /*
+    //   All atoms are kept in array Atom. Models, chains
+    // and residues have only references to Atom and
+    // they do not dispose Atoms when disposed themselves.
+    //   It is important, however, to dispose Atom at
+    // still alive residues, because each atom wipes out
+    // reference to itself from the corresponding residue
+    // before it dies.
+    if (Atom)  {
+      for (i=0;i<atmLen;i++)
+        if (atom[i]) delete atom[i];
+      delete Atom;
+    }
+    Atom    = NULL;
+    atmLen  = 0;
+    nAtoms  = 0;
+  */
+    DeleteAllModels();
+    if (model)  delete[] model;
+    model   = NULL;
+    nModels = 0;
+
+    crModel = NULL;
+    crChain = NULL;
+    crRes   = NULL;
+
+    if (atom)  delete[] atom;
+
+    atom    = NULL;
+    atmLen  = 0;
+    nAtoms  = 0;
+
+    modelCnt = 0;
+
+  }
+
+  void  Root::FreeFileMemory()  {
+
+    FreeCoordMemory  ();
+    title.FreeMemory ( false );
+    cryst.FreeMemory ();
+
+    SA      .FreeContainer();
+    Footnote.FreeContainer();
+    SB      .FreeContainer();
+    SC      .FreeContainer();
+
+    if (CIF)  delete CIF;
+    CIF = NULL;
+
+    lcount = 0;
+    S[0]   = char(0);
+
+  }
+
+  // virtual to be served by MMDB manager classes
+  void Root::ResetManager() {
+    cryst.Reset();
+  }
+
+  void Root::SetFlag ( word Flag )  {
+    Flags |= Flag;
+    ignoreSegID            = (Flags & MMDBF_IgnoreSegID            ) != 0;
+    ignoreElement          = (Flags & MMDBF_IgnoreElement          ) != 0;
+    ignoreCharge           = (Flags & MMDBF_IgnoreCharge           ) != 0;
+    ignoreNonCoorPDBErrors = (Flags & MMDBF_IgnoreNonCoorPDBErrors ) != 0;
+    ignoreUnmatch          = (Flags & MMDBF_IgnoreUnmatch          ) != 0;
+    allowDuplChID          = (Flags & MMDBF_AllowDuplChainID       ) != 0;
+    enforceUniqueChID      = (Flags & MMDBF_EnforceUniqueChainID   ) != 0;
+    cryst.processSG        = (Flags & MMDBF_DoNotProcessSpaceGroup ) == 0;
+    cryst.fixSpaceGroup    = (Flags & MMDBF_FixSpaceGroup          ) != 0;
+  }
+
+  void Root::RemoveFlag ( word Flag )  {
+    Flags &= ~Flag;
+    ignoreSegID            = (Flags & MMDBF_IgnoreSegID            ) != 0;
+    ignoreElement          = (Flags & MMDBF_IgnoreElement          ) != 0;
+    ignoreCharge           = (Flags & MMDBF_IgnoreCharge           ) != 0;
+    ignoreNonCoorPDBErrors = (Flags & MMDBF_IgnoreNonCoorPDBErrors ) != 0;
+    ignoreUnmatch          = (Flags & MMDBF_IgnoreUnmatch          ) != 0;
+    allowDuplChID          = (Flags & MMDBF_AllowDuplChainID       ) != 0;
+    enforceUniqueChID      = (Flags & MMDBF_EnforceUniqueChainID   ) != 0;
+    cryst.processSG        = (Flags & MMDBF_DoNotProcessSpaceGroup ) == 0;
+    cryst.fixSpaceGroup    = (Flags & MMDBF_FixSpaceGroup          ) != 0;
+  }
+
+
+  ERROR_CODE Root::ReadPDBASCII1 ( cpstr PDBLFName, io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( PDBLFName );
+    if (FName)  return ReadPDBASCII ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  void Root::ReadPDBLine ( io::RFile f, pstr L, int maxlen )  {
+  int     i;
+  bool Done;
+    do {
+      f.ReadLine ( L,maxlen );
+      Done = true;
+      if (ignoreRemarks)  {
+        if (!strncasecmp(L,"REMARK",6))  Done = false;
+      }
+      if (Flags & MMDBF_IgnoreBlankLines)  {
+        i = 0;
+        while (L[i] && (L[i]==' '))  i++;
+        if (!L[i])  Done = false;
+      }
+      if ((Flags & MMDBF_IgnoreHash) && (L[0]=='#'))
+        Done = false;
+    } while ((!f.FileEnd()) && (!Done));
+    PadSpaces  ( L,80 );
+  }
+
+  ERROR_CODE Root::ReadPDBASCII ( cpstr PDBFileName, io::GZ_MODE gzipMode )  {
+  io::File   f;
+  ERROR_CODE RC;
+
+    //  open the file as ASCII for reading
+    //  opening it in pseudo-binary mode helps reading various
+    //  line terminators for files coming from different platforms
+    f.assign ( PDBFileName,false,false,gzipMode );
+
+    if (f.reset(true)) {
+
+      RC = ReadPDBASCII ( f );
+      f.shut();
+
+    } else  {
+
+      RC =  Error_CantOpenFile;
+      ResetManager  ();
+      FreeFileMemory();
+      FType = MMDB_FILE_PDB;
+
+    }
+
+    return RC;
+
+  }
+
+
+  ERROR_CODE Root::ReadPDBASCII ( io::RFile f )  {
+  PContString contString;
+  word        cleanKey;
+  int         modNum;
+  bool        fend;
+  ERROR_CODE  RC;
+
+    //  remove previous data
+    ResetManager  ();
+    FreeFileMemory();
+
+    FType = MMDB_FILE_PDB;
+    SetFlag ( 0 );
+
+    if (f.FileEnd())  return Error_EmptyFile;
+
+    lcount = 1;  // line counter
+
+    // read title section
+    RC = Error_NoError;
+    ReadPDBLine ( f,S,sizeof(S) );
+    if (Flags & MMDBF_EnforceSpaces)  EnforceSpaces ( S );
+    do  {
+      if (!strncmp(S,"FTNOTE",6))  {
+        contString = new ContString(S);
+        Footnote.AddData ( contString );
+      } else  {
+        RC = title.ConvertPDBString(S);
+        if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+          RC = Error_NoError;
+        if (RC)  break;
+      }
+      fend = f.FileEnd();
+      if (!fend)  {
+        ReadPDBLine ( f,S,sizeof(S) );
+        lcount++;
+      }
+    } while (!fend);
+
+    title.GetResolution(); // only to fetch resolution from remarks
+
+    if (RC!=Error_WrongSection)  return RC;
+
+    ignoreRemarks = (Flags & MMDBF_IgnoreRemarks)!=0;
+
+    // read primary structure section
+    SwitchModel ( 1 );
+    if (!crModel)  return Error_GeneralError1;
+    do {
+      if (!strncmp(S,"FTNOTE",6))  {
+        contString = new ContString(S);
+        Footnote.AddData ( contString );
+      } else  {
+        RC = crModel->ConvertPDBString ( S );
+        if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+          RC = Error_NoError;
+        if (RC)  break;
+      }
+      fend = f.FileEnd();
+      if (!fend)  {
+        ReadPDBLine ( f,S,sizeof(S) );
+        title.TrimInput ( S );
+        lcount++;
+      }
+    } while (!fend);
+
+    if (RC!=Error_WrongSection)  return RC;
+
+    // temporary solution: the rest of file is stored
+    // in the form of strings
+    while (!f.FileEnd()          &&
+           strncmp(S,"CRYST" ,5) &&
+           strncmp(S,"ORIGX" ,5) &&
+           strncmp(S,"SCALE" ,5) &&
+           strncmp(S,"MTRIX" ,5) &&
+           strncmp(S,"TVECT" ,5) &&
+           strncmp(S,"MODEL ",6) &&
+           strncmp(S,"ATOM  ",6) &&
+           strncmp(S,"SIGATM",6) &&
+           strncmp(S,"ANISOU",6) &&
+           strncmp(S,"SIGUIJ",6) &&
+           strncmp(S,"TER   ",6) &&
+           strncmp(S,"HETATM",6) &&
+           strncmp(S,"ENDMDL",6))  {
+      if (!strncmp(S,"LINK  ",6))
+        crModel->ConvertPDBString ( S );
+      else if (!strncmp(S,"LINKR ",6))
+        crModel->ConvertPDBString ( S );
+      else if (!strncmp(S,"CISPEP",6)) {
+        GetInteger ( modNum,&(S[43]),3 );
+        if (modNum<=0)  modNum = 1;
+        if (modNum!=1)  SwitchModel ( modNum );
+        crModel->ConvertPDBString ( S );
+        if (modNum!=1)  SwitchModel ( 1 );
+      } else  {
+        contString = new ContString(S);
+        SA.AddData ( contString );
+      }
+      ReadPDBLine ( f,S,sizeof(S) );
+      title.TrimInput ( S );
+      lcount++;
+    }
+
+    // read crystallographic information section
+    do {
+      RC = cryst.ConvertPDBString ( S );
+      if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+        RC = Error_NoError;
+      if (RC)  break;
+      fend = f.FileEnd();
+      if (!fend)  {
+        ReadPDBLine ( f,S,sizeof(S) );
+        title.TrimInput ( S );
+        lcount++;
+      }
+    } while (!fend);
+
+    if (!RC)  {
+      RC = cryst.ConvertPDBString ( S );
+      if ((RC!=Error_WrongSection) && ignoreNonCoorPDBErrors)
+        RC = Error_WrongSection;
+    }
+
+    cryst.CalcCoordTransforms();
+    if (Flags & MMDBF_SimRWBROOK)
+      cryst.RWBROOKReadPrintout();
+
+    if (RC!=Error_WrongSection)  return RC;
+
+    // temporary solution: the rest of file is stored
+    // in the form of strings
+    while (!f.FileEnd()          &&
+           strncmp(S,"MODEL ",6) &&
+           strncmp(S,"ATOM  ",6) &&
+           strncmp(S,"SIGATM",6) &&
+           strncmp(S,"ANISOU",6) &&
+           strncmp(S,"SIGUIJ",6) &&
+           strncmp(S,"TER   ",6) &&
+           strncmp(S,"HETATM",6) &&
+           strncmp(S,"ENDMDL",6))  {
+      contString = new ContString(S);
+      SB.AddData ( contString );
+      ReadPDBLine ( f,S,sizeof(S) );
+      title.TrimInput ( S );
+      lcount++;
+    }
+
+    if (Flags & MMDBF_NoCoordRead)  return Error_NoError;
+
+    // read coordinate section
+    RC = Error_NoError;
+    do {
+      RC = ReadPDBAtom ( S );
+      if (RC)  break;
+      fend = f.FileEnd();
+      if (!fend)  {
+        ReadPDBLine ( f,S,sizeof(S) );
+        title.TrimInput ( S );
+        lcount++;
+      }
+    } while (!fend);
+  //  if (!RC)
+  //    RC = ReadPDBAtom(S);
+  //  commented on 28.05.2004, it appears that "CHAIN_ORDER" should not
+  //  be enforced here
+  //  cleanKey = PDBCLEAN_ATNAME | PDBCLEAN_CHAIN_ORDER;
+    cleanKey = 0x00000000;
+    if (Flags & MMDBF_EnforceAtomNames)
+      cleanKey = PDBCLEAN_ATNAME;
+    if (Flags & MMDBF_AutoSerials)
+      cleanKey |= PDBCLEAN_SERIAL;
+
+    if (cleanKey)
+      PDBCleanup ( cleanKey );
+
+    if ((!f.FileEnd()) && (RC!=Error_WrongSection))  return RC;
+
+    // temporary solution: the rest of file is stored
+    // in the form of strings
+    while (!f.FileEnd())  {
+      if (strncmp(S,"END   ",6))  {  // END is added automatically
+        contString = new ContString(S);
+        SC.AddData ( contString );
+      }
+      ReadPDBLine ( f,S,sizeof(S) );
+      title.TrimInput ( S );
+      lcount++;
+    }
+    lcount--;  // last line was not read
+
+    return Error_NoError;
+
+  }
+
+
+  ERROR_CODE Root::ReadCIFASCII1 ( cpstr CIFLFName, io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( CIFLFName );
+    if (FName)  return ReadCIFASCII ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::ReadCIFASCII ( cpstr CIFFileName, io::GZ_MODE gzipMode )  {
+  io::File   f;
+  ERROR_CODE rc;
+
+    //  open the file as ASCII for reading
+    //  opening it in pseudo-binary mode helps reading various
+    //  line terminators for files coming from different platforms
+    f.assign ( CIFFileName,false,false,gzipMode );
+
+    if (f.reset(true)) {
+      rc = ReadCIFASCII ( f );
+      f.shut();
+    } else
+      rc = Error_CantOpenFile;
+
+    return rc;
+
+  }
+
+  ERROR_CODE Root::ReadCIFASCII ( io::RFile f )  {
+  int        W;
+  ERROR_CODE RC;
+
+    //  remove previous data
+    ResetManager  ();
+    FreeFileMemory();
+    FType = MMDB_FILE_CIF;
+
+    SetFlag ( 0 );
+
+    CIFErrorLocation[0] = char(0);  // CIF reading phase
+
+    lcount = 0;  // line counter
+    S[0]   = char(0);
+
+    if (f.FileEnd())
+      return Error_EmptyFile;
+
+    if (!CIF)  CIF = new mmcif::Data();
+    CIF->SetStopOnWarning  ( true );
+    CIF->SetPrintWarnings  ( (Flags & MMDBF_PrintCIFWarnings)!=0 );
+    W = CIF->ReadMMCIFData ( f,S,lcount );
+
+    if (W)  {
+      if (W == mmcif::CIFRC_NoDataLine)      return Error_NotACIFFile;
+      if (W & mmcif::CIFW_UnrecognizedItems) return Error_UnrecognCIFItems;
+      if (W & mmcif::CIFW_MissingField)      return Error_MissingCIFField;
+      if (W & mmcif::CIFW_EmptyLoop)         return Error_EmptyCIFLoop;
+      if (W & mmcif::CIFW_UnexpectedEOF)     return Error_UnexpEndOfCIF;
+      if (W & mmcif::CIFW_LoopFieldMissing)  return Error_MissgCIFLoopField;
+      if (W & mmcif::CIFW_NotAStructure)     return Error_NotACIFStructure;
+      if (W & mmcif::CIFW_NotALoop)          return Error_NotACIFLoop;
+      return Error_Unknown;
+    }
+
+    RC = ReadFromCIF ( CIF );
+    if (CIF)  {
+      delete CIF;
+      CIF = NULL;
+    }
+
+    return RC;
+
+  }
+
+
+  ERROR_CODE Root::ReadFromCIF ( mmcif::PData CIFD )  {
+  mmcif::PLoop  Loop1,Loop2;
+  pstr          F,FC;
+  word          cleanKey;
+  int           i,l,j,n,retc;
+  ERROR_CODE    RC;
+
+    RC = title.GetCIF ( CIFD );
+
+    if (RC!=Error_NoError)  {
+      CIFD->Optimize();
+      return RC;
+    }
+
+    SwitchModel ( 1 );
+    if (!crModel)  return Error_GeneralError1;
+    RC = crModel->GetCIF ( CIFD );
+    if (RC!=Error_NoError)  {
+      CIFD->Optimize();
+      return RC;
+    }
+
+    RC = cryst.GetCIF ( CIFD );
+    if (RC!=Error_NoError)  {
+      CIFD->Optimize();
+      return RC;
+    }
+    cryst.CalcCoordTransforms();
+    if (Flags & MMDBF_SimRWBROOK)
+      cryst.RWBROOKReadPrintout();
+
+    RC = ReadCIFAtom ( CIFD );
+
+    Loop1 = CIFD->GetLoop ( CIFCAT_ENTITY      );
+    Loop2 = CIFD->GetLoop ( CIFCAT_STRUCT_ASYM );
+    if (Loop1 && Loop2)  {
+      // make 'Het' atoms
+      l = Loop1->GetLoopLength();
+      n = Loop2->GetLoopLength();
+      for (i=0;i<l;i++)  {
+        F = Loop1->GetString ( CIFTAG_TYPE,i,retc );
+        if (F && (!retc))  {
+          if (!strcasecmp(F,"non-polymer"))  {
+            F = Loop1->GetString ( CIFTAG_ID,i,retc );
+            if (F && (!retc))
+              for (j=0;j<n;j++)  {
+                FC = Loop2->GetString ( CIFTAG_ENTITY_ID,j,retc );
+                if (FC && (!retc))  {
+                  if (!strcasecmp(FC,F))  {
+                    FC = Loop2->GetString ( CIFTAG_ID,j,retc );
+                    if (FC && (!retc))
+                      MakeHetAtoms ( FC,true );
+                  }
+                }
+              }
+          }
+        }
+      }
+    }
+
+    if (RC==Error_NoError)  {
+      //  deleting these CIF loops here is a temporary solution
+      // taken in order to avoid mess at rewriting the CIF file.
+      CIFD->DeleteLoop ( CIFCAT_ATOM_SITE           );
+      CIFD->DeleteLoop ( CIFCAT_ATOM_SITE_ANISOTROP );
+      CIFD->Optimize   ();
+    }
+
+    cleanKey = 0x00000000;
+    if (Flags & MMDBF_EnforceAtomNames)
+      cleanKey = PDBCLEAN_ATNAME;
+    if (Flags & MMDBF_AutoSerials)
+      cleanKey |= PDBCLEAN_SERIAL;
+    if (cleanKey)
+      PDBCleanup ( cleanKey );
+
+    return RC;
+
+  }
+
+  ERROR_CODE Root::ReadCoorFile1 ( cpstr LFName, io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( LFName );
+    if (FName)  return ReadCoorFile ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::ReadCoorFile ( cpstr CFName, io::GZ_MODE gzipMode )  {
+  // auto format recognition
+  int     kin;
+  bool IBL;
+
+    kin = isMMDBBIN ( CFName,gzipMode );
+    if (kin==Error_EmptyFile)
+                return Error_EmptyFile;
+    if (kin<0)  return Error_CantOpenFile;
+
+    if (kin==0) return  ReadMMDBF ( CFName,gzipMode );
+
+    IBL = ((Flags & MMDBF_IgnoreBlankLines)!=0);
+    if (isPDB(CFName,gzipMode,IBL)==0)
+      return ReadPDBASCII ( CFName,gzipMode );
+    if (mmcif::isCIF(CFName,gzipMode)==0)
+      return ReadCIFASCII ( CFName,gzipMode );
+
+    return Error_ForeignFile;
+
+  }
+
+
+  ERROR_CODE Root::ReadCoorFile ( io::RFile f )  {
+  // auto format recognition
+  int  kin;
+  bool IBL;
+
+    kin = isMMDBBIN ( f );
+    f.reset ( true );
+    if (kin==Error_EmptyFile)
+                return Error_EmptyFile;
+    if (kin<0)  return Error_CantOpenFile;
+
+    if (kin==0) return  ReadMMDBF ( f );
+
+    IBL = ((Flags & MMDBF_IgnoreBlankLines)!=0);
+    kin = isPDB ( f,IBL );
+    f.reset ( true );
+    if (kin==0)
+      return ReadPDBASCII ( f );
+
+    kin = mmcif::isCIF ( f );
+    f.reset ( true );
+    if (kin==0)
+      return ReadCIFASCII ( f );
+
+    return Error_ForeignFile;
+
+  }
+
+
+  word  Root::PDBCleanup ( word CleanKey )  {
+  //  cleans coordinate part to comply with PDB standards:
+  //
+  //    CleanKey          Action
+  //  PDBCLEAN_ATNAME  pads atom names with spaces to form 4-symbol names
+  //  PDBCLEAN_TER     inserts TER cards in the end of each chain
+  //  PDBCLEAN_CHAIN   generates 1-character chain ids instead of
+  //                   those many-character
+  //  PDBCLEAN_CHAIN_STRONG generates 1-character chain ids starting
+  //                   from 'A' on for all ids, including single-char
+  //  PDBCLEAN_ALTCODE generates 1-character alternative codes instead
+  //                   of those many-character
+  //  PDBCLEAN_ALTCODE_STRONG generates 1-character alternative codes
+  //                   from 'A' on for all codes, including
+  //                   single-character ones
+  //  PDBCLEAN_SERIAL  puts serial numbers in due order
+  //  PDBCLEAN_INDEX   reorders the internal index of atoms such that
+  //                   it follows the actual order of atoms in
+  //                   the object hierarchy
+  //  PDBCLEAN_SEQNUM  renumbers all residues so that they go
+  //                   incrementally-by-one without insertion codes
+  //  PDBCLEAN_CHAIN_ORDER puts chains in order of atom's serial numbers
+  //  PDBCLEAN_SOLVENT moves solvent chains at the end of each model
+  //  PDBCLEAN_ELEMENT calculates PDB element names where they are not
+  //                   found in the chemical element table
+  //  PDBCLEAN_ELEMENT_STRONG  calculates all chemical element names
+  //
+  //  Return codes (as bits):
+  //  0                Ok
+  //  PDBCLEAN_CHAIN   too many chains for assigning them 1-letter codes
+  //  PDBCLEAN_ATNAME  element names were not available
+  //  PDBCLEAN_ALTCODE too many alternative codes encountered.
+  //
+  word      RC;
+  int       i,j,k,nal,nch,nr, nch1,nch2;
+  char      c;
+  AltLoc  * altLoc;
+  ChainID * chain_ID;
+  char      aLoc [257];
+  char      chnID[257];
+  int       modN,modl;
+  PPAtom    atom1;
+  PPChain   Chain1,Chain2;
+  PModel    crModel0;
+  PChain    crChain0;
+  PResidue  crRes0;
+  PAtom     A;
+  pstr      chID;
+  ChainID   chainID;
+  bool      NewChain,Done,Solvent;
+
+    RC = 0;
+    if (nAtoms<=0)  return RC;
+
+    if (CleanKey & PDBCLEAN_ATNAME)
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])
+          if (!atom[i]->MakePDBAtomName())  RC |= PDBCLEAN_ATNAME;
+
+    k = -1;
+
+    if (CleanKey & PDBCLEAN_TER)  {
+      modN     = -1;
+      crModel0 = crModel;
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          modl = atom[i]->GetModelNum();
+          chID = atom[i]->GetChainID ();
+          if (modN<0)  {
+            modN = modl;
+            SwitchModel ( modN );
+            if (chID)  strcpy ( chainID,chID );
+                 else  chainID[0] = char(0);
+          } else  {
+            if (modN!=modl)   NewChain = true;
+            else if (chID)    NewChain = strcmp(chID,chainID)!=0;
+                        else  NewChain = chainID[0]!=char(0);
+            if (NewChain)  {
+              if (k>=0)  {
+                if ((!atom[k]->Ter) && (!atom[k]->Het))  {
+                  // insert 'Ter' before atom in position 'i'
+                  PutAtom ( -(i+1),atom[k]->serNum+1,pstr("TER"),
+                            atom[k]->GetResName(),atom[k]->GetChainID(),
+                            atom[k]->GetSeqNum (),atom[k]->GetInsCode(),
+                            pstr(" "),pstr(" "),pstr(" ") );
+                  atom[i]->MakeTer();
+                }
+              }
+              modN = modl;
+              SwitchModel ( modN );
+              if (chID)  strcpy ( chainID,chID );
+                   else  chainID[0] = char(0);
+            }
+          }
+          k = i;
+        }
+
+      if (k>=0)  {
+        if ((!atom[k]->Ter) && (!atom[k]->Het))  {  // add last TER
+          i = nAtoms;
+          SwitchModel ( atom[k]->GetModelNum() );
+          PutAtom ( 0,nAtoms+1,pstr("TER"),atom[k]->GetResName(),
+                    atom[k]->GetChainID(),atom[k]->GetSeqNum(),
+                    atom[k]->GetInsCode(),pstr(" "),pstr(" "),
+                    pstr(" ") );
+          atom[i]->MakeTer();
+        }
+      }
+
+      crModel = crModel0;
+    }
+
+
+    if (CleanKey & (PDBCLEAN_CHAIN | PDBCLEAN_CHAIN_STRONG))  {
+      chain_ID = new ChainID[256];
+      for (i=0;i<nModels;i++)
+        if (model[i])  {
+          for (j=0;j<256;j++)  {
+            strcpy ( chain_ID[j]," " );
+            chnID[j] = char(0);
+          }
+          chnID[256] = char(0);
+          nch = 0;
+          for (j=0;j<model[i]->nChains;j++)  {
+            crChain0 = model[i]->chain[j];
+            if (crChain0)  {
+              if (!crChain0->chainID[0])
+                strcpy ( crChain0->chainID," " );
+              k = 0;
+              while ((k<nch) && (strcmp(chain_ID[k],crChain0->chainID)))
+                k++;
+              if (k>=nch)  {
+                if (nch>=255)  RC |= PDBCLEAN_CHAIN;
+                else  {
+                  strcpy ( chain_ID[nch],crChain0->chainID );
+                  if (!chain_ID[nch][1])
+                    chnID[nch] = chain_ID[nch][0];
+                  nch++;
+                }
+              }
+            }
+          }
+          c = 'A';
+          if (CleanKey & PDBCLEAN_CHAIN_STRONG)  {
+            // rename all chains through from A to Z
+            for (k=0;k<nch;k++)  {
+              chnID[k] = c;
+              c = char(int(c)+1);
+            }
+          } else  {
+            // rename only multi-character chain IDs
+            for (j=0;(j<nch) && (k<256);j++)  {
+              k = 0;
+              do  {
+                while ((k<nch) && (chnID[k]!=c))  k++;
+                if (k<nch)  c = char(int(c)+1);
+              } while (k<nch);
+              k = 0;
+              while ((k<256) && (chnID[k]))  k++;
+              if (k<256)  {
+                chnID[k] = c;
+                c = char(int(c)+1);
+              }
+            }
+          }
+          // assign new chain IDs
+          for (j=0;j<model[i]->nChains;j++)  {
+            crChain0 = model[i]->chain[j];
+            if (crChain0)  {
+              k = 0;
+              while ((k<nch) && (strcmp(chain_ID[k],crChain0->chainID)))
+                k++;
+              strcpy ( crChain0->prevChainID,crChain0->chainID );
+              crChain0->chainID[0] = chnID[k];
+              crChain0->chainID[1] = char(0);
+            }
+          }
+        }
+      delete[] chain_ID;
+    }
+
+
+    if (CleanKey & (PDBCLEAN_ALTCODE | PDBCLEAN_ALTCODE_STRONG))  {
+      altLoc = new AltLoc[256];
+      for (i=0;i<256;i++)  {
+        strcpy ( altLoc[i]," " );
+        aLoc[i] = char(0);
+      }
+      aLoc[0]   = ' ';
+      aLoc[256] = char(0);
+      nal = 1;
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->altLoc[0])  strcpy ( atom[i]->altLoc," " );
+          else  {
+            k = 0;
+            while ((k<nal) && (strcmp(altLoc[k],atom[i]->altLoc)))  k++;
+            if (k>=nal)  {
+              if (nal>=255)  RC |= PDBCLEAN_ALTCODE;
+              else  {
+                strcpy ( altLoc[nal],atom[i]->altLoc );
+                if (!altLoc[nal][1])  aLoc[nal] = altLoc[nal][0];
+                nal++;
+              }
+            }
+          }
+        }
+      c = 'A';
+      if (CleanKey & PDBCLEAN_ALTCODE_STRONG)
+        for (i=1;i<nal;i++)  {
+          aLoc[i] = c;
+          c = char(int(c)+1);
+        }
+      else
+        for (i=1;(i<nal) && (k<256);i++)  {
+          k = 0;
+          do  {
+            while ((k<nal) && (aLoc[k]!=c))  k++;
+            if (k<nal)  c = char(int(c)+1);
+          } while (k<nal);
+          k = 0;
+          while ((k<256) && (aLoc[k]))  k++;
+          if (k<256)  {
+            aLoc[k] = c;
+            c = char(int(c)+1);
+          }
+        }
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          k = 0;
+          while ((k<nal) && (strcmp(altLoc[k],atom[i]->altLoc)))  k++;
+          atom[i]->altLoc[0] = aLoc[k];
+          atom[i]->altLoc[1] = char(0);
+        }
+      delete[] altLoc;
+    }
+
+
+    if (CleanKey & PDBCLEAN_SEQNUM)
+      for (i=0;i<nModels;i++)  {
+        crModel0 = model[i];
+        if (crModel0)
+          for (j=0;j<crModel0->nChains;j++)  {
+            crChain0 = crModel0->chain[j];
+            if (crChain0)  {
+              nr = 0;
+              for (k=0;k<crChain0->nResidues;k++)  {
+                crRes0 = crChain0->residue[k];
+                if (crRes0)  {
+                  nr++;
+                  crRes0->seqNum     = nr;
+                  crRes0->insCode[0] = char(0);
+                }
+              }
+            }
+          }
+      }
+
+    if (CleanKey & PDBCLEAN_SOLVENT)  {
+      atom1 = new PAtom[nAtoms];
+      k = 1;
+      for (i=0;i<nModels;i++)
+        if (model[i])  {
+          if (model[i]->nChains>k)  k = model[i]->nChains;
+        }
+      Chain1 = new PChain[k];
+      Chain2 = new PChain[k];
+      k = 0;
+      for (i=0;i<nModels;i++)  {
+        crModel0 = model[i];
+        if (crModel0)  {
+          nch1 = 0;
+          nch2 = 0;
+          for (nch=0;nch<crModel0->nChains;nch++)  {
+            crChain0 = crModel0->chain[nch];
+            if (crChain0)  {
+              Solvent = false;
+              for (nr=0;(nr<crChain0->nResidues) && (!Solvent);nr++)  {
+                crRes0 = crChain0->residue[nr];
+                if (crRes0)
+                  for (j=0;(j<nSolventNames) && (!Solvent);j++)
+                    Solvent = !strcmp ( StdSolventName[j],crRes0->name );
+              }
+              if (Solvent)  Chain2[nch2++] = crChain0;
+                      else  Chain1[nch1++] = crChain0;
+            }
+          }
+          for (nch=0;nch<nch1;nch++)  {
+            crChain0 = Chain1[nch];
+            for (nr=0;nr<crChain0->nResidues;nr++)  {
+              crRes0 = crChain0->residue[nr];
+              if (crRes0)
+                for (j=0;j<crRes0->nAtoms;j++)
+                  if (crRes0->atom[j])  {
+                    atom1[k] = crRes0->atom[j];
+                    atom1[k]->index = k+1;
+                    k++;
+                  }
+            }
+            crModel0->chain[nch] = Chain1[nch];
+          }
+          for (nch=0;nch<nch2;nch++)  {
+            crChain0 = Chain2[nch];
+            for (nr=0;nr<crChain0->nResidues;nr++)  {
+              crRes0 = crChain0->residue[nr];
+              if (crRes0)
+                for (j=0;j<crRes0->nAtoms;j++)
+                  if (crRes0->atom[j])  {
+                    atom1[k] = crRes0->atom[j];
+                    atom1[k]->index = k+1;
+                    k++;
+                  }
+            }
+            crModel0->chain[nch1++] = Chain2[nch];
+          }
+          crModel0->nChains = nch1;
+        }
+      }
+      delete[] Chain1;
+      delete[] Chain2;
+      if (atom)  delete[] atom;
+      atom   = atom1;
+      atmLen = nAtoms;
+      nAtoms = k;
+    }
+
+    if (CleanKey & (PDBCLEAN_CHAIN_ORDER | PDBCLEAN_CHAIN_ORDER_IX))  {
+      for (i=0;i<nModels;i++)  {
+        crModel0 = model[i];
+        if (crModel0)  {
+          k = 0;
+          for (j=0;j<crModel0->nChains;j++)  {
+            crChain0 = crModel0->chain[j];
+            if (crChain0)  {
+              crChain0->nWeights = 0;
+              crChain0->Weight   = 0.0;
+              if (k<j)  {
+                crModel0->chain[k] = crModel0->chain[j];
+                crModel0->chain[j] = NULL;
+              }
+              k++;
+            }
+          }
+          crModel0->nChains = k;
+        }
+      }
+      if (CleanKey & PDBCLEAN_CHAIN_ORDER)
+        for (i=0;i<nAtoms;i++)
+          if (atom[i])  {
+            crChain0 = atom[i]->GetChain();
+            crChain0->nWeights++;
+            crChain0->Weight += atom[i]->serNum;
+          }
+      else
+        for (i=0;i<nAtoms;i++)
+          if (atom[i])  {
+            crChain0 = atom[i]->GetChain();
+            crChain0->nWeights++;
+            crChain0->Weight += atom[i]->GetIndex();
+          }
+      for (i=0;i<nModels;i++)  {
+        crModel0 = model[i];
+        if (crModel0)  {
+          for (j=0;j<crModel0->nChains;j++)  {
+            crChain0 = crModel0->chain[j];
+            if (crChain0->nWeights)
+              crChain0->Weight /= crChain0->nWeights;
+          }
+          //  bubble sorting
+          do {
+            Done = true;
+            for (j=1;j<crModel0->nChains;j++)
+              if (crModel0->chain[j-1]->Weight >
+                  crModel0->chain[j]->Weight)  {
+                crChain0             = crModel0->chain[j-1];
+                crModel0->chain[j-1] = crModel0->chain[j];
+                crModel0->chain[j]   = crChain0;
+                Done = false;
+              }
+          } while (!Done);
+        }
+      }
+    }
+
+    if (CleanKey & PDBCLEAN_INDEX)  {
+      k = 0;
+      for (i=0;i<nModels;i++)  {
+        crModel0 = model[i];
+        if (crModel0)  {
+          for (nch=0;nch<crModel0->nChains;nch++)  {
+            crChain0 = crModel0->chain[nch];
+            if (crChain0)  {
+              for (nr=0;nr<crChain0->nResidues;nr++)  {
+                crRes0 = crChain0->residue[nr];
+                if (crRes0)  {
+                  for (j=0;j<crRes0->nAtoms;j++)  {
+                    A = crRes0->atom[j];
+                    if (A)  {
+                      atom[A->index-1] = atom[k];
+                      if (atom[k])
+                        atom[k]->index = A->index;
+                      atom[k] = A;
+                      k++;
+                      A->index = k;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      nAtoms = k;
+    }
+
+    if (CleanKey & PDBCLEAN_SERIAL)  {
+      k = 0;
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (k<i)  {
+            atom[k] = atom[i];
+            atom[i] = NULL;
+          }
+          atom[k]->index  = k+1;
+          atom[k]->serNum = atom[k]->index;
+          k++;
+        }
+      nAtoms = k;
+    }
+
+    if (CleanKey & PDBCLEAN_ELEMENT)  {
+      for (i=0;i<nAtoms;i++)
+        if (atom[i] && (!atom[i]->Ter))  {
+          if (getElementNo(atom[i]->element)==ELEMENT_UNKNOWN)  {
+            strcpy ( atom[i]->element,"  " );
+            atom[i]->MakePDBAtomName();
+          }
+        }
+    }
+
+    if (CleanKey & PDBCLEAN_ELEMENT_STRONG)  {
+      for (i=0;i<nAtoms;i++)
+        if (atom[i] && (!atom[i]->Ter))  {
+          strcpy ( atom[i]->element,"  " );
+          atom[i]->MakePDBAtomName();
+        }
+    }
+
+    return RC;
+
+  }
+
+  void  Root::MakeHetAtoms ( cpstr chainID, bool Make )  {
+  //  Makes all atoms in chain 'chainID', in all models, as 'Het' atoms
+  //  if Make is set true, and makes them 'ordinary' atoms otherwise.
+  //  'Ter' is automatically removed when converting to 'Het' atoms,
+  //  and is automatically added when converting to 'ordinary' atoms.
+  int       i,j,k,l,n;
+  PModel   crModel0;
+  PChain   crChain0;
+  PResidue crRes0;
+    crModel0 = crModel;
+    for (i=0;i<nModels;i++)
+      if (model[i])
+        for (j=0;j<model[i]->nChains;j++)  {
+          crChain0 = model[i]->chain[j];
+          if (crChain0)  {
+            if (!strcmp(crChain0->chainID,chainID))  {
+              n = 0;
+              for (k=0;k<crChain0->nResidues;k++)  {
+                crRes0 = crChain0->residue[k];
+                if (crRes0)
+                  for (l=0;l<crRes0->nAtoms;l++)
+                    if (crRes0->atom[l])  {
+                      crRes0->atom[l]->Het = Make;
+                      n = crRes0->atom[l]->index;
+                    }
+              }
+              if (n>0)  {
+                n--;
+                if (atom[n]->Het && atom[n]->Ter)  RemoveAtom ( n+1 );
+                else if ((!atom[n]->Het) && (!atom[n]->Ter))  {
+                  SwitchModel ( model[i]->GetSerNum() );
+                  if (n<nAtoms-1)
+                    PutAtom ( -(n+2),atom[n]->serNum+1,pstr("TER"),
+                            atom[n]->GetResName(),atom[n]->GetChainID(),
+                            atom[n]->GetSeqNum (),atom[n]->GetInsCode(),
+                            pstr(" "),pstr(" "),pstr(" ") );
+                  else
+                    PutAtom ( 0,nAtoms+1,pstr("TER"),
+                            atom[n]->GetResName(),atom[n]->GetChainID(),
+                            atom[n]->GetSeqNum (),atom[n]->GetInsCode(),
+                            pstr(" "),pstr(" "),pstr(" ") );
+                  atom[n+1]->MakeTer();
+                }
+              }
+            }
+          }
+        }
+    crModel = crModel0;
+  }
+
+
+  void Root::RemoveAtom ( int index )  {
+  //    Removes atom at the specified index in the Atom array.
+  // This index is always accessible as atom[index]->index.
+  // If this leaves a residue empty, the residue is removed.
+  // If this leaves an empty chain, the chain is removed as well;
+  // the same happens to the model.
+  PResidue crRes0;
+  PChain   crChain0;
+  PModel   crModel0;
+  int      i,j;
+
+    if ((index>0) && (index<=nAtoms))  {
+      if (atom[index-1])  {
+        crRes0 = atom[index-1]->residue;
+        if (crRes0)  {
+          if (crRes0->_ExcludeAtom(index))  {
+            // the residue appears empty after the exclusion
+            if (crRes)  {
+              if ((crRes->seqNum==crRes0->seqNum) &&
+                  (!strcmp(crRes->insCode,crRes0->insCode)))
+                crRes = NULL;
+            }
+            crChain0 = crRes0->chain;
+            if (crChain0)  {
+              if (crChain0->_ExcludeResidue(crRes0->name,crRes0->seqNum,
+                                            crRes0->insCode))  {
+                // the chain appears empty after the exclusion
+                if (crChain)  {
+                  if (!strcmp(crChain->chainID,crChain0->chainID))
+                    crChain = NULL;
+                }
+                crModel0 = PModel(crChain0->model);
+                if (crModel0)  {
+                  if (crModel0->_ExcludeChain(crChain0->chainID))  {
+                    // the model appears ampty after the exclusion
+                    if (crModel)  {
+                      if (crModel->serNum==crModel0->serNum)
+                        crModel = NULL;
+                    }
+                    i = crModel0->serNum-1;
+                    delete model[i];
+                    model[i] = NULL;
+                  }
+                }
+                delete crChain0;  // it is already excluded from the hierarchy!
+              }
+            }
+            delete crRes0;  // it is already excluded from the hierarchy!
+          }
+        }
+        delete atom[index-1];  // it is already excluded from the hierarchy!
+        atom[index-1] = NULL;
+        // now rearrange and re-index atoms.
+        j = 0;
+        for (i=0;i<nAtoms;i++)
+          if (atom[i])  {
+            if (j<i)  {
+              atom[j] = atom[i];
+              atom[i] = NULL;
+            }
+            atom[j]->index = j+1;
+            j++;
+          }
+        nAtoms = j;
+      }
+    }
+  }
+
+
+  int  Root::_ExcludeModel ( int serNum )  {
+  //   _ExcludeModel(..) excludes (but does not dispose!) a model
+  // from the file. Returns 1 if the file gets empty and 0 otherwise.
+  int  i,k;
+
+    if (!Exclude)  return 0;
+
+    if ((0<serNum) && (serNum<=nModels))
+      model[serNum-1] = NULL;
+
+    k = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  {
+        if (k<i)  {
+          model[k] = model[i];
+          model[i] = NULL;
+        }
+        model[k]->serNum = k+1;
+        k++;
+      }
+
+    nModels = k;
+
+    if (nModels<=0)  return 1;
+               else  return 0;
+
+  }
+
+
+  int  Root::FinishStructEdit()  {
+  // Makes a new atom index after insertion or deletion of atoms.
+  // This function may change atoms' positions in the index and
+  // correspondingly the Atom::index field.
+  PResidue res;
+  PChain   chain;
+  PModel   Model1;
+  PPAtom   Atom1;
+  int       i,j,k,l,n,index,nAtoms1;
+
+    //  calculate new number of atoms
+    nAtoms1 = 0;
+    for (i=0;i<nModels;i++)  {
+      Model1 = model[i];
+      if (Model1)  {
+        for (j=0;j<Model1->nChains;j++)  {
+          chain = Model1->chain[j];
+          if (chain)  {
+            for (k=0;k<chain->nResidues;k++)  {
+              res = chain->residue[k];
+              if (res)  {
+                res->TrimAtomTable();
+                nAtoms1 += res->nAtoms;
+              }
+            }
+            chain->TrimResidueTable();
+          }
+        }
+        Model1->TrimChainTable();
+      }
+    }
+    TrimModelTable();
+
+    // compile a new index and null the old one
+
+    if (nAtoms1>0)  Atom1 = new PAtom[nAtoms1];
+              else  Atom1 = NULL;
+
+    n = 0;
+    for (i=0;i<nModels;i++)  {
+      Model1 = model[i];
+      for (j=0;j<Model1->nChains;j++)  {
+        chain = Model1->chain[j];
+        for (k=0;k<chain->nResidues;k++)  {
+          res = chain->residue[k];
+          for (l=0;l<res->nAtoms;l++)  {
+            Atom1[n] = res->atom[l];
+            index    = Atom1[n]->index;
+            if ((index>0) && (index<=atmLen))
+              atom[index-1] = NULL;
+            Atom1[n]->index = n+1;
+            n++;
+          }
+        }
+      }
+    }
+
+  //  if (n!=nAtoms1)  {
+  //    printf ( " **** PROGRAM ERROR IN Root::FinishStructEdit\n" );
+  //    exit ( 1 );
+  //  }
+
+
+    // check if there are dead atoms in the old index
+    for (i=0;i<atmLen;i++)
+      if (atom[i])  delete atom[i];
+
+    // dispose old index and replace it with the new one
+    if (atom)  delete[] atom;
+
+    atom   = Atom1;
+    atmLen = n;
+    nAtoms = n;
+
+    if (n==nAtoms1)  return 0;  // Ok
+               else  return 1;  // not Ok; should never happen
+
+  }
+
+  void Root::TrimModelTable()  {
+  int i,j;
+    j = 0;
+    for (i=0;i<nModels;i++)
+      if (model[i])  {
+        if (j<i)  {
+          model[j] = model[i];
+          model[i] = NULL;
+        }
+        model[j]->serNum = j+1;
+        j++;
+      }
+    nModels = j;
+  }
+
+
+  int  Root::GenerateNCSMates()  {
+  //
+  //   Generates NCS mates according to NCS matrices given
+  // in cryst. This will result in generating many-character
+  // chain names, composed as 'x_n' where 'x' is the original
+  // name and 'n' is a unique number, which will coincide with
+  // the symmetry operation (order) number. Another side
+  // effect will be a disorder in atoms' serial numbers.
+  //   The hierarchy should therefore be cleaned after
+  // generating the NCS mates. An appropriate way to do that
+  // is to issue the following call:
+  //
+  //   PDBCleanup ( PDBCLEAN_TER | PDBCLEAN_ALTCODE_STRONG |
+  //                PDBCLEAN_CHAIN_STRONG | PDBCLEAN_SERIAL );
+  //
+  PPChain chainTable,chain;
+  PChain  chn;
+  mat44    ncs_m;
+  ChainID  chainID;
+  int      i,j,k,nNCSOps,nChains,iGiven;
+
+    nNCSOps = cryst.GetNumberOfNCSMatrices();
+    if (nNCSOps<=0)  return 1;
+
+    for (i=0;i<nModels;i++)
+      if (model[i])  {
+        model[i]->GetChainTable ( chainTable,nChains );
+        if (nChains>0)  {
+          chain = new PChain[nChains];
+          for (j=0;j<nChains;j++)
+            chain[j] = chainTable[j];
+          for (j=0;j<nChains;j++)
+            if (chain[j])  {
+              for (k=0;k<nNCSOps;k++)
+                if (cryst.GetNCSMatrix(k,ncs_m,iGiven))  {
+                  if (!iGiven)  {
+                    chn = newChain();
+                    chn->Copy ( chain[j] );
+                    sprintf ( chainID,"%s_%i",
+                              chain[j]->GetChainID(),k+1 );
+                    chn->SetChainID     ( chainID );
+                    chn->ApplyTransform ( ncs_m   );
+                    model[i]->AddChain  ( chn     );
+                  }
+                }
+            }
+          delete[] chain;
+        }
+      }
+
+    return 0;
+
+  }
+
+
+  void  Root::ApplyNCSTransform ( int NCSMatrixNo )  {
+  mat33 t;
+  vect3 v;
+  int   i;
+    if (!cryst.GetNCSMatrix(NCSMatrixNo,t,v))  return;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  atom[i]->Transform ( t,v );
+  }
+
+
+  ERROR_CODE Root::PutPDBString ( cpstr PDBString )  {
+  PContString contString;
+  ERROR_CODE  RC;
+
+    strcpy    ( S,PDBString );  // maintain the buffer!
+    PadSpaces ( S,80 );
+    lcount++;
+
+    // belongs to title?
+    RC = title.ConvertPDBString ( S );
+    if (RC!=Error_WrongSection)  return RC;
+
+    // belongs to primary structure section?
+    SwitchModel ( 1 );
+    RC = crModel->ConvertPDBString ( S );
+    if (RC!=Error_WrongSection)  return RC;
+
+    // belongs to the crystallographic information section?
+    RC = cryst.ConvertPDBString ( S );
+    if (RC!=Error_WrongSection)  {
+  //    if (RC==0)  cryst.CalcCoordTransforms();
+      return RC;
+    }
+
+    // belongs to the coordinate section?
+    RC = ReadPDBAtom ( S );
+    if (RC!=Error_WrongSection)  return RC;
+
+    // temporary solution: the rest of file is stored
+    // in the form of strings
+    if ((S[0]) && (S[0]!=' ') && (strncmp(S,"END   ",6)))  {
+      // END is added automatically
+      contString = new ContString(S);
+      SC.AddData ( contString );
+    }
+
+    return Error_NoError;
+
+  }
+
+
+  ERROR_CODE Root::AddPDBASCII1 ( cpstr PDBLFName, io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( PDBLFName );
+    if (FName)  return AddPDBASCII ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::AddPDBASCII ( cpstr PDBFileName, io::GZ_MODE gzipMode ) {
+  io::File   f;
+  ERROR_CODE RC;
+    //  open the file as ASCII for reading
+    //  opening it in pseudo-binary mode helps reading various
+    //  line terminators for files coming from different platforms
+    f.assign ( PDBFileName,false,false,gzipMode );
+    if (f.reset(true)) {
+      lcount = 1;  // line counter
+      RC     = Error_NoError;
+      while ((!f.FileEnd()) && (!RC))  {
+        ReadPDBLine ( f,S,sizeof(S) );
+        RC = PutPDBString ( S );
+      }
+      f.shut();
+    } else
+      RC = Error_CantOpenFile;
+    return RC;
+  }
+
+
+  void Root::GetInputBuffer ( pstr Line, int & count )  {
+    if (FType==MMDB_FILE_PDB)  {  // PDB File
+      strcpy ( Line,S );
+      count = lcount;
+    } else if (FType==MMDB_FILE_CIF)  {
+      if (!CIFErrorLocation[0])  {  // CIF reading phase
+        strcpy ( Line,S );
+        count = lcount;
+      } else  {
+        strcpy ( Line,CIFErrorLocation );
+        count = -1;  // CIF interpretation phase
+      }
+    } else {
+      Line[0] = char(0);
+      count = -2;
+    }
+  }
+
+
+  int  Root::CrystReady()  {
+  //    Returns flags:
+  // CRRDY_Complete       if crystallographic information is complete
+  // CRRDY_NotPrecise     if cryst. inf-n is not precise
+  // CRRDY_isTranslation  if cryst. inf-n contains translation
+  // CRRDY_NoOrthCode     no orthogonalization code
+  //    Fatal:
+  // CRRDY_NoTransfMatrices  if transform. matrices were not calculated
+  // CRRDY_Unchecked         if cryst. inf-n was not checked
+  // CRRDY_Ambiguous         if cryst. inf-n is ambiguous
+  // CRRDY_NoCell            if cryst. inf-n is unusable
+  // CRRDY_NoSpaceGroup      if space group is not set
+  int k;
+
+    if (!(cryst.WhatIsSet & CSET_Transforms))
+      return CRRDY_NoTransfMatrices;
+
+    if ((cryst.WhatIsSet & CSET_CellParams)!=CSET_CellParams)
+      return CRRDY_NoCell;
+
+    if (!(cryst.WhatIsSet & CSET_SpaceGroup))
+      return CRRDY_NoSpaceGroup;
+
+    if (cryst.CellCheck & CCHK_Unchecked)
+      return CRRDY_Unchecked;
+
+    if (cryst.CellCheck & CCHK_Disagreement)
+      return CRRDY_Ambiguous;
+
+    k = 0x0000;
+    if (cryst.CellCheck & CCHK_Error)        k |= CRRDY_NotPrecise;
+    if (cryst.CellCheck & CCHK_Translations) k |= CRRDY_isTranslation;
+    if (cryst.CellCheck & CCHK_NoOrthCode)   k |= CRRDY_NoOrthCode;
+
+    return k;
+
+  }
+
+
+  bool Root::isCrystInfo()  {
+    return (((cryst.WhatIsSet & CSET_CellParams)==CSET_CellParams) &&
+             (cryst.WhatIsSet & CSET_SpaceGroup));
+  }
+
+  bool Root::isCellInfo()  {
+    return ((cryst.WhatIsSet & CSET_CellParams)==CSET_CellParams);
+  }
+
+  bool Root::isSpaceGroup()  {
+    return (cryst.WhatIsSet & CSET_SpaceGroup);
+  }
+
+  bool Root::isTransfMatrix()  {
+    return cryst.areMatrices();
+  }
+
+  bool Root::isScaleMatrix()  {
+    return ((cryst.WhatIsSet & CSET_ScaleMatrix)==CSET_ScaleMatrix);
+  }
+
+  bool Root::isNCSMatrix()  {
+    return cryst.isNCSMatrix();
+  }
+
+  int  Root::AddNCSMatrix ( mat33 & ncs_m, vect3 & ncs_v,
+                                 int iGiven )  {
+    return cryst.AddNCSMatrix ( ncs_m,ncs_v,iGiven );
+  }
+
+  int  Root::GetNumberOfNCSMatrices()  {
+    return cryst.GetNumberOfNCSMatrices();
+  }
+
+  int  Root::GetNumberOfNCSMates()  {
+  // Returns the number of NCS mates not given in the file (iGiven==0)
+    return cryst.GetNumberOfNCSMates();
+  }
+
+  bool  Root::GetNCSMatrix ( int NCSMatrixNo, // 0..N-1
+                                     mat44 & ncs_m, int & iGiven )  {
+    return cryst.GetNCSMatrix ( NCSMatrixNo,ncs_m,iGiven );
+  }
+
+  ERROR_CODE Root::ReadPDBAtom ( cpstr L )  {
+  //   If string L belongs to the coordinate section
+  // (records ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM),
+  // the correspondent information is retrieved and
+  // stored in the dynamic Atom array. In parallel, the
+  // structures of Model/Chain/Residue are generated and
+  // referenced to the corresponding Atom.
+  //   If processing of L was successful, the return is 0,
+  // otherwise it returns the corresponding Error_XXX
+  // code.
+  //   If L does not belong to the coordinate section,
+  // Error_WrongSection is returned.
+  int        index,i;
+  ERROR_CODE RC;
+
+    if (!strncmp(L,"ATOM  ",6)) {
+
+      index = nAtoms+1;  // index for the next atom in Atom array
+      RC    = CheckAtomPlace ( index,L );
+      if (!RC)  RC = atom[index-1]->ConvertPDBATOM ( index,L );
+
+    } else if (!strncmp(L,"SIGATM",6)) {
+
+      index = nAtoms;    // keep index!
+      RC    = CheckAtomPlace ( index,L );
+      if (!RC)  RC = atom[index-1]->ConvertPDBSIGATM ( index,L );
+
+    } else if (!strncmp(L,"ANISOU",6)) {
+
+      index = nAtoms;    // keep index
+      RC    = CheckAtomPlace ( index,L );
+      if (!RC)  RC = atom[index-1]->ConvertPDBANISOU ( index,L );
+
+    } else if (!strncmp(L,"SIGUIJ",6)) {
+
+      index = nAtoms;    // keep index
+      RC    = CheckAtomPlace ( index,L );
+      if (!RC)  RC = atom[index-1]->ConvertPDBSIGUIJ ( index,L );
+
+    } else if (!strncmp(L,"TER   ",6)) {
+
+      index = nAtoms+1;  // new place in Atom array
+      RC    = CheckAtomPlace ( index,L );
+      if (!RC)  RC = atom[index-1]->ConvertPDBTER ( index,L );
+
+    } else if (!strncmp(L,"HETATM",6)) {
+
+      index = nAtoms+1;  // new place in Atom array
+      RC    = CheckAtomPlace ( index,L );
+      if (!RC)  RC = atom[index-1]->ConvertPDBHETATM ( index,L );
+
+    } else if (!strncmp(L,"MODEL ",6)) {
+
+      modelCnt++;
+      RC = SwitchModel ( L );
+      for (i=0;(i<nModels) && (!RC);i++)
+        if (model[i] && (model[i]!=crModel))  {
+          if (crModel->serNum==model[i]->serNum)
+            RC = Error_DuplicatedModel;
+        }
+  //    if (!RC)  {
+  //      if (crModel->serNum!=modelCnt)
+  //        RC = Error_DuplicatedModel;
+  //    }
+
+    } else if (!strncmp(L,"ENDMDL",6)) {
+
+      crModel = NULL;
+      crChain = NULL;
+      crRes   = NULL;
+
+      RC      = Error_NoError;
+
+    } else
+      return Error_WrongSection;
+
+    return RC;
+
+  }
+
+
+  ERROR_CODE Root::ReadCIFAtom ( mmcif::PData CIFD )  {
+  mmcif::PLoop Loop,LoopAnis;
+  int          i,index,nATS;
+  ERROR_CODE   RC;
+
+    Loop = CIFD->GetLoop ( CIFCAT_ATOM_SITE );
+    if (!Loop)  return Error_NoError;  // no atom coordinates in the file
+
+    LoopAnis = CIFD->GetLoop ( CIFCAT_ATOM_SITE_ANISOTROP );
+    nATS     = Loop->GetLoopLength();
+
+    for (i=1;i<=nATS;i++)  {
+      // nAtoms and i should always coincide at this point. This piece
+      // of code was however left in order to reach identity with
+      // ReadPDBAtom(..).
+      index = nAtoms+1;  // index for the next atom in Atom array
+      RC    = CheckAtomPlace ( index,Loop );
+      if (!RC)  RC = atom[index-1]->GetCIF ( i,Loop,LoopAnis );
+      if (RC && (RC!=Error_CIF_EmptyRow))  return RC;
+    }
+    if (Flags & MMDBF_AutoSerials)
+      PDBCleanup ( PDBCLEAN_SERIAL );
+
+    return Error_NoError;
+
+  }
+
+  int  Root::PutAtom ( int            index,
+                            int            serNum,
+                            const AtomName atomName,
+                            const ResName  resName,
+                            const ChainID  chainID,
+                            int            seqNum,
+                            const InsCode  insCode,
+                            const AltLoc   altLoc,
+                            const SegID    segID,
+                            const Element  element )  {
+
+  //   An atom with the specified properties is put into the
+  // structure. The current model is used; if no model is
+  // set (crModel==NULL), one is created. Coordinates and
+  // other parameters of the atom need to be set separately.
+  //
+  //   If index is positive and there is already an atom at
+  // this position in the system, the new atom will REPLACE
+  // it. The corresponding residues are automatically
+  // updated.
+  //
+  //   If index is null (=0), the new atom will be put on
+  // the top of the structure, i.e. it will be put into
+  // (index=nAtoms+1)-th position.
+  //
+  //   If index is negative, then the new atom is INSERTED
+  // BEFORE the atom in the (-index)th position. For
+  // saving the computational efforts, this WILL NOT cause
+  // the recalculation of all atoms' serial numbers
+  // according to their actual positions. It will be needed
+  // however to put the things in order by calling
+  // Root::OrderAtoms() at a certain point, especially
+  // before writing an output ASCII file. NOTE that this
+  // ordering is never done automatically.
+  //
+  //   Limitation: if PutAtom implies creating new
+  // chains/residues, these are always created on the top
+  // of existing chains/residues.
+
+
+  int i,kndex,RC;
+
+    kndex = index;
+
+    if (kndex<0)  {  // the new atom is to be inserted
+
+      kndex = -kndex;
+      if (kndex>atmLen)
+        ExpandAtomArray ( kndex+1000-atmLen );
+
+      if (atom[kndex-1]!=NULL)  { // the position is occupied
+
+        // expand the array if necessary
+        if (nAtoms>=atmLen)
+          ExpandAtomArray ( IMax(kndex,nAtoms)+1000-atmLen );
+
+        // now shift all atoms from (kndex-1)th to the end of array.
+        // note that this does not affect residues as they keep only
+        // pointers on atoms
+        for (i=nAtoms;i>=kndex;i--)  {
+          atom[i] = atom[i-1];
+          atom[i]->index = i+1;  // this is Ok because residues keep
+                                 // POINTERS rather than indices!
+        }
+        atom[kndex-1] = NULL;
+        nAtoms++;
+
+      }
+
+    }
+
+    if (kndex==0)  kndex = nAtoms+1;
+
+    if (!crModel)  SwitchModel ( 1 );
+
+
+    RC = AllocateAtom ( kndex,chainID,chainID,resName,resName,
+                        seqNum,seqNum,1,insCode,true );
+    if (!RC)
+      atom[kndex-1]->SetAtomName ( kndex,serNum,atomName,altLoc,
+                                   segID,element );
+    return RC;
+
+  }
+
+
+  int Root::PutAtom ( int    index,  // same meaning as above
+                           PAtom A,      // pointer to completed atom
+                                          // class
+                           int    serNum  // 0 means that the serial
+                                          // number will be set equal
+                                          // to "index". Otherwise,
+                                          // the serial number is set
+                                          // to the specified value
+                         )  {
+  int i,kndex,RC,sn;
+
+    if (!A)  return -1;
+
+    kndex = index;
+
+    if (kndex<0)  {  // the new atom is to be inserted
+
+      kndex = -kndex;
+
+      if (kndex>atmLen)
+        ExpandAtomArray ( kndex+1000-atmLen );
+
+      if (atom[kndex-1]!=NULL)  { // the position is occupied
+
+        // expand the array if necessary
+        if (nAtoms>=atmLen)
+          ExpandAtomArray ( IMax(kndex,nAtoms)+1000-atmLen );
+        // now shift all atoms from (kndex-1)th to the end of array.
+        // note that this does not affect residues as they keep only
+        // pointers on atoms
+
+        for (i=nAtoms;i>=kndex;i--)  {
+          atom[i] = atom[i-1];
+          atom[i]->index = i+1;  // this is Ok because residues keep
+                                 // POINTERS rather than indices!
+        }
+
+        atom[kndex-1] = NULL;
+        nAtoms++;
+
+      }
+
+    }
+
+    if (kndex==0)  kndex = nAtoms+1;
+
+
+    RC = AllocateAtom ( kndex,A->GetChainID(),A->GetLabelAsymID(),
+                              A->GetResName(),A->GetLabelCompID(),
+                              A->GetSeqNum (),A->GetLabelSeqID (),
+                              A->GetLabelEntityID(),A->GetInsCode(),
+                              true );
+
+    if (serNum<=0)  sn = kndex;
+              else  sn = serNum;
+    if (!RC)  {
+      atom[kndex-1]->Copy ( A );
+      atom[kndex-1]->serNum = sn;
+    }
+
+    return RC;
+
+  }
+
+  int Root::CheckInAtom ( int index, // same meaning as above
+                               PAtom  A  // pointer to completed
+                                          // atom class
+                             )  {
+  int i,kndex;
+
+    if (!A)  return -1;
+
+    kndex = index;
+
+    if (kndex<0)  {  // the new atom is to be inserted
+
+      kndex = -kndex;
+
+      if (kndex>atmLen)
+        ExpandAtomArray ( kndex+1000-atmLen );
+
+      if (atom[kndex-1]!=NULL)  { // the position is occupied
+
+        // expand the array if necessary
+        if (nAtoms>=atmLen)
+          ExpandAtomArray ( IMax(kndex,nAtoms)+1000-atmLen );
+        // now shift all atoms from (kndex-1)th to the end of array.
+        // note that this does not affect residues as they keep only
+        // pointers on atoms
+
+        for (i=nAtoms;i>=kndex;i--)  {
+          atom[i] = atom[i-1];
+          if (atom[i])
+            atom[i]->index = i+1;  // this is Ok because residues keep
+                                   // POINTERS rather than indices!
+        }
+
+      }
+
+      nAtoms++;
+
+    } else  {
+      if (kndex==0)      kndex = nAtoms + 1;  // add atom on the very top
+      if (kndex>atmLen)  ExpandAtomArray ( kndex+1000-atmLen );
+      if (kndex>nAtoms)  nAtoms = kndex;
+      if (atom[kndex-1]) delete atom[kndex-1];
+    }
+
+    atom[kndex-1] = A;
+    A->index = kndex;
+
+    return 0;
+
+  }
+
+  int Root::CheckInAtoms ( int index, // same meaning as above
+                                PPAtom A, // array of atoms to check in
+                                int natms  // number of atoms to check in
+                              )  {
+  PPAtom A1;
+  int     i,j,k,k1,kndex;
+
+    if (!A)  return -1;
+
+    A1    = NULL;
+    kndex = index;
+
+    if (kndex<0)  {  // the new atoms are to be inserted
+
+      kndex = -kndex;
+
+      if (nAtoms+natms>=atmLen)
+        ExpandAtomArray ( IMax(kndex,nAtoms)+1000+natms-atmLen );
+
+      if (kndex<nAtoms)
+      A1 = new PAtom[natms];
+      k = kndex-1;
+      j = 0;
+      for (i=0;i<natms;i++)
+        if (A[i])  {
+          if (atom[k])  A1[j++] = atom[k];
+          atom[k] = A[i];
+          atom[k]->index = k+1;
+          k++;
+        }
+
+      if (j>0)  {
+        // insert removed atoms into the gap
+        nAtoms += j;
+        k1      = k+j;
+        for (i=nAtoms-1;i>=k1;i--)  {
+          atom[i] = atom[i-j];
+          if (atom[i])
+            atom[i]->index = i+1;  // this is Ok because residues keep
+                                   // POINTERS rather than indices!
+        }
+        for (i=0;i<j;i++)  {
+          atom[k] = A1[i];
+          atom[k]->index = k+1;
+          k++;
+        }
+      }
+
+      delete[] A1;
+
+    } else  {
+
+      if (kndex==0)      kndex = nAtoms + 1;  // add atom on the very top
+      k = kndex + natms;
+      if (k>atmLen)  ExpandAtomArray ( k+1000-atmLen );
+      kndex--;
+      for (i=0;i<natms;i++)
+        if (A[i])  {
+          if (atom[kndex]) delete atom[kndex];
+          atom[kndex] = A[i];
+          atom[kndex]->index = kndex+1;
+          kndex++;
+        }
+      nAtoms = IMax(nAtoms,kndex);
+
+    }
+
+    return 0;
+
+  }
+
+
+  ERROR_CODE Root::SwitchModel ( cpstr L )  {
+  int nM;
+
+    if (!GetInteger(nM,&(L[10]),4))
+      return Error_UnrecognizedInteger;
+
+    return SwitchModel ( nM );
+
+  }
+
+  ERROR_CODE Root::SwitchModel ( int nM )  {
+  PPModel Mdl;
+  int      i;
+  bool  Transfer;
+
+    if (nM<=0)
+      return Error_WrongModelNo;
+
+    if (nM>nModels)  {
+      if ((nModels==1) && model[0])  Transfer = (nAtoms<=0);
+                               else  Transfer = false;
+      Mdl = new PModel[nM];
+      for (i=0;i<nModels;i++)
+        Mdl[i] = model[i];
+      for (i=nModels;i<nM;i++)
+        Mdl[i] = NULL;
+      if (model) delete[] model;
+      model   = Mdl;
+      nModels = nM;
+      if (Transfer)  {
+        model[nM-1] = model[0];
+        model[0]    = NULL;
+      }
+    }
+
+    if (!model[nM-1])
+      model[nM-1] = newModel();
+    model[nM-1]->SetMMDBManager ( PManager(this),nM );
+
+    crModel = model[nM-1];
+    crChain = NULL;  // new model - new chain
+    crRes   = NULL;  // new chain - new residue
+
+    return Error_NoError;
+
+  }
+
+  ERROR_CODE Root::CheckAtomPlace ( int index, cpstr L )  {
+  //   This function gets the residue/chain information stored
+  // in PDB string L (the records should start with the
+  // keywords ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM) and
+  // sets the pointers crChain and crRes to the respective.
+  // chain and residue. If there is no chain/residue to place
+  // the atom in, these will be created.
+  //   The function prepares place for the atom in the index-th
+  // cell of the Atom array, expanding it as necessary. If the
+  // corresponding element in the Atom array was not initialized,
+  // a Atom class is created with reference to the current
+  // residue.
+  //   This function DOES NOT check the PDB string L for
+  // atom keywords.
+  ResName  resName;
+  int      seqNum;
+  ChainID  chainID;
+  InsCode  insCode;
+
+    // get the residue sequence number/ insert code
+    if (!GetIntIns(seqNum,insCode,&(L[22]),4))  {
+      if (strncmp(L,"TER   ",6))
+            return Error_UnrecognizedInteger;
+      else  { // we allow for empty TER card here
+        seqNum  = 0;
+        insCode[0] = char(1);  // unprintable symbol! used as
+                               // flag that TER card does not
+                               // have serial number
+        insCode[1] = char(0);
+      }
+    }
+
+    // get chain ID
+    if (L[20]!=' ')  {
+      chainID[0] = L[20];
+      chainID[1] = L[21];
+      chainID[2] = char(0);
+    } else if (L[21]!=' ')  {
+      chainID[0] = L[21];
+      chainID[1] = char(0);
+    } else
+      chainID[0] = char(0);
+
+    // get residue name
+    strcpy_ncss ( resName,&(L[17]),3 );
+    if ((!resName[0]) && (!strncmp(L,"TER   ",6)))  {
+      insCode[0] = char(1);
+      insCode[1] = char(0);
+    }
+
+    return AllocateAtom ( index ,chainID,chainID,resName,resName,
+                          seqNum,seqNum,1,insCode,false );
+
+  }
+
+  ERROR_CODE Root::CheckAtomPlace ( int index, mmcif::PLoop Loop )  {
+  //   Version of CheckAtomPlace(..) for reading from CIF file.
+  ResName  resName,label_comp_id;
+  int      seqNum ,label_seq_id,label_entity_id,RC,k,nM;
+  ChainID  chainID,label_asym_id;
+  InsCode  insCode;
+  pstr     F;
+
+    // Get the residue sequence number/insert code. They are
+    // removed from the file after reading.
+    k = index-1;
+  //  if (!CIFGetInteger1(seqNum,Loop,CIFTAG_LABEL_SEQ_ID,k))
+    if (!CIFGetInteger1(seqNum,Loop,CIFTAG_AUTH_SEQ_ID,k))
+      CIFGetString  ( insCode,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,k,
+                      sizeof(InsCode),pstr("") );
+    else  {
+      F = Loop->GetString ( CIFTAG_GROUP_PDB,k,RC );
+      if ((!F) || (RC)) return  Error_CIF_EmptyRow;
+      if (strcmp(F,"TER"))  {
+        seqNum = MinInt4;  // only at reading CIF we allow this
+        CIFGetString ( insCode,Loop,CIFTAG_NDB_HELIX_CLASS_PDB,k,
+                       sizeof(InsCode),pstr("") );
+      } else  { // we allow for empty TER card here
+        seqNum     = 0;
+        insCode[0] = char(1);  // unprintable symbol! used as
+                               // flag that TER card does not
+                               // have serial number
+        insCode[1] = char(0);
+      }
+    }
+
+    CIFGetInteger1 ( label_seq_id   ,Loop,CIFTAG_LABEL_SEQ_ID   ,k );
+    CIFGetInteger1 ( label_entity_id,Loop,CIFTAG_LABEL_ENTITY_ID,k );
+
+    // get chain/residue ID
+    CIFGetString ( chainID,Loop,CIFTAG_AUTH_ASYM_ID,k,
+                   sizeof(ChainID),pstr("") );
+    CIFGetString ( resName,Loop,CIFTAG_AUTH_COMP_ID,k,
+                   sizeof(ResName),pstr("") );
+
+    CIFGetString ( label_asym_id,Loop,CIFTAG_LABEL_ASYM_ID,k,
+                   sizeof(ChainID),pstr("") );
+    CIFGetString ( label_comp_id,Loop,CIFTAG_LABEL_COMP_ID,k,
+                   sizeof(ResName),pstr("") );
+
+    if (!resName[0])  strcpy ( resName,label_comp_id );
+
+    if (!CIFGetInteger1(nM,Loop,CIFTAG_PDBX_PDB_MODEL_NUM,k))  {
+      if (crModel)  {
+        if (nM!=crModel->serNum)  SwitchModel ( nM );
+      } else
+        SwitchModel ( nM );
+    }
+
+    return AllocateAtom ( index ,chainID,label_asym_id,resName,
+                          label_comp_id,seqNum,label_seq_id,
+                          label_entity_id,insCode,false );
+
+  }
+
+
+  ERROR_CODE Root::AllocateAtom ( int           index,
+                                  const ChainID chainID,
+                                  const ChainID label_asym_id,
+                                  const ResName resName,
+                                  const ResName label_comp_id,
+                                  int           seqNum,
+                                  int           label_seq_id,
+                                  int           label_entity_id,
+                                  const InsCode insCode,
+                                  bool       Replace )  {
+
+    if ((!resName[0]) && (insCode[0]!=char(1)))
+      return Error_EmptyResidueName;
+
+    // check if there is a pointer to model
+    if (!crModel)  {
+      // the model pointer was not set. Check if there are
+      // models already defined
+      if (!model)
+           SwitchModel ( 1 );  // creates a model
+      else return Error_NoModel;
+    }
+
+    if (crChain && (insCode[0]!=char(1)))  {
+      //   If crChain is not NULL, the model pointer was not
+      // changed and we may try to keep using crChain as
+      // pointer to the being-read chain. However, we must
+      // check that the record still belongs to the same chain.
+      //   All this does not work if insCode[0] is set to 1
+      // which indicates a special case of 'TER' card without
+      // parameters.
+      if (enforceUniqueChID)  {
+        // enforcing unique chain IDs should be used only in case
+        // of multi-chain complexes where 1-letter chain IDs are
+        // not enough to accomodate all chains. Then chains are
+        // dynamically renamed like A0,A1,A2,.. etc. Therefore, we
+        // check only first symbol here.
+        if (chainID[0]!=crChain->chainID[0])
+          crChain = NULL;  // the chain has to be changed
+      } else if (strcmp(chainID,crChain->chainID))
+        crChain = NULL;  // the chain has to be changed
+    }
+    if (!crChain) {
+      // either the model or chain was changed  -- get a new chain
+      if (allowDuplChID)
+            crChain = crModel->CreateChain    ( chainID );
+      else  crChain = crModel->GetChainCreate ( chainID,
+                                                enforceUniqueChID );
+      crRes = NULL;  // new chain - new residue
+    }
+
+    if (crRes && (insCode[0]!=char(1)))  {
+      //   If crRes is not NULL, neither the model nor chain were
+      // changed. Check if this record still belongs to the
+      // same residue.
+      //   All this does not work if insCode[0] is set to 1
+      // which indicates a special case of 'TER' card without
+      // parameters.
+      if ((seqNum!=crRes->seqNum)         ||
+           strcmp(insCode,crRes->insCode) ||
+           strcmp(resName,crRes->name))
+        crRes = NULL;  // the residue has to be changed
+    }
+    if (!crRes)  {
+      // either the chain or residue was changed -- get a new residue
+      crRes = crChain->GetResidueCreate ( resName,seqNum,insCode,
+                                        Flags & MMDBF_IgnoreDuplSeqNum );
+      if (!crRes)  return  Error_DuplicateSeqNum;
+    }
+
+    strcpy ( crRes->label_asym_id,label_asym_id );
+    strcpy ( crRes->label_comp_id,label_comp_id );
+    crRes->label_seq_id    = label_seq_id;
+    crRes->label_entity_id = label_entity_id;
+
+    // now check if there is place in the Atom array
+    if (index>atmLen)
+      // there is no place, expand Atom by 1000 atom places at once
+      ExpandAtomArray ( index+1000-atmLen );
+    nAtoms = IMax(nAtoms,index);
+
+    // delete the to-be-replaced atom if there is any
+    if (Replace && atom[index-1])  {
+      delete atom[index-1];
+      atom[index-1] = NULL;
+    }
+    if (!atom[index-1])  {
+      atom[index-1] = newAtom();
+      crRes->_AddAtom ( atom[index-1] );
+      atom[index-1]->index = index;
+    }
+
+    return Error_NoError;
+
+  }
+
+  void Root::ExpandAtomArray ( int inc )  {
+  // Expands the Atom array by adding more inc positions.
+  // The length of Atom array is increased unconditionally.
+  PPAtom Atom1;
+  int     i;
+    atmLen += inc;
+    Atom1   = new PAtom[atmLen];
+    for (i=0;i<nAtoms;i++)
+      Atom1[i] = atom[i];
+    for (i=nAtoms;i<atmLen;i++)
+      Atom1[i] = NULL;
+    if (atom) delete[] atom;
+    atom = Atom1;
+  }
+
+  void Root::AddAtomArray ( int inc )  {
+  // Checks if 'inc' atoms may be added into Atom array,
+  // and if not, expands the Atom array such that to
+  // allocate exactly 'inc' atoms more than is currently
+  // contained.
+  PPAtom Atom1;
+  int     i;
+    if (nAtoms+inc>atmLen)  {
+      atmLen = nAtoms+inc;
+      Atom1  = new PAtom[atmLen];
+      for (i=0;i<nAtoms;i++)
+        Atom1[i] = atom[i];
+      for (i=nAtoms;i<atmLen;i++)
+        Atom1[i] = NULL;
+      if (atom) delete[] atom;
+      atom = Atom1;
+    }
+  }
+
+
+  ERROR_CODE Root::WritePDBASCII1 ( cpstr PDBLFName,
+                                    io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( PDBLFName );
+    if (FName)  return WritePDBASCII ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::WritePDBASCII ( cpstr PDBFileName,
+                                   io::GZ_MODE gzipMode )  {
+  io::File f;
+
+    //  opening it in pseudo-text mode ensures that the line
+    //  endings will correspond to the system MMDB is running on
+    f.assign ( PDBFileName,true,false,gzipMode );
+    FType = MMDB_FILE_PDB;
+
+    if (f.rewrite())  {
+      WritePDBASCII ( f );
+      f.shut();
+    } else
+      return Error_CantOpenFile;
+
+    return Error_NoError;
+
+  }
+
+
+  void  Root::WritePDBASCII ( io::RFile f )  {
+  int  i;
+
+    FType = MMDB_FILE_PDB;
+
+    title.PDBASCIIDump ( f );
+
+    i = 0;
+    while (i<nModels)
+      if (model[i])  break;
+               else  i++;
+    if (i<nModels)
+      model[i]->PDBASCIIDumpPS ( f );
+
+    // output cispep records
+    for (i=0;i<nModels;i++)
+      if (model[i])
+        model[i]->PDBASCIIDumpCP ( f );
+
+    SA      .PDBASCIIDump ( f );
+    Footnote.PDBASCIIDump ( f );
+    cryst   .PDBASCIIDump ( f );
+    SB      .PDBASCIIDump ( f );
+
+    for (i=0;i<nModels;i++)
+      if (model[i])
+        model[i]->PDBASCIIDump ( f );
+
+    SC.PDBASCIIDump ( f );
+
+    f.WriteLine ( pstr("END") );
+
+  }
+
+
+  ERROR_CODE Root::WriteCIFASCII1 ( cpstr CIFLFName,
+                                    io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( CIFLFName );
+    if (FName)  return WriteCIFASCII ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::WriteCIFASCII ( cpstr CIFFileName,
+                                   io::GZ_MODE gzipMode )  {
+  int  i;
+
+    if (!CIF)  CIF = new mmcif::Data();
+    CIF->SetStopOnWarning ( true );
+    CIF->SetPrintWarnings ( (Flags & MMDBF_PrintCIFWarnings)!=0 );
+    FType = MMDB_FILE_CIF;
+
+    title.MakeCIF ( CIF );
+
+    i = 0;
+    while (i<nModels)
+      if (model[i])  break;
+               else  i++;
+    if (i<nModels)
+      model[i]->MakePSCIF ( CIF );
+
+    cryst.MakeCIF ( CIF );
+
+    for (i=0;i<nModels;i++)
+      if (model[i])
+        model[i]->MakeAtomCIF ( CIF );
+
+    CIF->Optimize();
+    CIF->WriteMMCIFData ( CIFFileName,gzipMode );
+
+    return Error_NoError;
+
+  }
+
+
+  PAtom  Root::GetAtomI ( int index )  {
+    if (index>nAtoms)  return NULL;
+    if (index<1)       return NULL;
+    if (!atom)         return NULL;
+    return atom[index-1];
+  }
+
+
+  #define MMDBFLabel  "**** This is MMDB binary file ****"
+  #define Edition     1
+
+  ERROR_CODE Root::ReadMMDBF1 ( cpstr MMDBLFName,
+                                io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( MMDBLFName );
+    if (FName)  return ReadCoorFile ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::ReadMMDBF ( cpstr MMDBRootName,
+                               io::GZ_MODE gzipMode )  {
+  io::File   f;
+  ERROR_CODE rc;
+
+    f.assign ( MMDBRootName,false,true,gzipMode );
+    FType = MMDB_FILE_Binary;
+    if (f.reset(true))  {
+      rc = ReadMMDBF ( f );
+      f.shut();
+    } else
+      rc = Error_CantOpenFile;
+
+    return rc;
+
+  }
+
+  ERROR_CODE Root::ReadMMDBF ( io::RFile f )  {
+  char  Label[100];
+  byte  Version;
+
+    FType = MMDB_FILE_Binary;
+    f.ReadFile ( Label,sizeof(MMDBFLabel) );
+    if (strncmp(Label,MMDBFLabel,sizeof(MMDBFLabel)))
+      return Error_ForeignFile;
+
+    f.ReadByte ( &Version );
+    if (Version>Edition)
+      return Error_WrongEdition;
+
+    read ( f );
+
+    return Error_NoError;
+
+  }
+
+
+  ERROR_CODE Root::WriteMMDBF1 ( cpstr MMDBLFName, io::GZ_MODE gzipMode )  {
+  pstr FName;
+    FName = getenv ( MMDBLFName );
+    if (FName)  return WriteMMDBF ( FName,gzipMode );
+          else  return Error_NoLogicalName;
+  }
+
+  ERROR_CODE Root::WriteMMDBF ( cpstr MMDBRootName, io::GZ_MODE gzipMode )  {
+  io::File f;
+  char     Label[100];
+  byte     Version=Edition;
+
+    f.assign ( MMDBRootName,false,true,gzipMode );
+    FType = MMDB_FILE_Binary;
+    if (f.rewrite())  {
+      strcpy ( Label,MMDBFLabel );
+      f.WriteFile ( Label,sizeof(MMDBFLabel) );
+      f.WriteByte ( &Version );
+      write ( f );
+      f.shut();
+    } else
+      return Error_CantOpenFile;
+
+    return Error_NoError;
+
+  }
+
+
+  pstr  Root::GetEntryID()  {
+    return title.idCode;
+  }
+
+  void  Root::SetEntryID ( const IDCode idCode )  {
+    strcpy ( title.idCode,idCode );
+  }
+
+  void Root::SetSyminfoLib ( cpstr syminfo_lib )  {
+    cryst.SetSyminfoLib ( syminfo_lib );
+  }
+
+  pstr Root::GetSyminfoLib()  {
+    return cryst.GetSyminfoLib();
+  }
+
+  int Root::SetSpaceGroup ( cpstr spGroup )  {
+    return cryst.SetSpaceGroup ( spGroup );
+  }
+
+  pstr Root::GetSpaceGroup()  {
+    return cryst.GetSpaceGroup();
+  }
+
+  pstr Root::GetSpaceGroupFix()  {
+    return cryst.GetSpaceGroupFix();
+  }
+
+  void  Root::GetAtomStatistics ( RAtomStat AS )  {
+  int i;
+    AS.Init();
+    for (i=0;i<nModels;i++)
+      if (model[i])  model[i]->CalAtomStatistics ( AS );
+    AS.Finish();
+  }
+
+  void Root::SetIgnoreSCALEi ( bool ignoreScalei )  {
+    cryst.ignoreScalei = ignoreScalei;
+  }
+
+  void Root::SetCell ( realtype cell_a,
+                            realtype cell_b,
+                            realtype cell_c,
+                            realtype cell_alpha,
+                            realtype cell_beta,
+                            realtype cell_gamma,
+                            int      OrthCode )  {
+    cryst.SetCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
+                    cell_gamma,OrthCode );
+  }
+
+  void Root::PutCell ( realtype cell_a,
+                            realtype cell_b,
+                            realtype cell_c,
+                            realtype cell_alpha,
+                            realtype cell_beta,
+                            realtype cell_gamma,
+                            int      OrthCode )  {
+    cryst.PutCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
+                    cell_gamma,OrthCode );
+  }
+
+  int  Root::GetCell ( realtype & cell_a,
+                            realtype & cell_b,
+                            realtype & cell_c,
+                            realtype & cell_alpha,
+                            realtype & cell_beta,
+                            realtype & cell_gamma,
+                            realtype & vol,
+                            int      & OrthCode )  {
+    if (cryst.WhatIsSet & CSET_CellParams)  {
+      cryst.GetCell ( cell_a,cell_b,cell_c,cell_alpha,cell_beta,
+                      cell_gamma,vol );
+      OrthCode = cryst.NCode + 1;
+      return 1;
+    } else {
+      cell_a     = 0.0;    cell_b    = 0.0;    cell_c     = 0.0;
+      cell_alpha = 0.0;    cell_beta = 0.0;    cell_gamma = 0.0;
+      vol        = 0.0;    OrthCode  = 0;
+      return 0;
+    }
+  }
+
+  int  Root::GetRCell ( realtype & cell_as,
+                             realtype & cell_bs,
+                             realtype & cell_cs,
+                             realtype & cell_alphas,
+                             realtype & cell_betas,
+                             realtype & cell_gammas,
+                             realtype & vols,
+                             int      & OrthCode )  {
+    if (cryst.WhatIsSet & CSET_CellParams)  {
+      cryst.GetRCell ( cell_as,cell_bs,cell_cs,cell_alphas,cell_betas,
+                       cell_gammas,vols );
+      OrthCode = cryst.NCode + 1;
+      return 1;
+    } else {
+      cell_as     = 0.0;    cell_bs    = 0.0;    cell_cs     = 0.0;
+      cell_alphas = 0.0;    cell_betas = 0.0;    cell_gammas = 0.0;
+      vols        = 0.0;    OrthCode   = 0;
+      return 0;
+    }
+  }
+
+  int Root::GetNumberOfSymOps()  {
+    if (cryst.WhatIsSet & CSET_SpaceGroup)
+          return cryst.GetNumberOfSymOps();
+    else  return 0;
+  }
+
+  pstr Root::GetSymOp ( int Nop )  {
+    return cryst.GetSymOp ( Nop );
+  }
+
+
+  void Root::GetROMatrix ( mat44 & RO )  {
+    Mat4Copy ( cryst.RO,RO );
+  }
+
+  int Root::GetTMatrix ( mat44 & TMatrix, int Nop,
+                              int cellshift_a, int cellshift_b,
+                              int cellshift_c )  {
+  //  GetTMatrix(..) calculates and returns the coordinate transformation
+  //  matrix, which converts orthogonal coordinates according to
+  //  the symmetry operation number Nop and places them into unit cell
+  //  shifted by cellshift_a a's, cellshift_b b's and cellshift_c c's.
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+    return cryst.GetTMatrix ( TMatrix,Nop,cellshift_a,cellshift_b,
+                              cellshift_c,NULL );
+  }
+
+
+  int Root::GetUCTMatrix ( mat44 & TMatrix, int Nop,
+                                realtype x, realtype y, realtype z,
+                                int cellshift_a, int cellshift_b,
+                                int cellshift_c )  {
+  //  GetUCTMatrix(..) calculates and returns the coordinate
+  //  transformation matrix, which converts orthogonal coordinates
+  //  according to the symmetry operation number Nop. Translation
+  //  part of the resulting matrix is being chosen such that point
+  //  (x,y,z) has least distance to the center of primary (333)
+  //  unit cell, and then it is shifted by cellshift_a a's,
+  //  cellshift_b b's and cellshift_c c's.
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+    return cryst.GetUCTMatrix ( TMatrix,Nop,x,y,z,
+                                cellshift_a,cellshift_b,cellshift_c,
+                                NULL );
+  }
+
+
+  int Root::GetFractMatrix ( mat44 & TMatrix, int Nop,
+                                  int cellshift_a, int cellshift_b,
+                                  int cellshift_c )  {
+  //  GetFractMatrix(..) calculates and returns the coordinate
+  //  transformation matrix, which converts fractional coordinates
+  //  according to the symmetry operation number Nop and places them
+  //  into unit cell shifted by cellshift_a a's, cellshift_b b's and
+  //  cellshift_c c's.
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+    return cryst.GetFractMatrix ( TMatrix,Nop,cellshift_a,cellshift_b,
+                                  cellshift_c,NULL );
+  }
+
+  int  Root::GetSymOpMatrix ( mat44 & TMatrix, int Nop )  {
+  //
+  //  GetSymOpMatrix(..) returns the transformation matrix for
+  //  Nop-th symmetry operator in the space group
+  //
+  //  Return 0 means everything's fine,
+  //         1 there's no symmetry operation Nop defined
+  //         2 fractionalizing/orthogonalizing matrices were not
+  //           calculated
+  //         3 cell parameters were not set up.
+  //
+    return cryst.GetSymOpMatrix ( TMatrix,Nop );
+  }
+
+  //  -------------  User-Defined Data  ------------------------
+
+  int  Root::RegisterUDInteger ( UDR_TYPE udr_type, cpstr UDDataID )  {
+    return udRegister.RegisterUDInteger ( udr_type,UDDataID );
+  }
+
+  int  Root::RegisterUDReal ( UDR_TYPE udr_type, cpstr UDDataID )  {
+    return udRegister.RegisterUDReal ( udr_type,UDDataID );
+  }
+
+  int  Root::RegisterUDString ( UDR_TYPE udr_type, cpstr UDDataID )  {
+    return udRegister.RegisterUDString ( udr_type,UDDataID );
+  }
+
+  int  Root::GetUDDHandle ( UDR_TYPE udr_type, cpstr UDDataID )  {
+    return udRegister.GetUDDHandle ( udr_type,UDDataID );
+  }
+
+
+
+  //  ----------------------------------------------------------
+
+  int Root::DeleteAllModels()  {
+  int i,k;
+    Exclude = false;
+    k = 0;
+    for (i=0;i<nModels;i++)  {
+      if (model[i])  {
+        delete model[i];
+        model[i] = NULL;
+        k++;
+      }
+    }
+    Exclude = true;
+    FinishStructEdit();
+    return k;
+  }
+
+  bool Root::GetNewChainID ( int modelNo, ChainID chID,
+                                     int length )  {
+    if ((modelNo>=1) && (modelNo<=nModels))  {
+      if (model[modelNo-1])
+        return  model[modelNo-1]->GetNewChainID ( chID,length );
+    }
+    return false;
+  }
+
+  //  -------------------------------------------------------------
+
+  PMask Root::GetSelMask ( int selHnd )  {
+  UNUSED_ARGUMENT(selHnd);
+    return NULL;
+  }
+
+  //  -------------------------------------------------------------
+
+  int  Root::GetNofExpDataRecs()  {
+    return title.expData.Length();
+  }
+
+  pstr  Root::GetExpDataRec ( int recNo )  {
+  PExpData  expData;
+    expData = PExpData(title.expData.GetContainerClass(recNo));
+    if (expData)  return expData->Line;
+    return NULL;
+  }
+
+
+  //  -------------------------------------------------------------
+
+  int  Root::GetNofMdlTypeRecs()  {
+    return title.mdlType.Length();
+  }
+
+  pstr  Root::GetMdlTypeRec ( int recNo )  {
+  PMdlType  mdlType;
+    mdlType = PMdlType(title.mdlType.GetContainerClass(recNo));
+    if (mdlType)  return mdlType->Line;
+    return NULL;
+  }
+
+
+  //  -------------------  Stream functions  ----------------------
+
+  void  Root::Copy ( PRoot MMDBRoot )  {
+  int i;
+
+    title.Copy ( &MMDBRoot->title );
+    cryst.Copy ( &MMDBRoot->cryst );
+
+    //   It is important to copy atoms _before_ models,
+    // residues and chains!
+    Flags  = MMDBRoot->Flags;
+    nAtoms = MMDBRoot->nAtoms;
+    atmLen = nAtoms;
+    if (nAtoms>0)  {
+      atom = new PAtom[atmLen];
+      for (i=0;i<nAtoms;i++)
+        if (MMDBRoot->atom[i])  {
+          atom[i] = newAtom();
+          atom[i]->Copy ( MMDBRoot->atom[i] );
+          atom[i]->index = i+1;
+          // the internal atom references are installed
+          // by residue classes when they are copied in
+          // model->chain below
+        } else
+          atom[i] = NULL;
+    }
+
+    nModels = MMDBRoot->nModels;
+    if (nModels>0)  {
+      model = new PModel[nModels];
+      for (i=0;i<nModels;i++)  {
+        if (MMDBRoot->model[i])  {
+          model[i] = newModel();
+          model[i]->SetMMDBManager ( PManager(this),i+1 );
+          model[i]->_copy ( MMDBRoot->model[i] );
+        } else
+          model[i] = NULL;
+      }
+    }
+
+    SA      .Copy ( &MMDBRoot->SA       );
+    Footnote.Copy ( &MMDBRoot->Footnote );
+    SB      .Copy ( &MMDBRoot->SB       );
+    SC      .Copy ( &MMDBRoot->SC       );
+
+    if (MMDBRoot->CIF)  {
+      CIF = new mmcif::Data;
+      CIF->Copy ( MMDBRoot->CIF );
+    }
+
+  }
+
+
+
+  // -------  user-defined data handlers
+
+  int  Root::PutUDData ( int UDDhandle, int iudd )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::putUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Root::PutUDData ( int UDDhandle, realtype rudd )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::putUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Root::PutUDData ( int UDDhandle, cpstr sudd )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::putUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Root::GetUDData ( int UDDhandle, int & iudd )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::getUDData ( UDDhandle,iudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Root::GetUDData ( int UDDhandle, realtype & rudd )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::getUDData ( UDDhandle,rudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Root::GetUDData ( int UDDhandle, pstr sudd, int maxLen )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::getUDData ( UDDhandle,sudd,maxLen );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+  int  Root::GetUDData ( int UDDhandle, pstr & sudd )  {
+    if (UDDhandle & UDRF_HIERARCHY)
+          return  UDData::getUDData ( UDDhandle,sudd );
+    else  return  UDDATA_WrongUDRType;
+  }
+
+
+  pstr Root::GetStructureTitle ( pstr & L )  {
+    return title.GetStructureTitle ( L );
+  }
+
+  void  Root::SetShortBinary()  {
+  // leaves only coordinates in binary files
+  int i;
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  atom[i]->SetShortBinary();
+  }
+
+
+  void  Root::write ( io::RFile f )  {
+  int  i,k;
+  byte Version=1;
+
+    f.WriteByte ( &Version );
+
+    UDData::write ( f );
+
+    title     .write ( f );
+    cryst     .write ( f );
+    udRegister.write ( f );
+    DefPath   .write ( f );
+
+    f.WriteWord ( &Flags  );
+    f.WriteInt  ( &nAtoms );
+    for (i=0;i<nAtoms;i++)  {
+      if (atom[i])  k = 1;
+              else  k = 0;
+      f.WriteInt ( &k );
+      if (atom[i]) atom[i]->write ( f );
+    }
+
+    f.WriteInt ( &nModels );
+    for (i=0;i<nModels;i++)  {
+      if (model[i])  k = 1;
+               else  k = 0;
+      f.WriteInt ( &k );
+      if (model[i]) model[i]->write ( f );
+    }
+
+    SA      .write ( f );
+    Footnote.write ( f );
+    SB      .write ( f );
+    SC      .write ( f );
+
+    StreamWrite ( f,CIF );
+
+  }
+
+  void  Root::read ( io::RFile f )  {
+  int  i,k;
+  byte Version;
+
+    ResetManager  ();
+    FreeFileMemory();
+
+    f.ReadByte ( &Version );
+
+    UDData::read ( f );
+
+    title     .read ( f );
+    cryst     .read ( f );
+    udRegister.read ( f );
+    DefPath   .read ( f );
+
+    //   It is important to read atoms before models,
+    // residues and chains!
+    f.ReadWord ( &Flags  );
+    f.ReadInt  ( &nAtoms );
+    atmLen = nAtoms;
+    if (nAtoms>0)  {
+      atom = new PAtom[atmLen];
+      for (i=0;i<nAtoms;i++)  {
+        f.ReadInt ( &k );
+        if (k)  {
+          atom[i] = newAtom();
+          atom[i]->read ( f );
+          // the internal atom references are installed
+          // by residue classes when they are read in
+          // model->chain below
+        } else
+          atom[i] = NULL;
+      }
+    }
+
+    f.ReadInt ( &nModels );
+    if (nModels>0)  {
+      model = new PModel[nModels];
+      for (i=0;i<nModels;i++)  {
+        f.ReadInt ( &k );
+        if (k)  {
+          model[i] = newModel();
+          model[i]->SetMMDBManager ( PManager(this),0 );
+          model[i]->read ( f );
+        } else
+          model[i] = NULL;
+      }
+    }
+
+    SA      .read ( f );
+    Footnote.read ( f );
+    SB      .read ( f );
+    SC      .read ( f );
+
+    StreamRead ( f,CIF );
+
+  }
+
+
+  MakeStreamFunctions(Root)
+
+
+  int isMMDBBIN ( cpstr FName, io::GZ_MODE gzipMode )  {
+  io::File f;
+  int   rc;
+
+    f.assign ( FName,false,true,gzipMode );
+    if (f.reset(true))  {
+      rc = isMMDBBIN ( f );
+      f.shut();
+    } else
+      rc = -1;
+
+    return rc;
+
+  }
+
+  int isMMDBBIN ( io::RFile f )  {
+  char  Label[100];
+  byte  Version;
+
+    if (f.FileEnd())
+      return Error_EmptyFile;
+
+    f.ReadFile ( Label,sizeof(MMDBFLabel) );
+    if (strncmp(Label,MMDBFLabel,sizeof(MMDBFLabel)))
+      return 1;
+
+    f.ReadByte ( &Version );
+
+    if (Version>Edition)  return 2;
+                    else  return 0;
+
+  }
+
+
+  int isPDB ( cpstr FName, io::GZ_MODE gzipMode,
+              bool IgnoreBlankLines )  {
+  io::File f;
+  int   rc;
+
+    f.assign ( FName,false,false,gzipMode );
+    if (f.reset(true))  {
+      //  opening it in pseudo-binary mode helps reading various
+      //  line terminators for files coming from different platforms
+      rc = isPDB ( f,IgnoreBlankLines );
+      f.shut();
+    } else
+      rc = -1;
+
+    return rc;
+
+  }
+
+  int isPDB ( io::RFile f, bool IgnoreBlankLines )  {
+  char    S[256];
+  int     i;
+  bool Done;
+
+    if (f.FileEnd())
+      return Error_EmptyFile;
+
+    do {
+      Done = true;
+      f.ReadLine ( S,sizeof(S)-1 );
+      if (IgnoreBlankLines)  {
+        i = 0;
+        while (S[i] && (S[i]==' '))  i++;
+        if (!S[i])  Done = false;
+      }
+    } while ((!f.FileEnd()) && (!Done));
+
+    PadSpaces  ( S,80 );
+    if (!strncasecmp(S,"HEADER",6))  return 0;
+    if (!strncasecmp(S,"OBSLTE",6))  return 0;
+    if (!strncasecmp(S,"TITLE ",6))  return 0;
+    if (!strncasecmp(S,"CAVEAT",6))  return 0;
+    if (!strncasecmp(S,"COMPND",6))  return 0;
+    if (!strncasecmp(S,"SOURCE",6))  return 0;
+    if (!strncasecmp(S,"KEYWDS",6))  return 0;
+    if (!strncasecmp(S,"EXPDTA",6))  return 0;
+    if (!strncasecmp(S,"AUTHOR",6))  return 0;
+    if (!strncasecmp(S,"REVDAT",6))  return 0;
+    if (!strncasecmp(S,"SPRSDE",6))  return 0;
+    if (!strncasecmp(S,"JRNL  ",6))  return 0;
+    if (!strncasecmp(S,"REMARK",6))  return 0;
+    if (!strncasecmp(S,"DBREF ",6))  return 0;
+    if (!strncasecmp(S,"SEQADV",6))  return 0;
+    if (!strncasecmp(S,"SEQRES",6))  return 0;
+    if (!strncasecmp(S,"MODRES",6))  return 0;
+    if (!strncasecmp(S,"HET   ",6))  return 0;
+    if (!strncasecmp(S,"HETNAM",6))  return 0;
+    if (!strncasecmp(S,"HETSYN",6))  return 0;
+    if (!strncasecmp(S,"FORMUL",6))  return 0;
+    if (!strncasecmp(S,"HELIX ",6))  return 0;
+    if (!strncasecmp(S,"SHEET ",6))  return 0;
+    if (!strncasecmp(S,"TURN  ",6))  return 0;
+    if (!strncasecmp(S,"SSBOND",6))  return 0;
+    if (!strncasecmp(S,"LINK  ",6))  return 0;
+    if (!strncasecmp(S,"HYDBND",6))  return 0;
+    if (!strncasecmp(S,"SLTBRG",6))  return 0;
+    if (!strncasecmp(S,"CISPEP",6))  return 0;
+    if (!strncasecmp(S,"SITE  ",6))  return 0;
+    if (!strncasecmp(S,"CRYST1",6))  return 0;
+    if (!strncasecmp(S,"CRYST ",6))  return 0;
+    if (!strncasecmp(S,"ORIGX1",6))  return 0;
+    if (!strncasecmp(S,"ORIGX2",6))  return 0;
+    if (!strncasecmp(S,"ORIGX3",6))  return 0;
+    if (!strncasecmp(S,"SCALE1",6))  return 0;
+    if (!strncasecmp(S,"SCALE2",6))  return 0;
+    if (!strncasecmp(S,"SCALE3",6))  return 0;
+    if (!strncasecmp(S,"MTRIX1",6))  return 0;
+    if (!strncasecmp(S,"MTRIX2",6))  return 0;
+    if (!strncasecmp(S,"MTRIX3",6))  return 0;
+    if (!strncasecmp(S,"TVECT ",6))  return 0;
+    if (!strncasecmp(S,"MODEL ",6))  return 0;
+    if (!strncasecmp(S,"ATOM  ",6))  return 0;
+    if (!strncasecmp(S,"SIGATM",6))  return 0;
+    if (!strncasecmp(S,"ANISOU",6))  return 0;
+    if (!strncasecmp(S,"SIGUIJ",6))  return 0;
+    if (!strncasecmp(S,"TER   ",6))  return 0;
+    if (!strncasecmp(S,"HETATM",6))  return 0;
+    if (!strncasecmp(S,"ENDMDL",6))  return 0;
+    if (!strncasecmp(S,"CONECT",6))  return 0;
+    if (!strncasecmp(S,"MASTER",6))  return 0;
+    if (!strncasecmp(S,"END   ",6))  return 0;
+    if (!strncasecmp(S,"USER  ",6))  return 0;
+
+    return  1;
+
+  }
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_root.h b/mmdb2/mmdb_root.h
new file mode 100644
index 0000000..df5c0e1
--- /dev/null
+++ b/mmdb2/mmdb_root.h
@@ -0,0 +1,639 @@
+//  $Id: mmdb_root.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    14.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Root <interface>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Root
+//       ~~~~~~~~~
+//
+//  (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Root__
+#define __MMDB_Root__
+
+#include "mmdb_io_file.h"
+#include "mmdb_uddata.h"
+#include "mmdb_title.h"
+#include "mmdb_cryst.h"
+#include "mmdb_chain.h"
+#include "mmdb_model.h"
+#include "mmdb_defs.h"
+
+namespace mmdb  {
+
+  // =======================  Root  ===========================
+
+  // special effect flags
+  enum MMDB_READ_FLAG  {
+    MMDBF_AutoSerials            = 0x00000001,
+    MMDBF_NoCoordRead            = 0x00000002,
+    MMDBF_SimRWBROOK             = 0x00000004,
+    MMDBF_PrintCIFWarnings       = 0x00000008,
+    MMDBF_EnforceSpaces          = 0x00000010,
+    MMDBF_IgnoreDuplSeqNum       = 0x00000020,
+    MMDBF_IgnoreSegID            = 0x00000040,
+    MMDBF_IgnoreElement          = 0x00000080,
+    MMDBF_IgnoreCharge           = 0x00000100,
+    MMDBF_IgnoreNonCoorPDBErrors = 0x00000200,
+    MMDBF_IgnoreUnmatch          = 0x00000400,
+    MMDBF_IgnoreBlankLines       = 0x00000800,
+    MMDBF_IgnoreHash             = 0x00001000,
+    MMDBF_IgnoreRemarks          = 0x00002000,
+    MMDBF_AllowDuplChainID       = 0x00004000,
+    MMDBF_FixSpaceGroup          = 0x00008000,
+    MMDBF_EnforceAtomNames       = 0x00010000,
+    MMDBF_EnforceUniqueChainID   = 0x00020000,
+    MMDBF_DoNotProcessSpaceGroup = 0x00040000
+  };
+
+  // MMDBF_EnforceUniqueChainID   will make MMDB to rename chains on
+  //         reading a file such as to maintain chains uniquesness. This
+  //         is supposed to work only with 1-letter chain IDs and only
+  //         if chain names are interchanged in the file. For example,
+  //         if file contains a sequence of chains named
+  //
+  //              A,B, A,B, A,B, A,B, A,B
+  //
+  //         and this flag is set on, the resulting chain names in
+  //         MMDB will be:
+  //
+  //              A,B, A0,B0, A1,B1, A2,B2, A3,B3
+  //
+
+  // file types:
+  enum MMDB_FILE_TYPE  {
+    MMDB_FILE_Undefined = -1,
+    MMDB_FILE_PDB       =  0,
+    MMDB_FILE_CIF       =  1,
+    MMDB_FILE_Binary    =  2
+  };
+
+  // cleanup flags:
+  enum PDB_CLEAN_FLAG  {
+    PDBCLEAN_ATNAME         = 0x00000001,
+    PDBCLEAN_TER            = 0x00000002,
+    PDBCLEAN_CHAIN          = 0x00000004,
+    PDBCLEAN_CHAIN_STRONG   = 0x00000008,
+    PDBCLEAN_ALTCODE        = 0x00000010,
+    PDBCLEAN_ALTCODE_STRONG = 0x00000020,
+    PDBCLEAN_SERIAL         = 0x00000040,
+    PDBCLEAN_SEQNUM         = 0x00000080,
+    PDBCLEAN_CHAIN_ORDER    = 0x00000100,
+    PDBCLEAN_CHAIN_ORDER_IX = 0x00000200,
+    PDBCLEAN_SOLVENT        = 0x00000400,
+    PDBCLEAN_INDEX          = 0x00000800,
+    PDBCLEAN_ELEMENT        = 0x00001000,
+    PDBCLEAN_ELEMENT_STRONG = 0x00002000
+  };
+
+  // crystallographic info inquery
+  enum MMDB_CRYST_FLAG  {
+    CRRDY_NotPrecise       =  0x00000001,
+    CRRDY_isTranslation    =  0x00000002,
+    CRRDY_NoOrthCode       =  0x00000004,
+    CRRDY_Complete         =  0,
+    CRRDY_NoTransfMatrices = -1,
+    CRRDY_Unchecked        = -2,
+    CRRDY_Ambiguous        = -3,
+    CRRDY_NoCell           = -4,
+    CRRDY_NoSpaceGroup     = -5
+  };
+
+  DefineClass(Root);
+  DefineStreamFunctions(Root);
+
+  class Root : public UDData  {
+
+    friend class Model;
+    friend class Chain;
+    friend class Residue;
+    friend class Atom;
+
+    public :
+
+      Root ();
+      Root ( io::RPStream Object );
+      ~Root();
+
+      void  FreeFileMemory();
+
+
+      //  ---------------  Reading/Writing external files  ---------
+
+      void  SetFlag        ( word Flag );
+      void  RemoveFlag     ( word Flag );
+
+      ERROR_CODE ReadPDBASCII   ( cpstr PDBFileName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadPDBASCII1  ( cpstr PDBLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadPDBASCII   ( io::RFile f );
+
+      ERROR_CODE ReadCIFASCII   ( cpstr CIFFileName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadCIFASCII1  ( cpstr CIFLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadCIFASCII   ( io::RFile f );
+      ERROR_CODE ReadFromCIF    ( mmcif::PData CIFD );
+
+      // adds info from PDB file
+      ERROR_CODE AddPDBASCII1   ( cpstr PDBLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE AddPDBASCII    ( cpstr PDBFileName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+      // auto format recognition
+      ERROR_CODE ReadCoorFile   ( cpstr LFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadCoorFile1  ( cpstr CFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadCoorFile   ( io::RFile f );
+
+      ERROR_CODE WritePDBASCII  ( cpstr PDBFileName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE WritePDBASCII1 ( cpstr PDBLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      void       WritePDBASCII  ( io::RFile f );
+
+      ERROR_CODE WriteCIFASCII  ( cpstr CIFFileName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE WriteCIFASCII1 ( cpstr CIFLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+      ERROR_CODE ReadMMDBF      ( cpstr MMDBRootName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadMMDBF1     ( cpstr MMDBLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE ReadMMDBF      ( io::RFile f );
+      ERROR_CODE WriteMMDBF     ( cpstr MMDBRootName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+      ERROR_CODE WriteMMDBF1    ( cpstr MMDBLFName,
+                                  io::GZ_MODE gzipMode=io::GZM_CHECK );
+
+      void  GetInputBuffer ( pstr Line, int & count );
+
+      //  PutPDBString adds a PDB-keyworded string
+      // to the existing structure. Note that the string
+      // is namely added meaning that it will be the
+      // last REMARK, last JRNL, last ATOM etc. string
+      // -- always the last one in its group.
+      ERROR_CODE PutPDBString ( cpstr PDBString );
+
+
+      //  PDBCleanup(..) cleans coordinate part to comply with PDB
+      // standards and MMDB "expectations":
+      //
+      //  PDBCLEAN_ATNAME  pads atom names with spaces to form
+      //                   4-symbol names
+      //  PDBCLEAN_TER     inserts TER cards in the end of each chain
+      //  PDBCLEAN_CHAIN   generates 1-character chain ids instead of
+      //                   those many-character
+      //  PDBCLEAN_CHAIN_STRONG generates 1-character chain ids starting
+      //                   from 'A' on for all ids, including the
+      //                   single-character ones
+      //  PDBCLEAN_ALTCODE generates 1-character alternative codes
+      //                   instead of many-character ones
+      //  PDBCLEAN_ALTCODE_STRONG generates 1-character alternative codes
+      //                   from 'A' on for all codes, including the
+      //                   single-character ones
+      //  PDBCLEAN_SERIAL  puts serial numbers in due order
+      //  PDBCLEAN_SEQNUM  renumbers all residues so that they go
+      //                   incrementally-by-one without insertion codes
+      //  PDBCLEAN_CHAIN_ORDER puts chains in order of atom's serial
+      //                   numbers
+      //  PDBCLEAN_CHAIN_ORDER_IX puts chains in order of atom's
+      //                   indices internal to MMDB
+      //  PDBCLEAN_SOLVENT moves solvent chains at the end of each model
+      //
+      //  Return codes (as bits):
+      //  0                Ok
+      //  PDBCLEAN_CHAIN   too many chains for assigning them
+      //                   1-letter codes
+      //  PDBCLEAN_ATNAME  element names were not available
+      //  PDBCLEAN_ALTCODE too many alternative codes encountered.
+      //
+      word  PDBCleanup ( word CleanKey );
+
+      //     Makes all atoms in chain 'chainID', in all models, as
+      //  'Het' atoms if Make is set True, and makes them 'ordinary'
+      //  atoms otherwise. 'Ter' is automatically removed when
+      //  converting to 'Het' atoms, and is automatically added
+      //  when converting to 'ordinary' atoms. This may cause
+      //  disorder in serial numbers -- just call
+      //  PDBClean(PDBCLEAN_SERIAL) when necessary to fix this.
+      void  MakeHetAtoms ( cpstr chainID, bool Make );
+
+      //  ---------------  Working with atoms by serial numbers  ---
+
+      inline PPAtom GetAtomArray   ()  { return atom;   }
+      inline int GetAtomArrayLength()  { return atmLen; } // strictly not for
+                                               // use in applications!!
+      PAtom  GetAtomI ( int index );   // returns Atom[index-1]
+
+      //   PutAtom(..) puts atom with the specified properties
+      // into the structure. The current model is used; if no model
+      // is set (crModel==NULL), one is created. Coordinates and
+      // other parameters of the atom need to be set separately.
+      //   The place, at which the atom is put, is determined by
+      // index. If index is positive, then it points onto (index-1)th
+      // element of the Atom array (the index counts 1,2,... and
+      // generally coincides with the atom's serial number). If
+      // there is already an atom at this position in the system,
+      // the new atom will REPLACE it. The corresponding residues
+      // are automatically updated.
+      //   If index is null (=0), the new atom will be put on
+      // the top of the structure, i.e. it will be put into
+      // (index=nAtoms+1)-th position.
+      //   If index is negative, then the new atom is INSERTED
+      // BEFORE the atom in the (-index)th position. For saving
+      // the computational efforts, this WILL NOT cause the
+      // recalculation of all atoms' serial numbers according
+      // to their actual positions. It will be needed, however,
+      // for putting the things in order at a certain point,
+      // especially before writing an output ASCII file. NOTE
+      // that this ordering is never done automatically.
+      //   In a correct PDB file the serial number (serNum) is always
+      // equal to its position (index). However here we allow them
+      // to be different for easing the management of relations,
+      // particularly the connectivity.
+      //
+      //   Limitation: if PutAtom implies creating new
+      // chains/residues, these are always created on the top
+      // of existing chains/residues.
+      int   PutAtom ( int            index,
+                      int            serNum,
+                      const AtomName atomName,
+                      const ResName  resName,
+                      const ChainID  chainID,
+                      int            seqNum,
+                      const InsCode  insCode,
+                      const AltLoc   altLoc,
+                      const SegID    segID,
+                      const Element  element );
+
+      int   PutAtom (
+                 int    index,    // same meaning as above
+                 PAtom   A,       // pointer to completed atom class
+                 int    serNum=0  // 0 means that the serial number
+                                  // will be set equal to index.
+                                  // Otherwise the serial number
+                                  // is set to the specified
+                                  // value
+                    );
+
+
+      //    RemoveAtom(..) removes atom at the specified index
+      // in the Atom array. This index is always accessible
+      // as Atom[index]->index. If this leaves a residue empty,
+      // the residue is removed. If this leaves an empty chain,
+      // the chain is removed as well; the same happens to the
+      // model.
+      void  RemoveAtom ( int index );
+
+      int   FinishStructEdit();
+
+      void  TrimModelTable();
+
+      //  ----------------  Deleting models  -----------------------
+
+      int  DeleteAllModels  ();
+      bool GetNewChainID ( int modelNo, ChainID chID, int length=1 );
+
+      //  ---------------  Enquiring -------------------------------
+
+      int   CrystReady();
+      //    Returns flags:
+      // CRRDY_Complete       if crystallographic information is complete
+      // CRRDY_NotPrecise     if cryst. inf-n is not precise
+      // CRRDY_isTranslation  if cryst. inf-n contains translation
+      // CRRDY_NoOrthCode      no orthogonalization code
+      //    Fatal:
+      // CRRDY_NoTransfMatrices  if transform. matrices were not
+      //                         calculated
+      // CRRDY_Unchecked         if cryst. inf-n was not checked
+      // CRRDY_Ambiguous         if cryst. inf-n is ambiguous
+      // CRRDY_NoCell            if cryst. inf-n is unusable
+      // CRRDY_NoSpaceGroup      if space group is not set
+
+
+      bool isCrystInfo   ();  // cell parameters and space group
+      bool isCellInfo    ();  // cell param-s a,b,c, alpha,beta,gamma
+      bool isSpaceGroup  ();  // space group on CRYST1 card
+      bool isTransfMatrix();  // orthogonalizing/fractionalizing
+                                 // matrices
+      bool isScaleMatrix ();  // SCALEx PDB records
+      bool isNCSMatrix   ();  // MTRIXx PDB records
+      int  GetNumberOfNCSMatrices();
+      int  GetNumberOfNCSMates   ();  // Returns the number of
+                                      // NCS mates not given in
+                                      // the file (iGiven==0)
+      bool GetNCSMatrix  ( int NCSMatrixNo, // 0..N-1
+                            mat44 & ncs_m, int & iGiven );
+
+      int  GetNumberOfSymOps ();  // number of symmetry operations
+      pstr GetSymOp ( int Nop );  // XYZ symmetry operation name
+
+
+      //  -------------  User-Defined Data  ------------------------
+
+      int RegisterUDInteger ( UDR_TYPE udr_type, cpstr UDDataID );
+      int RegisterUDReal    ( UDR_TYPE udr_type, cpstr UDDataID );
+      int RegisterUDString  ( UDR_TYPE udr_type, cpstr UDDataID );
+      int GetUDDHandle      ( UDR_TYPE udr_type, cpstr UDDataID );
+
+      //  ----------------------------------------------------------
+
+      void  SetSyminfoLib ( cpstr syminfo_lib );
+      pstr  GetSyminfoLib ();
+      int   SetSpaceGroup ( cpstr spGroup );
+      pstr  GetSpaceGroup ();
+      pstr  GetSpaceGroupFix();
+
+      void  GetAtomStatistics ( RAtomStat AS );
+
+      void  SetIgnoreSCALEi ( bool ignoreScalei );
+
+      //  SetCell(..) is for changing cell parameters
+      void  SetCell ( realtype cell_a,
+                      realtype cell_b,
+                      realtype cell_c,
+                      realtype cell_alpha,
+                      realtype cell_beta,
+                      realtype cell_gamma,
+                      int      OrthCode=0 );
+
+      //  PutCell(..) is for setting cell parameters
+      void  PutCell ( realtype cell_a,
+                      realtype cell_b,
+                      realtype cell_c,
+                      realtype cell_alpha,
+                      realtype cell_beta,
+                      realtype cell_gamma,
+                      int      OrthCode=0 );
+
+      int   GetCell ( realtype & cell_a,
+                      realtype & cell_b,
+                      realtype & cell_c,
+                      realtype & cell_alpha,
+                      realtype & cell_beta,
+                      realtype & cell_gamma,
+                      realtype & vol,
+                      int      & OrthCode );
+
+      int  GetRCell ( realtype & cell_as,
+                      realtype & cell_bs,
+                      realtype & cell_cs,
+                      realtype & cell_alphas,
+                      realtype & cell_betas,
+                      realtype & cell_gammas,
+                      realtype & vols,
+                      int      & OrthCode );
+
+      void GetROMatrix ( mat44 & RO );
+
+      //  GetTMatrix(..) calculates and returns the coordinate
+      //  transformation matrix, which converts orthogonal coordinates
+      //  according to the symmetry operation number Nop and places
+      //  them into unit cell shifted by cellshift_a a's, cellshift_b
+      //  b's and cellshift_c c's.
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      int GetTMatrix ( mat44 & TMatrix, int Nop,
+                       int cellshift_a, int cellshift_b,
+                       int cellshift_c );
+
+      //  GetUCTMatrix(..) calculates and returns the coordinate
+      //  transformation matrix, which converts orthogonal coordinates
+      //  according to the symmetry operation number Nop. Translation
+      //  part of the matrix is being chosen such that point (x,y,z)
+      //  has least distance to the center of primary (333) unit cell,
+      //  and then it is shifted by cellshift_a a's, cellshift_b b's and
+      //  cellshift_c c's.
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      int GetUCTMatrix ( mat44 & TMatrix, int Nop,
+                         realtype x, realtype y, realtype z,
+                         int cellshift_a, int cellshift_b,
+                         int cellshift_c );
+
+      //  GetFractMatrix(..) calculates and returns the coordinate
+      //  transformation matrix, which converts fractional coordinates
+      //  according to the symmetry operation number Nop and places them
+      //  into unit cell shifted by cellshift_a a's, cellshift_b b's
+      //  and cellshift_c c's.
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      int GetFractMatrix ( mat44 & TMatrix, int Nop,
+                           int cellshift_a, int cellshift_b,
+                           int cellshift_c );
+
+
+      //  GetSymOpMatrix(..) returns the transformation matrix for
+      //  Nop-th symmetry operator in the space group
+      //
+      //  Return 0 means everything's fine,
+      //         1 there's no symmetry operation Nop defined
+      //         2 fractionalizing/orthogonalizing matrices were not
+      //           calculated
+      //         3 cell parameters were not set up.
+      //
+      int GetSymOpMatrix ( mat44 & TMatrix, int Nop );
+
+
+      int   AddNCSMatrix    ( mat33 & ncs_m, vect3 & ncs_v, int iGiven );
+      int   GenerateNCSMates(); // 1: no NCS matrices, 0: Ok
+
+      pstr  GetEntryID ();
+      void  SetEntryID ( const IDCode idCode );
+
+      int   GetNofExpDataRecs();
+      pstr  GetExpDataRec ( int recNo );  // 0.. on
+
+      int   GetNofMdlTypeRecs();
+      pstr  GetMdlTypeRec ( int recNo );  // 0.. on
+
+      int   GetFileType() { return FType; }
+
+      void  Copy ( PRoot MMDBRoot );
+
+      void  SetShortBinary();  // leaves only coordinates in binary files
+
+      // -------  user-defined data handlers
+      int   PutUDData ( int UDDhandle, int      iudd );
+      int   PutUDData ( int UDDhandle, realtype rudd );
+      int   PutUDData ( int UDDhandle, cpstr    sudd );
+
+      int   GetUDData ( int UDDhandle, int      & iudd );
+      int   GetUDData ( int UDDhandle, realtype & rudd );
+      int   GetUDData ( int UDDhandle, pstr sudd, int maxLen );
+      int   GetUDData ( int UDDhandle, pstr     & sudd );
+
+      // GetStructureTitle() returns the contents of TITLE record
+      // unfolded into single line. If Title is missing, returns
+      // contents of COMPND(:MOLECULE). If COMPND is missing, returns
+      // HEADER. If Header is missing, returns PDB code. If no PDB
+      // code is there, returns "Not available".
+      pstr  GetStructureTitle ( pstr & L );
+
+      PCryst GetCrystData()  { return &cryst; }
+
+      PClassContainer GetUnparsedA()  { return &SA; }
+      PClassContainer GetUnparsedB()  { return &SB; }
+      PClassContainer GetUnparsedC()  { return &SC; }
+
+    protected :
+
+      word       Flags;    // special effect flags
+      int        FType;    // type of last file operation:
+                           //    -1 : none
+                           //     0 : PDB
+                           //     1 : CIF
+                           //     2 : BIN
+                           // encoded as MMDB_FILE_XXXXX above
+
+      Title      title;    // title section
+      Cryst      cryst;    // crystallographic information section
+      UDRegister udRegister; // register of user-defined data
+
+      int        nModels;  // number of models
+      PPModel    model;    // array of models [0..nModels-1]
+
+      int        nAtoms;   // number of atoms
+      int        atmLen;   // length of Atom array
+      PPAtom     atom;     // array of atoms ordered by serial numbers
+
+      AtomPath   DefPath;  // default coordinate path
+
+      ClassContainer SA;   // string container for unrecognized strings
+                           // which are between the title and the
+                           // crystallographic sections
+      ClassContainer Footnote;  // string container for footnotes
+      ClassContainer SB;   // string container for unrecognized strings
+                           // which are between the crystallographic and
+                           // the coordinate sections
+      ClassContainer SC;   // string container for unrecognized strings
+                           // following the coordinate section
+
+      //  input buffer
+      int          lcount;  // input line counter
+      char         S[500];  // read buffer
+      mmcif::PData CIF;     // CIF file manager
+
+      PModel     crModel; // current model, used at reading a PDB file
+      PChain     crChain; // current chain, used at reading a PDB file
+      PResidue   crRes;   // current residue, used at reading a PDB file
+
+      bool     Exclude;            // used internally
+      bool     ignoreRemarks;      // used temporarily
+      bool     allowDuplChID;      // used temporarily
+      bool     enforceUniqueChID;  // used temporarily
+
+      void       InitMMDBRoot    ();
+      void       FreeCoordMemory ();
+      void       ReadPDBLine     ( io::RFile f, pstr L, int maxlen );
+      ERROR_CODE ReadPDBAtom     ( cpstr L );
+      ERROR_CODE ReadCIFAtom     ( mmcif::PData CIFD   );
+      ERROR_CODE CheckAtomPlace  ( int  index, cpstr L );
+      ERROR_CODE CheckAtomPlace  ( int  index, mmcif::PLoop Loop );
+      ERROR_CODE SwitchModel     ( cpstr L );
+      ERROR_CODE SwitchModel     ( int nM );
+      ERROR_CODE AllocateAtom    ( int           index,
+                                   const ChainID chainID,
+                                   const ChainID label_asym_id,
+                                   const ResName resName,
+                                   const ResName label_comp_id,
+                                   int           seqNum,
+                                   int           label_seq_id,
+                                   int           label_entity_id,
+                                   const InsCode insCode,
+                                   bool          Replace );
+      void  ExpandAtomArray ( int inc );
+      void  AddAtomArray    ( int inc );
+
+      void  ApplyNCSTransform ( int NCSMatrixNo );
+
+      virtual void ResetManager();
+
+      //  ---------------  Stream I/O  -----------------------------
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+      // don't use _ExcludeModel in your applications!
+      int   _ExcludeModel ( int serNum );
+
+      int   CheckInAtom   ( int index, PAtom A );
+      int   CheckInAtoms  ( int index, PPAtom A, int natms );
+
+      virtual PMask GetSelMask ( int selHnd );
+
+    private :
+      int modelCnt;  // used only at reading files
+
+  };
+
+
+
+  //  isMMDBBIN will return
+  //    -1   if file FName does not exist
+  //     0   if file FName is likely a MMDB BIN (binary) file
+  //     1   if file FName is not a MMDB BIN (binary) file
+  //     2   if file FName is likely a MMDB BIN (binary) file,
+  //         but of a wrong edition (i.e. produced by a lower
+  //         version of MMDB).
+  extern int isMMDBBIN ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK );
+  extern int isMMDBBIN ( io::RFile f );
+
+  //  isPDB will return
+  //    -1   if file FName does not exist
+  //     0   if file FName is likely a PDB file
+  //     1   if file FName is not a PDB file
+  extern int isPDB ( cpstr FName, io::GZ_MODE gzipMode=io::GZM_CHECK,
+                     bool IgnoreBlankLines=false );
+  extern int isPDB ( io::RFile f, bool IgnoreBlankLines=false );
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb/mmdb_rwbrook.cpp b/mmdb2/mmdb_rwbrook.cpp
old mode 100755
new mode 100644
similarity index 56%
rename from mmdb/mmdb_rwbrook.cpp
rename to mmdb2/mmdb_rwbrook.cpp
index 52bb4f5..5bc056c
--- a/mmdb/mmdb_rwbrook.cpp
+++ b/mmdb2/mmdb_rwbrook.cpp
@@ -1,4 +1,4 @@
-//  $Id: mmdb_rwbrook.cpp,v 1.46 2012/01/26 17:52:20 ekr Exp $
+//  $Id: mmdb_rwbrook.cpp $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
@@ -6,13 +6,13 @@
 //
 //   Copyright (C) Eugene Krissinel 2000-2008.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -22,164 +22,143 @@
 //
 //  =================================================================
 //
-//    29.01.10   <--  Date of Last Modification.
+//    16.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
-//  **** Module  :   MMDB_RWBrook  <implementation>
+//  **** Module  :  MMDB_RWBrook  <implementation>
 //       ~~~~~~~~~
-//  **** Project :   MacroMolecular Data Base (MMDB)
+//  **** Project :  MacroMolecular Data Base (MMDB), "new rwbrook"
 //       ~~~~~~~~~
-//  **** Classes :   CChannel     ( I/O unit class                  )
-//       ~~~~~~~~~
-//  **** Functions : mmdb_f_init_ ( initializer                       )
-//       ~~~~~~~~~~~ mmdb_f_quit_ ( disposer                          )
-//               autoserials_     ( switch to the autoserials regime  )
-//               setreadcoords_   ( switch for reading coordinates    )
-//               simrwbrook_      ( simulates old RWBROOK printout    )
-//               mmdb_f_openl_    ( associates a unit with a file     )
-//               mmdb_f_open_     ( associates a unit with a file     )
-//               mmdb_f_copy_     ( copies contents of units          )
-//               mmdb_f_delete_   ( deletes part of a unit            )
-//               mmdb_f_settype_  ( changes type of file and r/w mode )
-//               mmdb_f_setname_  ( changes file name                 )
-//               mmdb_f_write_    ( writes a data structure into file )
-//               mmdb_f_close_    ( closes and disposes a data str-re )
-//               mmdb_f_advance_  ( advances the internal pointer     )
-//               mmdb_f_rewd_     ( sets internal pointer on the top  )
-//               mmdb_f_bksp_     ( shifts int-l pointer 1 atom back  )
-//               mmdb_f_atom_     ( reads/writes atom properties      )
-//               mmdb_f_coord_    ( reads/writes atom coordinates     )
-//               mmdb_f_setcell_  ( sets the crystal cell parameters  )
-//               mmdb_f_wbspgrp_  ( sets the space group              )
-//               mmdb_f_rbspgrp_  ( gets the space group              )
-//               mmdb_f_wbcell_   ( sets the crystal cell parameters  )
-//               mmdb_f_rbcell_   ( gets the crystal cell parameters  )
-//               mmdb_f_rbcelln_  ( gets the crystal cell parameters  )
-//               mmdb_f_rbrcel_   ( gets the recipricol cell          )
-//               mmdb_f_rborf_    ( returns or fill transf. matrices  )
-//               mmdb_f_orthmat_  ( calc. standard othogonalisations  )
-//               mmdb_f_cvanisou_ ( converts between cryst-c units    )
-//               mmdb_f_wremark_  ( writes a remark statement         )
-//               mmdb_f_setter
-//               mmdb_f_sethet
-//               rberrstop_       ( error messenger                   )
-//               rbcheckerr_      ( a simple  error messenger         )
+//  **** Functions : mmdb_f_init_     ( initializer                       )
+//       ~~~~~~~~~~~ mmdb_f_quit_     ( disposer                          )
+//                   autoserials_     ( switch to the autoserials regime  )
+//                   setreadcoords_   ( switch for reading coordinates    )
+//                   simrwbrook_      ( simulates old RWBROOK printout    )
+//                   mmdb_f_openl_    ( associates a unit with a file     )
+//                   mmdb_f_open_     ( associates a unit with a file     )
+//                   mmdb_f_copy_     ( copies contents of units          )
+//                   mmdb_f_delete_   ( deletes part of a unit            )
+//                   mmdb_f_settype_  ( changes type of file and r/w mode )
+//                   mmdb_f_setname_  ( changes file name                 )
+//                   mmdb_f_write_    ( writes a data structure into file )
+//                   mmdb_f_close_    ( closes and disposes a data str-re )
+//                   mmdb_f_advance_  ( advances the internal pointer     )
+//                   mmdb_f_rewd_     ( sets internal pointer on the top  )
+//                   mmdb_f_bksp_     ( shifts int-l pointer 1 atom back  )
+//                   mmdb_f_atom_     ( reads/writes atom properties      )
+//                   mmdb_f_coord_    ( reads/writes atom coordinates     )
+//                   mmdb_f_setcell_  ( sets the crystal cell parameters  )
+//                   mmdb_f_wbspgrp_  ( sets the space group              )
+//                   mmdb_f_rbspgrp_  ( gets the space group              )
+//                   mmdb_f_wbcell_   ( sets the crystal cell parameters  )
+//                   mmdb_f_rbcell_   ( gets the crystal cell parameters  )
+//                   mmdb_f_rbcelln_  ( gets the crystal cell parameters  )
+//                   mmdb_f_rbrcel_   ( gets the recipricol cell          )
+//                   mmdb_f_rborf_    ( returns or fill transf. matrices  )
+//                   mmdb_f_orthmat_  ( calc. standard othogonalisations  )
+//                   mmdb_f_cvanisou_ ( converts between cryst-c units    )
+//                   mmdb_f_wremark_  ( writes a remark statement         )
+//                   mmdb_f_setter
+//                   mmdb_f_sethet
+//                   rberrstop_       ( error messenger                   )
+//                   rbcheckerr_      ( a simple error messenger          )
 //
-//  (C) E. Krissinel 2000-2010
+//  (C) E. Krissinel 2000-2013
 //
 //  =================================================================
 //
-//  Note: what if the orthogonalization code is not defined?
-//
 
-#ifndef  __STRING_H
 #include "string.h"
-#endif
-
-#ifndef  __STDLIB_H
 #include "stdlib.h"
-#endif
-
-#ifndef  __MATH_H
 #include "math.h"
-#endif
 
-#ifndef  __MMDB_RWBrook__
 #include "mmdb_rwbrook.h"
-#endif
-
-#ifndef  __MMDB_Manager__
 #include "mmdb_manager.h"
-#endif
-
-#ifndef  __MMDB_Tables__
 #include "mmdb_tables.h"
-#endif
-
 #include "hybrid_36.h"
 
-//  ==========================  CChannel  ===========================
+//  ==========================  Channel  ===========================
 
-DefineClass(CChannel)
+DefineClass(Channel)
 
-class CChannel {
+class Channel {
 
   public :
 
-    int           nUnit;       // unit number
-    int           nType;       // unit type: 0- PDB; 1- CIF; 2- binary
-    int           nRead;       // 0: input, 1: output
-    PCMMDBManager MMDBManager; // MMDB manager
-    pstr          FName;       // file name
-    int           fPos;        // "position" in the file
-    int           ErrCode;     // error code of last operation
-    Boolean       FAutoSer;    // autoserials flag for reading PDB
-    Boolean       FReadCoords; // flag to read coordinate section
-    Boolean       FSimRWBROOK; // flag to simulate old RWBROOK's printout
-
-    CChannel ();
-    ~CChannel();
-
-    void     Dispose();
-    void     Init   ();
-
-    void     SetFileType ( pstr FType );
-    void     SetFileName ( pstr FileName, int FNameLen );
-    void     IdentifyFile( pstr ExistingFName );
-
-    Boolean  EndOfFile   ();
-    PCAtom * GetAtomArray();
-    PCAtom   GetAtomI    ( int index );
-
-    PCMMDBCryst GetCryst ();
-
-    Boolean  areCrystMatrices();
-    void     Frac2Orth   (
-                realtype x,    realtype y,    realtype z,
-                realtype & xx, realtype & yy, realtype & zz );
-    void     Orth2Frac   (
-                realtype x,    realtype y,    realtype z,
-                realtype & xx, realtype & yy, realtype & zz );
-    void     Cryst2Orth  ( rvector U );
-    void     Orth2Cryst  ( rvector U );
-    int      SetCell     ( realtype cell_a,
-                           realtype cell_b,
-                           realtype cell_c,
-                           realtype cell_alpha,
-                           realtype cell_beta,
-                           realtype cell_gamma,
-                           int      OrthCode );
-    int      PutCell     ( realtype cell_a,
-                           realtype cell_b,
-                           realtype cell_c,
-                           realtype cell_alpha,
-                           realtype cell_beta,
-                           realtype cell_gamma,
-                           int      OrthCode );
-    int      SetSpGroup  ( pstr     spGroup );
-    int      GetSpGroup  ( pstr     spGroup );
-    int      GetCell     ( realtype & cell_a,
-                           realtype & cell_b,
-                           realtype & cell_c,
-                           realtype & cell_alpha,
-                           realtype & cell_beta,
-                           realtype & cell_gamma,
-                           realtype & cell_v,
-                           int      & OrthCode );
-    int      GetRCell    ( realtype & cell_as,
-                           realtype & cell_bs,
-                           realtype & cell_cs,
-                           realtype & cell_alphas,
-                           realtype & cell_betas,
-                           realtype & cell_gammas,
-                           realtype & cell_vs );
+    int            nUnit;       // unit number
+    int            nType;       // unit type: 0- PDB; 1- CIF; 2- binary
+    int            nRead;       // 0: input, 1: output
+    mmdb::PManager MMDBManager; // MMDB manager
+    mmdb::pstr     FName;       // file name
+    int            fPos;        // "position" in the file
+    int            ErrCode;     // error code of last operation
+    bool           FAutoSer;    // autoserials flag for reading PDB
+    bool           FReadCoords; // flag to read coordinate section
+    bool           FSimRWBROOK; // flag to simulate old RWBROOK's printout
+
+    Channel ();
+    ~Channel();
+
+    void    Dispose();
+    void    Init   ();
+
+    void    SetFileType ( mmdb::pstr FType );
+    void    SetFileName ( mmdb::pstr FileName, int FNameLen );
+    void    IdentifyFile( mmdb::pstr ExistingFName );
+
+    bool    EndOfFile   ();
+    mmdb::PAtom * GetAtomArray();
+    mmdb::PAtom   GetAtomI    ( int index );
+
+    mmdb::PCryst GetCryst ();
+
+    bool   areCrystMatrices();
+    void   Frac2Orth   (
+                mmdb::realtype x,    mmdb::realtype y,    mmdb::realtype z,
+                mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz );
+    void   Orth2Frac   (
+                mmdb::realtype x,    mmdb::realtype y,    mmdb::realtype z,
+                mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz );
+    void   Cryst2Orth  ( mmdb::rvector U );
+    void   Orth2Cryst  ( mmdb::rvector U );
+    int    SetCell     ( mmdb::realtype cell_a,
+                         mmdb::realtype cell_b,
+                         mmdb::realtype cell_c,
+                         mmdb::realtype cell_alpha,
+                         mmdb::realtype cell_beta,
+                         mmdb::realtype cell_gamma,
+                         int      OrthCode );
+    int    PutCell     ( mmdb::realtype cell_a,
+                         mmdb::realtype cell_b,
+                         mmdb::realtype cell_c,
+                         mmdb::realtype cell_alpha,
+                         mmdb::realtype cell_beta,
+                         mmdb::realtype cell_gamma,
+                         int      OrthCode );
+    int    SetSpGroup  ( mmdb::pstr     spGroup );
+    int    GetSpGroup  ( mmdb::pstr     spGroup );
+    int    GetCell     ( mmdb::realtype & cell_a,
+                         mmdb::realtype & cell_b,
+                         mmdb::realtype & cell_c,
+                         mmdb::realtype & cell_alpha,
+                         mmdb::realtype & cell_beta,
+                         mmdb::realtype & cell_gamma,
+                         mmdb::realtype & cell_v,
+                         int      & OrthCode );
+    int    GetRCell    ( mmdb::realtype & cell_as,
+                         mmdb::realtype & cell_bs,
+                         mmdb::realtype & cell_cs,
+                         mmdb::realtype & cell_alphas,
+                         mmdb::realtype & cell_betas,
+                         mmdb::realtype & cell_gammas,
+                         mmdb::realtype & cell_vs );
 
     void MakeCoordStructure();
     void Read ();
     void Write();
 
-    void GetInputBuffer ( pstr Line, int & count );
+    void GetInputBuffer ( mmdb::pstr Line, int & count );
 
   protected :
 
@@ -187,15 +166,15 @@ class CChannel {
 
 };
 
-CChannel::CChannel()  {
+Channel::Channel()  {
   Init();
 }
 
-CChannel::~CChannel()  {
+Channel::~Channel()  {
   Dispose();
 }
 
-void CChannel::Init()  {
+void Channel::Init()  {
   nUnit       = -1;
   nType       = -1;
   nRead       = 0;
@@ -203,12 +182,12 @@ void CChannel::Init()  {
   FName       = NULL;
   ErrCode     = 0;
   fPos        = 0;
-  FAutoSer    = False;
-  FReadCoords = True;
-  FSimRWBROOK = False;
+  FAutoSer    = false;
+  FReadCoords = true;
+  FSimRWBROOK = false;
 }
 
-void CChannel::Dispose()  {
+void Channel::Dispose()  {
   if (MMDBManager)  delete MMDBManager;
   if (FName)        delete[] FName;
   MMDBManager = NULL;
@@ -221,13 +200,13 @@ void CChannel::Dispose()  {
 }
 
 
-void CChannel::SetFileType ( pstr FType )  {
+void Channel::SetFileType ( mmdb::pstr FType )  {
   switch (FType[0])  {
     default  :
     case ' ' :  if (nRead==0)
                      nType = -1;                  // auto at reading
                 else if (MMDBManager)
-                     nType = MMDBManager->FType;  // auto at writing
+                     nType = MMDBManager->GetFileType(); // auto at writing
                 else nType = -1;
               break;
     case 'P' :  nType = 0;   break;  // PDB
@@ -236,41 +215,41 @@ void CChannel::SetFileType ( pstr FType )  {
   }
 }
 
-void CChannel::IdentifyFile ( pstr ExistingFName )  {
+void Channel::IdentifyFile ( mmdb::pstr ExistingFName )  {
   if (nType==-1)  {
     if (ExistingFName)  {
-      if  (isMMDBBIN(ExistingFName)==0)  nType = 2;
-      else if (isPDB(ExistingFName,GZM_CHECK,True)==0)
+      if  (mmdb::isMMDBBIN(ExistingFName)==0)  nType = 2;
+      else if (mmdb::isPDB(ExistingFName,mmdb::io::GZM_CHECK,true)==0)
                                          nType = 0;
-      else if (isCIF(ExistingFName)==0)  nType = 1;
+      else if (mmdb::mmcif::isCIF(ExistingFName)==0)  nType = 1;
                                    else  nType = -2;  // unidentified
     } else  {
       if (MMDBManager)  {
-        if (MMDBManager->FType<0)
+        if (MMDBManager->GetFileType()<0)
               nType = 0;                  // PDB
-        else  nType = MMDBManager->FType; // same as it was on last input
+        else  nType = MMDBManager->GetFileType(); // same as it was on last input
       } else  nType = 0;
     }
   }
 }
 
-void CChannel::SetFileName ( pstr FileName, int FNameLen )  {
+void Channel::SetFileName ( mmdb::pstr FileName, int FNameLen )  {
   if (FName)  delete[] FName;
   FName = new char[FNameLen+1];
   strncpy ( FName,FileName,FNameLen );
   FName[FNameLen] = char(0);
 }
 
-void CChannel::MakeCoordStructure()  {
+void Channel::MakeCoordStructure()  {
   if (MMDBManager)
-    MMDBManager->Delete ( MMDBFCM_All );
+    MMDBManager->Delete ( mmdb::MMDBFCM_All );
   else  {
-    MMDBManager = new CMMDBManager();
-    MMDBManager->SetFlag ( MMDBF_AllowDuplChainID );
+    MMDBManager = new mmdb::Manager();
+    MMDBManager->SetFlag ( mmdb::MMDBF_AllowDuplChainID );
   }
 }
 
-void CChannel::Read()  {
+void Channel::Read()  {
 int RC;
 
   ErrCode = -2;
@@ -280,18 +259,18 @@ int RC;
 
   IdentifyFile ( FName );
 
-  if (FAutoSer)     MMDBManager->SetFlag    ( MMDBF_AutoSerials );
-           else     MMDBManager->RemoveFlag ( MMDBF_AutoSerials );
-  if (FReadCoords)  MMDBManager->RemoveFlag ( MMDBF_NoCoordRead );
-              else  MMDBManager->SetFlag    ( MMDBF_NoCoordRead );
-  if (FSimRWBROOK)  MMDBManager->SetFlag    ( MMDBF_SimRWBROOK  );
-              else  MMDBManager->RemoveFlag ( MMDBF_SimRWBROOK  );
+  if (FAutoSer)     MMDBManager->SetFlag    ( mmdb::MMDBF_AutoSerials );
+           else     MMDBManager->RemoveFlag ( mmdb::MMDBF_AutoSerials );
+  if (FReadCoords)  MMDBManager->RemoveFlag ( mmdb::MMDBF_NoCoordRead );
+              else  MMDBManager->SetFlag    ( mmdb::MMDBF_NoCoordRead );
+  if (FSimRWBROOK)  MMDBManager->SetFlag    ( mmdb::MMDBF_SimRWBROOK  );
+              else  MMDBManager->RemoveFlag ( mmdb::MMDBF_SimRWBROOK  );
 
-  MMDBManager->SetFlag ( MMDBF_IgnoreDuplSeqNum | 
-                         MMDBF_IgnoreBlankLines |
-                         MMDBF_IgnoreRemarks    |
-                         MMDBF_IgnoreNonCoorPDBErrors |
-                         MMDBF_AllowDuplChainID );
+  MMDBManager->SetFlag ( mmdb::MMDBF_IgnoreDuplSeqNum |
+                         mmdb::MMDBF_IgnoreBlankLines |
+                         mmdb::MMDBF_IgnoreRemarks    |
+                         mmdb::MMDBF_IgnoreNonCoorPDBErrors |
+                         mmdb::MMDBF_AllowDuplChainID );
 
   switch (nType)  {
     default : nType   = 0;  // nType=-2: unidentified: try PDB
@@ -302,10 +281,10 @@ int RC;
   if (ErrCode==0)  {
     RC = MMDBManager->CrystReady();
     switch (RC)  {
-      case CRRDY_NoTransfMatrices : ErrCode = RWBERR_NoMatrices;   break;
-      case CRRDY_Unchecked        : ErrCode = RWBERR_NoCheck;      break;
-      case CRRDY_Ambiguous        : ErrCode = RWBERR_Disagreement; break;
-      case CRRDY_NoCell           : ErrCode = RWBERR_NoCellParams; break;
+      case mmdb::CRRDY_NoTransfMatrices : ErrCode = RWBERR_NoMatrices;   break;
+      case mmdb::CRRDY_Unchecked        : ErrCode = RWBERR_NoCheck;      break;
+      case mmdb::CRRDY_Ambiguous        : ErrCode = RWBERR_Disagreement; break;
+      case mmdb::CRRDY_NoCell           : ErrCode = RWBERR_NoCellParams; break;
       default : ;
     }
   }
@@ -313,7 +292,7 @@ int RC;
   TranslateError();
 }
 
-void CChannel::Write()  {
+void Channel::Write()  {
   ErrCode = -3;
   if ((!MMDBManager) || (!FName))  return;
   IdentifyFile ( FName );
@@ -327,52 +306,52 @@ void CChannel::Write()  {
   TranslateError();
 }
 
-void  CChannel::TranslateError()  {
+void  Channel::TranslateError()  {
 
   switch (ErrCode)  {
 
-    case Error_CantOpenFile        : ErrCode = RWBERR_CantOpenFile;     break;
-    case Error_UnrecognizedInteger : ErrCode = RWBERR_WrongInteger;     break;
-    case Error_NoData             : ErrCode = RWBERR_NotACIFFile;       break;
-    case Error_WrongModelNo       : ErrCode = RWBERR_WrongModelNo;      break;
-    case Error_DuplicatedModel    : ErrCode = RWBERR_DuplicatedModel;   break;
-    case Error_ForeignFile        : ErrCode = RWBERR_ForeignFile;       break;
-    case Error_WrongEdition       : ErrCode = RWBERR_WrongEdition;      break;
-    case Error_ATOM_Unrecognized  : ErrCode = RWBERR_ATOM_Unrecognd;    break;
-    case Error_ATOM_AlreadySet    : ErrCode = RWBERR_ATOM_AlreadySet;   break;
-    case Error_ATOM_NoResidue     : ErrCode = RWBERR_ATOM_NoResidue;    break;
-    case Error_ATOM_Unmatch       : ErrCode = RWBERR_ATOM_Unmatch;      break;
-    case Error_NotACIFFile        : ErrCode = RWBERR_NotACIFFile;       break;
-    case Error_UnrecognCIFItems   : ErrCode = RWBERR_UnrecognCIFItems;  break;
-    case Error_MissingCIFField    : ErrCode = RWBERR_MissingCIFField;   break;
-    case Error_EmptyCIFLoop       : ErrCode = RWBERR_EmptyCIFLoop;      break;
-    case Error_UnexpEndOfCIF      : ErrCode = RWBERR_UnexpEndOfCIF;     break;
-    case Error_MissgCIFLoopField  : ErrCode = RWBERR_MissgCIFLoopField; break;
-    case Error_NotACIFStructure   : ErrCode = RWBERR_NotACIFStructure;  break;
-    case Error_NotACIFLoop        : ErrCode = RWBERR_NotACIFLoop;       break;
-    case Error_UnrecognizedReal   : ErrCode = RWBERR_WrongReal;         break;
-
-    case Error_Ok                 : ErrCode = RWBERR_Ok;                break;
-    case Error_WrongChainID       : ErrCode = RWBERR_WrongChainID;      break;
-    case Error_WrongEntryID       : ErrCode = RWBERR_WrongEntryID;      break;
-    case Error_SEQRES_serNum      : ErrCode = RWBERR_SEQRES_serNum;     break;
-    case Error_SEQRES_numRes      : ErrCode = RWBERR_SEQRES_numRes;     break;
-    case Error_SEQRES_extraRes    : ErrCode = RWBERR_SEQRES_exraRes;    break;
-    case Error_NCSM_Unrecognized  : ErrCode = RWBERR_NCSM_Unrecogn;     break;
-    case Error_NCSM_AlreadySet    : ErrCode = RWBERR_NCSM_AlreadySet;   break;
-    case Error_NCSM_WrongSerial   : ErrCode = RWBERR_NCSM_WrongSerial;  break;
-    case Error_NCSM_UnmatchIG     : ErrCode = RWBERR_NCSM_UnmatchIG;    break;
-    case Error_NoModel            : ErrCode = RWBERR_NoModel;           break;
-    case Error_NoSheetID          : ErrCode = RWBERR_NoSheetID;         break;
-    case Error_WrongSheetID       : ErrCode = RWBERR_WrongSheetID;      break;
-    case Error_WrongStrandNo      : ErrCode = RWBERR_WrongStrandNo;     break;
-    case Error_WrongNumberOfStrands : ErrCode = RWBERR_WrongNofStrands; break;
-    case Error_WrongSheetOrder    : ErrCode = RWBERR_WrongSheetOrder;   break;
-    case Error_HBondInconsistency : ErrCode = RWBERR_HBondInconsis;     break;
-    case Error_EmptyResidueName   : ErrCode = RWBERR_EmptyResidueName;  break;
-    case Error_DuplicateSeqNum    : ErrCode = RWBERR_DuplicateSeqNum;   break;
-    case Error_NoLogicalName      : ErrCode = RWBERR_NoLogicalName;     break;
-    case Error_GeneralError1      : ErrCode = RWBERR_GeneralError1;     break;
+    case mmdb::Error_CantOpenFile        : ErrCode = RWBERR_CantOpenFile;     break;
+    case mmdb::Error_UnrecognizedInteger : ErrCode = RWBERR_WrongInteger;     break;
+    case mmdb::Error_NoData             : ErrCode = RWBERR_NotACIFFile;       break;
+    case mmdb::Error_WrongModelNo       : ErrCode = RWBERR_WrongModelNo;      break;
+    case mmdb::Error_DuplicatedModel    : ErrCode = RWBERR_DuplicatedModel;   break;
+    case mmdb::Error_ForeignFile        : ErrCode = RWBERR_ForeignFile;       break;
+    case mmdb::Error_WrongEdition       : ErrCode = RWBERR_WrongEdition;      break;
+    case mmdb::Error_ATOM_Unrecognized  : ErrCode = RWBERR_ATOM_Unrecognd;    break;
+    case mmdb::Error_ATOM_AlreadySet    : ErrCode = RWBERR_ATOM_AlreadySet;   break;
+    case mmdb::Error_ATOM_NoResidue     : ErrCode = RWBERR_ATOM_NoResidue;    break;
+    case mmdb::Error_ATOM_Unmatch       : ErrCode = RWBERR_ATOM_Unmatch;      break;
+    case mmdb::Error_NotACIFFile        : ErrCode = RWBERR_NotACIFFile;       break;
+    case mmdb::Error_UnrecognCIFItems   : ErrCode = RWBERR_UnrecognCIFItems;  break;
+    case mmdb::Error_MissingCIFField    : ErrCode = RWBERR_MissingCIFField;   break;
+    case mmdb::Error_EmptyCIFLoop       : ErrCode = RWBERR_EmptyCIFLoop;      break;
+    case mmdb::Error_UnexpEndOfCIF      : ErrCode = RWBERR_UnexpEndOfCIF;     break;
+    case mmdb::Error_MissgCIFLoopField  : ErrCode = RWBERR_MissgCIFLoopField; break;
+    case mmdb::Error_NotACIFStructure   : ErrCode = RWBERR_NotACIFStructure;  break;
+    case mmdb::Error_NotACIFLoop        : ErrCode = RWBERR_NotACIFLoop;       break;
+    case mmdb::Error_UnrecognizedReal   : ErrCode = RWBERR_WrongReal;         break;
+
+    case mmdb::Error_Ok                 : ErrCode = RWBERR_Ok;                break;
+    case mmdb::Error_WrongChainID       : ErrCode = RWBERR_WrongChainID;      break;
+    case mmdb::Error_WrongEntryID       : ErrCode = RWBERR_WrongEntryID;      break;
+    case mmdb::Error_SEQRES_serNum      : ErrCode = RWBERR_SEQRES_serNum;     break;
+    case mmdb::Error_SEQRES_numRes      : ErrCode = RWBERR_SEQRES_numRes;     break;
+    case mmdb::Error_SEQRES_extraRes    : ErrCode = RWBERR_SEQRES_exraRes;    break;
+    case mmdb::Error_NCSM_Unrecognized  : ErrCode = RWBERR_NCSM_Unrecogn;     break;
+    case mmdb::Error_NCSM_AlreadySet    : ErrCode = RWBERR_NCSM_AlreadySet;   break;
+    case mmdb::Error_NCSM_WrongSerial   : ErrCode = RWBERR_NCSM_WrongSerial;  break;
+    case mmdb::Error_NCSM_UnmatchIG     : ErrCode = RWBERR_NCSM_UnmatchIG;    break;
+    case mmdb::Error_NoModel            : ErrCode = RWBERR_NoModel;           break;
+    case mmdb::Error_NoSheetID          : ErrCode = RWBERR_NoSheetID;         break;
+    case mmdb::Error_WrongSheetID       : ErrCode = RWBERR_WrongSheetID;      break;
+    case mmdb::Error_WrongStrandNo      : ErrCode = RWBERR_WrongStrandNo;     break;
+    case mmdb::Error_WrongNumberOfStrands : ErrCode = RWBERR_WrongNofStrands; break;
+    case mmdb::Error_WrongSheetOrder    : ErrCode = RWBERR_WrongSheetOrder;   break;
+    case mmdb::Error_HBondInconsistency : ErrCode = RWBERR_HBondInconsis;     break;
+    case mmdb::Error_EmptyResidueName   : ErrCode = RWBERR_EmptyResidueName;  break;
+    case mmdb::Error_DuplicateSeqNum    : ErrCode = RWBERR_DuplicateSeqNum;   break;
+    case mmdb::Error_NoLogicalName      : ErrCode = RWBERR_NoLogicalName;     break;
+    case mmdb::Error_GeneralError1      : ErrCode = RWBERR_GeneralError1;     break;
 
     default : ;
   }
@@ -380,46 +359,46 @@ void  CChannel::TranslateError()  {
 
 }
 
-Boolean CChannel::EndOfFile()  {
+bool Channel::EndOfFile()  {
 int nA;
   if (MMDBManager)  {
     nA = MMDBManager->GetNumberOfAtoms();
     if (fPos>nA)  {
       fPos = nA+1;
-      return True;
+      return true;
     }
   } else
-    return  True;
-  return False;
+    return  true;
+  return false;
 }
 
-PCAtom * CChannel::GetAtomArray()  {
+mmdb::PAtom * Channel::GetAtomArray()  {
   if (MMDBManager)  return MMDBManager->GetAtomArray();
               else  return NULL;
 }
 
-PCAtom CChannel::GetAtomI ( int index )  {
+mmdb::PAtom Channel::GetAtomI ( int index )  {
 // returns index-th atom, as counted from the
 // top of file
   if (MMDBManager)  return MMDBManager->GetAtomI ( index );
               else  return NULL;
 }
 
-PCMMDBCryst CChannel::GetCryst()  {
-  if (MMDBManager)  return &(MMDBManager->Cryst);
+mmdb::PCryst Channel::GetCryst()  {
+  if (MMDBManager)  return MMDBManager->GetCrystData();
               else  return NULL;
 }
 
-Boolean CChannel::areCrystMatrices()  {
-  if (MMDBManager)  return MMDBManager->Cryst.areMatrices();
-              else  return False;
+bool Channel::areCrystMatrices()  {
+  if (MMDBManager)  return MMDBManager->isTransfMatrix();
+              else  return false;
 }
 
-void  CChannel::Frac2Orth (
-                realtype x,    realtype y,    realtype z,
-                realtype & xx, realtype & yy, realtype & zz )  {
+void  Channel::Frac2Orth (
+                mmdb::realtype x,    mmdb::realtype y,    mmdb::realtype z,
+                mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz )  {
   if (MMDBManager)
-    MMDBManager->Cryst.Frac2Orth ( x,y,z,xx,yy,zz );
+    MMDBManager->Frac2Orth ( x,y,z,xx,yy,zz );
   else  {
     xx = x;
     yy = y;
@@ -427,11 +406,11 @@ void  CChannel::Frac2Orth (
   }
 }
 
-void  CChannel::Orth2Frac (
-                realtype x,    realtype y,    realtype z,
-                realtype & xx, realtype & yy, realtype & zz )  {
+void  Channel::Orth2Frac (
+                mmdb::realtype x,    mmdb::realtype y,    mmdb::realtype z,
+                mmdb::realtype & xx, mmdb::realtype & yy, mmdb::realtype & zz )  {
   if (MMDBManager)
-    MMDBManager->Cryst.Orth2Frac ( x,y,z,xx,yy,zz );
+    MMDBManager->Orth2Frac ( x,y,z,xx,yy,zz );
   else  {
     xx = x;
     yy = y;
@@ -439,37 +418,38 @@ void  CChannel::Orth2Frac (
   }
 }
 
-void  CChannel::Cryst2Orth ( rvector U )  {
+void  Channel::Cryst2Orth ( mmdb::rvector U )  {
   if (MMDBManager)
-    MMDBManager->Cryst.Cryst2Orth ( U );
+    MMDBManager->GetCrystData()->Cryst2Orth ( U );
 }
 
-void  CChannel::Orth2Cryst ( rvector U )  {
+void  Channel::Orth2Cryst ( mmdb::rvector U )  {
   if (MMDBManager)
-    MMDBManager->Cryst.Orth2Cryst ( U );
+    MMDBManager->GetCrystData()->Orth2Cryst ( U );
 }
 
 
-int  CChannel::PutCell ( realtype cell_a,
-                         realtype cell_b,
-                         realtype cell_c,
-                         realtype cell_alpha,
-                         realtype cell_beta,
-                         realtype cell_gamma,
+int  Channel::PutCell ( mmdb::realtype cell_a,
+                         mmdb::realtype cell_b,
+                         mmdb::realtype cell_c,
+                         mmdb::realtype cell_alpha,
+                         mmdb::realtype cell_beta,
+                         mmdb::realtype cell_gamma,
                          int      OrthCode )  {
 
   if (MMDBManager)  {
-    
-    MMDBManager->Cryst.PutCell ( cell_a,cell_b,cell_c,
-                                 cell_alpha,cell_beta,cell_gamma,
-                                 OrthCode );
+    mmdb::PCryst cryst = MMDBManager->GetCrystData();
+
+    cryst->PutCell ( cell_a,cell_b,cell_c,
+                     cell_alpha,cell_beta,cell_gamma,
+                     OrthCode );
 
     if ((cell_a!=0.0) || (OrthCode>0))  {
-      if (MMDBManager->Cryst.CellCheck & CCHK_Disagreement)
+      if (cryst->CellCheck & mmdb::CCHK_Disagreement)
         return RWBERR_Disagreement;
-      if (MMDBManager->Cryst.CellCheck & CCHK_NoOrthCode)
+      if (cryst->CellCheck & mmdb::CCHK_NoOrthCode)
         return RWBERR_NoOrthCode;
-      if (MMDBManager->Cryst.CellCheck & CCHK_Unchecked)
+      if (cryst->CellCheck & mmdb::CCHK_Unchecked)
         return RWBERR_NoCheck;
     }
 
@@ -482,25 +462,26 @@ int  CChannel::PutCell ( realtype cell_a,
 }
 
 
-int  CChannel::SetCell ( realtype cell_a,
-                         realtype cell_b,
-                         realtype cell_c,
-                         realtype cell_alpha,
-                         realtype cell_beta,
-                         realtype cell_gamma,
+int  Channel::SetCell ( mmdb::realtype cell_a,
+                         mmdb::realtype cell_b,
+                         mmdb::realtype cell_c,
+                         mmdb::realtype cell_alpha,
+                         mmdb::realtype cell_beta,
+                         mmdb::realtype cell_gamma,
                          int      OrthCode )  {
 
   if (MMDBManager)  {
-    
-    MMDBManager->Cryst.SetCell ( cell_a,cell_b,cell_c,
-                                 cell_alpha,cell_beta,cell_gamma,
-                                 OrthCode );
+    mmdb::PCryst cryst = MMDBManager->GetCrystData();
 
-    if (MMDBManager->Cryst.CellCheck & CCHK_Disagreement)
+    cryst->SetCell ( cell_a,cell_b,cell_c,
+                     cell_alpha,cell_beta,cell_gamma,
+                     OrthCode );
+
+    if (cryst->CellCheck & mmdb::CCHK_Disagreement)
       return RWBERR_Disagreement;
-    if (MMDBManager->Cryst.CellCheck & CCHK_NoOrthCode)
+    if (cryst->CellCheck & mmdb::CCHK_NoOrthCode)
       return RWBERR_NoOrthCode;
-    if (MMDBManager->Cryst.CellCheck & CCHK_Unchecked)
+    if (cryst->CellCheck & mmdb::CCHK_Unchecked)
       return RWBERR_NoCheck;
 
     return RWBERR_Ok;
@@ -512,7 +493,7 @@ int  CChannel::SetCell ( realtype cell_a,
 }
 
 
-int  CChannel::SetSpGroup ( pstr spGroup )  {
+int  Channel::SetSpGroup ( mmdb::pstr spGroup )  {
   if (MMDBManager)  {
     MMDBManager->SetSpaceGroup(spGroup);
     return RWBERR_Ok;
@@ -521,10 +502,11 @@ int  CChannel::SetSpGroup ( pstr spGroup )  {
 }
 
 
-int  CChannel::GetSpGroup ( pstr spGroup )  {
+int  Channel::GetSpGroup ( mmdb::pstr spGroup )  {
   if (MMDBManager)  {
-    if (MMDBManager->Cryst.WhatIsSet & CSET_SpaceGroup)
-          strcpy ( spGroup,MMDBManager->Cryst.spaceGroup );
+    mmdb::PCryst cryst = MMDBManager->GetCrystData();
+    if (cryst->WhatIsSet & mmdb::CSET_SpaceGroup)
+          strcpy ( spGroup,cryst->spaceGroup );
     else  strcpy ( spGroup," " );
     return RWBERR_Ok;
   } else
@@ -532,29 +514,30 @@ int  CChannel::GetSpGroup ( pstr spGroup )  {
 }
 
 
-int  CChannel::GetCell ( realtype & cell_a,
-                         realtype & cell_b,
-                         realtype & cell_c,
-                         realtype & cell_alpha,
-                         realtype & cell_beta,
-                         realtype & cell_gamma,
-                         realtype & cell_v,
+int  Channel::GetCell ( mmdb::realtype & cell_a,
+                         mmdb::realtype & cell_b,
+                         mmdb::realtype & cell_c,
+                         mmdb::realtype & cell_alpha,
+                         mmdb::realtype & cell_beta,
+                         mmdb::realtype & cell_gamma,
+                         mmdb::realtype & cell_v,
                          int      & OrthCode )  {
 
   if (MMDBManager)  {
-    cell_a     = MMDBManager->Cryst.a;
-    cell_b     = MMDBManager->Cryst.b;
-    cell_c     = MMDBManager->Cryst.c;
-    cell_alpha = MMDBManager->Cryst.alpha;
-    cell_beta  = MMDBManager->Cryst.beta;
-    cell_gamma = MMDBManager->Cryst.gamma;
-    cell_v     = MMDBManager->Cryst.Vol;
-    OrthCode   = MMDBManager->Cryst.NCode;
-    if (!(MMDBManager->Cryst.WhatIsSet & CSET_CellParams))
+    mmdb::PCryst cryst = MMDBManager->GetCrystData();
+    cell_a     = cryst->a;
+    cell_b     = cryst->b;
+    cell_c     = cryst->c;
+    cell_alpha = cryst->alpha;
+    cell_beta  = cryst->beta;
+    cell_gamma = cryst->gamma;
+    cell_v     = cryst->Vol;
+    OrthCode   = cryst->NCode;
+    if (!(cryst->WhatIsSet & mmdb::CSET_CellParams))
       return RWBERR_NoCellParams;
-    if (!(MMDBManager->Cryst.WhatIsSet & CSET_Transforms))
+    if (!(cryst->WhatIsSet & mmdb::CSET_Transforms))
       return RWBERR_NoCheck;
-//    if (MMDBManager->Cryst.CellCheck & CCHK_NoOrthCode)
+//    if (MMDBManager->Cryst.CellCheck & mmdb::CCHK_NoOrthCode)
 //      return RWBERR_NoOrthCode;
 
     return RWBERR_Ok;
@@ -565,27 +548,28 @@ int  CChannel::GetCell ( realtype & cell_a,
 
 }
 
-int CChannel::GetRCell ( realtype & cell_as,
-                         realtype & cell_bs,
-                         realtype & cell_cs,
-                         realtype & cell_alphas,
-                         realtype & cell_betas,
-                         realtype & cell_gammas,
-                         realtype & cell_vs )  {
+int Channel::GetRCell ( mmdb::realtype & cell_as,
+                         mmdb::realtype & cell_bs,
+                         mmdb::realtype & cell_cs,
+                         mmdb::realtype & cell_alphas,
+                         mmdb::realtype & cell_betas,
+                         mmdb::realtype & cell_gammas,
+                         mmdb::realtype & cell_vs )  {
   if (MMDBManager)  {
-    MMDBManager->Cryst.GetRCell ( cell_as,cell_bs,cell_cs,
-                        cell_alphas,cell_betas,cell_gammas,
-                        cell_vs );
-    if (!(MMDBManager->Cryst.WhatIsSet & CSET_CellParams))
+    mmdb::PCryst cryst = MMDBManager->GetCrystData();
+    cryst->GetRCell ( cell_as,cell_bs,cell_cs,
+                      cell_alphas,cell_betas,cell_gammas,
+                      cell_vs );
+    if (!(cryst->WhatIsSet & mmdb::CSET_CellParams))
       return RWBERR_NoCellParams;
-    if (!(MMDBManager->Cryst.WhatIsSet & CSET_Transforms))
+    if (!(cryst->WhatIsSet & mmdb::CSET_Transforms))
       return RWBERR_NoCheck;
     return RWBERR_Ok;
   } else
     return RWBERR_NoFile;
 }
 
-void CChannel::GetInputBuffer ( pstr Line, int & count )  {
+void Channel::GetInputBuffer ( mmdb::pstr Line, int & count )  {
   if (MMDBManager)
     MMDBManager->GetInputBuffer ( Line,count );
   else  {
@@ -598,53 +582,53 @@ void CChannel::GetInputBuffer ( pstr Line, int & count )  {
 
 //  ========================  static data  ===========================
 
-static int         nChannels;    // number of channels in processing
-static PCChannel * Channel;      // array of channels in processing
+static int        nChannels;    // number of channels in processing
+static PChannel * channel;      // array of channels in processing
 
-static Boolean     FAutoSer;     // flag to automatically generate
-                                 // serial numbers at reading PDB files
-static Boolean     FReadCoords;  // flag to read coordinates; if set to
-                                 // False, only the header of PDB file
-                                 // is read
-static Boolean     FSimRWBROOK;  // flag to simulate old RWBROOK printout
-                                 // as closely as possible
+static bool       FAutoSer;     // flag to automatically generate
+                                // serial numbers at reading PDB files
+static bool       FReadCoords;  // flag to read coordinates; if set to
+                                // false, only the header of PDB file
+                                // is read
+static bool       FSimRWBROOK;  // flag to simulate old RWBROOK printout
+                                // as closely as possible
 
-static char        LastFunc[80]; // name of the last called function
-static int         LastUnit;     // number of the last unit called
-static int         LastRC;       // last return code
-static int         LastSer;      // last serial number kept for
-                                 // certain warnings
+static char       LastFunc[80]; // name of the last called function
+static int        LastUnit;     // number of the last unit called
+static int        LastRC;       // last return code
+static int        LastSer;      // last serial number kept for
+                                // certain warnings
 
 
 //  ========================  RWBrook API  ===========================
 
 
 FORTRAN_SUBR ( MMDB_F_INIT, mmdb_f_init,(),(),() )  {
-  InitMatType();
+  mmdb::InitMatType();
   nChannels   = 0;
-  Channel     = NULL;
+  channel     = NULL;
   strcpy ( LastFunc,"MMDB_F_Init" );
   LastUnit    = -1;
   LastRC      = 0;
   LastSer     = 0;
-  FAutoSer    = False;
-  FReadCoords = True;
-  FSimRWBROOK = False;
+  FAutoSer    = false;
+  FReadCoords = true;
+  FSimRWBROOK = false;
 }
 
 
 FORTRAN_SUBR ( MMDB_F_QUIT, mmdb_f_quit,(),(),() )  {
 int i;
-  for (i=0;i<nChannels;i++) 
-    if (Channel[i])  delete Channel[i];
-  if (Channel) delete[] Channel;
-  Channel   = NULL;
+  for (i=0;i<nChannels;i++)
+    if (channel[i])  delete channel[i];
+  if (channel) delete[] channel;
+  channel   = NULL;
   nChannels = 0;
   strcpy ( LastFunc,"MMDB_F_Quit" );
   LastUnit  = -1;
   LastRC    = 0;
   LastSer   = 0;
-  FAutoSer  = False;
+  FAutoSer  = false;
 }
 
 
@@ -678,8 +662,8 @@ int GetChannel ( int iUnit )  {
 //   If the channel is not found, returns -1
 int i;
   for (i=0;i<nChannels;i++)
-    if (Channel[i])  {
-      if (Channel[i]->nUnit==iUnit)
+    if (channel[i])  {
+      if (channel[i]->nUnit==iUnit)
         return i;
     }
   return -1;
@@ -697,37 +681,37 @@ int MakeChannel ( int iUnit )  {
 //   Returns serial number of the channel
 // associated with the newly reinitialized
 // or created unit.
-int         i,m;
-PCChannel * Channel1;
+int        i,m;
+PChannel * channel1;
 
   m = GetChannel ( iUnit );
 
   if (m>=0)  {  // such channel already exists
-    Channel[m]->Dispose();  // clear it first
-    Channel[m]->Init();     // reinitialize it
-    Channel[m]->nUnit = iUnit;
+    channel[m]->Dispose();  // clear it first
+    channel[m]->Init();     // reinitialize it
+    channel[m]->nUnit = iUnit;
     return m;
-  } 
+  }
 
   for (i=0;i<nChannels;i++)  // look for free channel
-    if (!Channel[i])  {
+    if (!channel[i])  {
       m = i;  // found!
       break;
     }
 
   if (m<0)  {  // no free channel
     // create new channel place
-    Channel1 = new PCChannel[nChannels+1];
+    channel1 = new PChannel[nChannels+1];
     for (i=0;i<nChannels;i++)
-      Channel1[i] = Channel[i];
-    if (Channel) delete[] Channel;
-    Channel = Channel1;
+      channel1[i] = channel[i];
+    if (channel) delete[] channel;
+    channel = channel1;
     m = nChannels;
     nChannels++;  // increase number of channels
   }
 
-  Channel[m] = new CChannel();  // create new channel
-  Channel[m]->nUnit = iUnit;
+  channel[m] = new Channel();  // create new channel
+  channel[m]->nUnit = iUnit;
 
   return m;
 
@@ -735,21 +719,21 @@ PCChannel * Channel1;
 
 FORTRAN_SUBR ( MMDB_F_OPEN, mmdb_f_open,
                (    // lengths-at-end list
-                fpstr FName,      // file name
-                fpstr RWStat,     // "INPUT" or "OUTPUT"
-                fpstr FType,      // "PDB", "CIF", "BIN" or " "
+                mmdb::machine::fpstr FName,      // file name
+                mmdb::machine::fpstr RWStat,     // "INPUT" or "OUTPUT"
+                mmdb::machine::fpstr FType,      // "PDB", "CIF", "BIN" or " "
                 int * iUnit,      // channel number
                 int * iRet,       // returns error code
                 int   FName_len,  // fortran-hidden length of FName
                 int   RWStat_len, // fortran-hidden length of RWStat
                 int   FType_len   // fortran-hidden length of FType
                ), ( // lengths-in-structure list
-                fpstr FName,  fpstr RWStat, fpstr FType,      
-                int * iUnit,  int * iRet       
+                mmdb::machine::fpstr FName,  mmdb::machine::fpstr RWStat, mmdb::machine::fpstr FType,
+                int * iUnit,  int * iRet
                ), ( // lengths-follow list
-                fpstr FName,   int FName_len,    
-                fpstr RWStat,  int RWStat_len,   
-                fpstr FType,   int FType_len,   
+                mmdb::machine::fpstr FName,   int FName_len,
+                mmdb::machine::fpstr RWStat,  int RWStat_len,
+                mmdb::machine::fpstr FType,   int FType_len,
                 int * iUnit,   int * iRet
                ) )  {
 
@@ -760,9 +744,9 @@ int k;
 char  L[500];
 
 #ifdef WIN32
- GetStrTerWin32File ( L,FTN_STR(FName),0,sizeof(L),FTN_LEN(FName) );
+ mmdb::GetStrTerWin32File ( L,FTN_STR(FName),0,sizeof(L),FTN_LEN(FName) );
 #else
- GetStrTer ( L,FTN_STR(FName),0,sizeof(L),FTN_LEN(FName) );
+ mmdb::GetStrTer ( L,FTN_STR(FName),0,sizeof(L),FTN_LEN(FName) );
 #endif
 
   strcpy ( LastFunc,"MMDB_F_Open" );
@@ -782,22 +766,22 @@ char  L[500];
   if (k>=0)  {
 
     if (FTN_STR(RWStat)[0]=='I')  {
-      Channel[k]->nRead       = 0;
-      Channel[k]->FAutoSer    = FAutoSer;
-      Channel[k]->FReadCoords = FReadCoords;
-      Channel[k]->FSimRWBROOK = FSimRWBROOK;
+      channel[k]->nRead       = 0;
+      channel[k]->FAutoSer    = FAutoSer;
+      channel[k]->FReadCoords = FReadCoords;
+      channel[k]->FSimRWBROOK = FSimRWBROOK;
     } else
-      Channel[k]->nRead = 1;
+      channel[k]->nRead = 1;
 
     // store file name
-    Channel[k]->SetFileName ( L,sizeof(L) );
+    channel[k]->SetFileName ( L,sizeof(L) );
 
     // store unit type
-    Channel[k]->SetFileType ( FTN_STR(FType) );
-    Channel[k]->IdentifyFile( L );
+    channel[k]->SetFileType ( FTN_STR(FType) );
+    channel[k]->IdentifyFile( L );
 
     if (FSimRWBROOK)  {
-      switch (Channel[k]->nType)  {
+      switch (channel[k]->nType)  {
         default : printf ( "  unknown-format" );  break;
         case  0 : printf ( "  PDB"   );           break;
         case  1 : printf ( "  mmCIF" );           break;
@@ -809,11 +793,11 @@ char  L[500];
     }
 
     if (FTN_STR(RWStat)[0]=='I')  {
-      Channel[k]->Read();
-      *iRet = Channel[k]->ErrCode;
+      channel[k]->Read();
+      *iRet = channel[k]->ErrCode;
     } else  {
-      Channel[k]->MakeCoordStructure();
-      Channel[k]->fPos = 1;
+      channel[k]->MakeCoordStructure();
+      channel[k]->fPos = 1;
       *iRet = RWBERR_Ok;
     }
 
@@ -826,37 +810,37 @@ char  L[500];
 
 FORTRAN_SUBR ( MMDB_F_OPENL, mmdb_f_openl,
                (    // lengths-at-end list
-                fpstr LName,      // logical name
-                fpstr RWStat,     // "INPUT" or "OUTPUT"
-                fpstr FType,      // "PDB", "CIF", "BIN" or " "
+                mmdb::machine::fpstr LName,      // logical name
+                mmdb::machine::fpstr RWStat,     // "INPUT" or "OUTPUT"
+                mmdb::machine::fpstr FType,      // "PDB", "CIF", "BIN" or " "
                 int * iUnit,      // channel number
                 int * iRet,       // returns error code
                 int   LName_len,  // fortran-hidden length of LName
                 int   RWStat_len, // fortran-hidden length of RWStat
                 int   FType_len   // fortran-hidden length of FType
                ), ( // lengths-in-structure list
-                fpstr LName,  fpstr RWStat, fpstr FType,
+                mmdb::machine::fpstr LName,  mmdb::machine::fpstr RWStat, mmdb::machine::fpstr FType,
                 int * iUnit,  int * iRet
                ), ( // lengths-follow list
-                fpstr LName,   int LName_len, 
-                fpstr RWStat,  int RWStat_len,
-                fpstr FType,   int FType_len,
+                mmdb::machine::fpstr LName,   int LName_len,
+                mmdb::machine::fpstr RWStat,  int RWStat_len,
+                mmdb::machine::fpstr FType,   int FType_len,
                 int * iUnit,   int * iRet
                ) )  {
-char  L[200];
-pstr  S;
+char        L[200];
+mmdb::pstr  S;
 char_struct(FName)
 
   strcpy ( LastFunc,"MMDB_F_Openl" );
-    
-  GetStrTer ( L,FTN_STR(LName),0,sizeof(L),FTN_LEN(LName) );
-    
+
+  mmdb::GetStrTer ( L,FTN_STR(LName),0,sizeof(L),FTN_LEN(LName) );
+
   S = getenv ( L );
-    
+
   if (S)  {
 
     fill_char_struct(FName,S)
-  
+
   } else if (FTN_STR(RWStat)[0]=='O') {
 
     // The user may not have assigned a logical
@@ -866,20 +850,20 @@ char_struct(FName)
     fill_char_struct(FName,L)
 
   } else {
-    *iRet = RWBERR_NoLogicalName;  
+    *iRet = RWBERR_NoLogicalName;
     return;
   }
 
   printf ( "\n  Logical name: %s  File name: %s\n",L,FName );
 
-  FORTRAN_CALL ( MMDB_F_OPEN, mmdb_f_open, 
+  FORTRAN_CALL ( MMDB_F_OPEN, mmdb_f_open,
                    ( FName,RWStat,FType,iUnit,iRet,
                      FName_len,RWStat_len,FType_len ),
                    ( &FName,RWStat,FType,iUnit,iRet ),
                    ( FName,FName_len,RWStat,RWStat_len,
                      FType,FType_len,iUnit,iRet ) );
 
-}     
+}
 
 FORTRAN_SUBR ( MMDB_F_COPY, mmdb_f_copy,
                (    // lengths-at-end list
@@ -904,8 +888,8 @@ FORTRAN_SUBR ( MMDB_F_COPY, mmdb_f_copy,
                 int * iUnit1,  int * iUnit2,
                 int * copyKey, int * iRet
                ) )  {
-int  k1,k2;
-word copyMask;
+int             k1,k2;
+mmdb::COPY_MASK copyMask;
 
   strcpy ( LastFunc,"MMDB_F_Copy" );
 
@@ -913,20 +897,20 @@ word copyMask;
   k1 = GetChannel ( LastUnit );
 
   if (k1>=0)  {
-    if (Channel[k1]->MMDBManager)  {
+    if (channel[k1]->MMDBManager)  {
       LastUnit = *iUnit2;
       k2 = GetChannel ( LastUnit );
       if (k2>=0)  {
-        if (Channel[k2]->MMDBManager)  {
+        if (channel[k2]->MMDBManager)  {
           switch (*copyKey)  {
-            case 1  :  copyMask = MMDBFCM_All;    break;
-            case 2  :  copyMask = MMDBFCM_Top;    break;
-            case 3  :  copyMask = MMDBFCM_Title;  break;
-            case 4  :  copyMask = MMDBFCM_Cryst;  break;
-            case 5  :  copyMask = MMDBFCM_Coord;  break;
-            default :  copyMask = 0x0000;
+            case 1  :  copyMask = mmdb::MMDBFCM_All;    break;
+            case 2  :  copyMask = mmdb::MMDBFCM_Top;    break;
+            case 3  :  copyMask = mmdb::MMDBFCM_Title;  break;
+            case 4  :  copyMask = mmdb::MMDBFCM_Cryst;  break;
+            case 5  :  copyMask = mmdb::MMDBFCM_Coord;  break;
+            default :  copyMask = mmdb::MMDBFCM_None;
           }
-          Channel[k1]->MMDBManager->Copy ( Channel[k2]->MMDBManager,
+          channel[k1]->MMDBManager->Copy ( channel[k2]->MMDBManager,
                                            copyMask );
           *iRet = RWBERR_Ok;
        } else
@@ -966,8 +950,8 @@ FORTRAN_SUBR ( MMDB_F_DELETE, mmdb_f_delete,
                ), ( // lengths-follow list
                 int * iUnit, int * delKey, int * iRet
                ) )  {
-int  k;
-word delMask;
+int        k;
+mmdb::word delMask;
 
   strcpy ( LastFunc,"MMDB_F_Delete" );
 
@@ -976,16 +960,16 @@ word delMask;
   k = GetChannel ( LastUnit );
 
   if (k>=0)  {
-    if (Channel[k]->MMDBManager)  {
+    if (channel[k]->MMDBManager)  {
       switch (*delKey)  {
-        case 1  :  delMask = MMDBFCM_All;    break;
-        case 2  :  delMask = MMDBFCM_Top;    break;
-        case 3  :  delMask = MMDBFCM_Title;  break;
-        case 4  :  delMask = MMDBFCM_Cryst;  break;
-        case 5  :  delMask = MMDBFCM_Coord;  break;
+        case 1  :  delMask = mmdb::MMDBFCM_All;    break;
+        case 2  :  delMask = mmdb::MMDBFCM_Top;    break;
+        case 3  :  delMask = mmdb::MMDBFCM_Title;  break;
+        case 4  :  delMask = mmdb::MMDBFCM_Cryst;  break;
+        case 5  :  delMask = mmdb::MMDBFCM_Coord;  break;
         default :  delMask = 0x0000;
       }
-      Channel[k]->MMDBManager->Delete ( delMask );
+      channel[k]->MMDBManager->Delete ( delMask );
       *iRet = RWBERR_Ok;
     } else
       *iRet = RWBERR_NoFile;
@@ -1000,26 +984,26 @@ word delMask;
 FORTRAN_SUBR ( MMDB_F_SETTYPE, mmdb_f_settype,
                (    // lengths-at-end list
                 int * iUnit,     // unit number
-                fpstr FType,     // "PDB", "CIF", "BIN" or " "
-                fpstr RWStat,    // "INPUT" or "OUTPUT"
+                mmdb::machine::fpstr FType,     // "PDB", "CIF", "BIN" or " "
+                mmdb::machine::fpstr RWStat,    // "INPUT" or "OUTPUT"
                 int * iRet,      // returns -1 if unit not found,
                                  // otherwise 0
                 int   FType_len, // fortran-hidden length of FType
                 int   RWStat_len // fortran-hidden length of RWStat
                ), ( // lengths-in-structure list
-                int * iUnit,  fpstr FType,
-                fpstr RWStat, int * iRet
+                int * iUnit,  mmdb::machine::fpstr FType,
+                mmdb::machine::fpstr RWStat, int * iRet
                ), ( // length-follow list
-                int * iUnit,     
-                fpstr FType,   int FType_len,  
-                fpstr RWStat,  int RWStat_len,
+                int * iUnit,
+                mmdb::machine::fpstr FType,   int FType_len,
+                mmdb::machine::fpstr RWStat,  int RWStat_len,
                 int * iRet
                ) )  {
 UNUSED_ARGUMENT(FType_len);
 UNUSED_ARGUMENT(RWStat_len);
 
 int k;
-  
+
   strcpy ( LastFunc,"MMDB_F_SetType" );
   if (*iUnit>0)
     LastUnit = *iUnit;
@@ -1028,10 +1012,10 @@ int k;
 
   if (k>=0)  {
     // store unit type
-    Channel[k]->SetFileType ( FTN_STR(FType) );
+    channel[k]->SetFileType ( FTN_STR(FType) );
     // store unit mode
-    if (FTN_STR(RWStat)[0]=='I')  Channel[k]->nRead = 0;
-                            else  Channel[k]->nRead = 1;
+    if (FTN_STR(RWStat)[0]=='I')  channel[k]->nRead = 0;
+                            else  channel[k]->nRead = 1;
     *iRet = RWBERR_Ok;
   } else
     *iRet = RWBERR_NoChannel;
@@ -1045,15 +1029,15 @@ int k;
 FORTRAN_SUBR ( MMDB_F_SETNAME, mmdb_f_setname,
                (    // lengths-at-end list
                 int * iUnit,    // unit number
-                fpstr FName,    // file name
+                mmdb::machine::fpstr FName,    // file name
                 int * iRet,     // returns -1 if unit not found,
                                 // otherwise 0
                 int   FName_len // fortran-hidden length of FName
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr FName, int * iRet
+                int * iUnit, mmdb::machine::fpstr FName, int * iRet
                ), ( // lengths-follow list
                 int * iUnit,
-                fpstr FName, int FName_len,
+                mmdb::machine::fpstr FName, int FName_len,
                 int * iRet
                ) )  {
 
@@ -1069,7 +1053,7 @@ int k;
     *iRet = RWBERR_NoChannel;
   else  {
     // store file name
-    Channel[k]->SetFileName ( FTN_STR(FName),FTN_LEN(FName) );
+    channel[k]->SetFileName ( FTN_STR(FName),FTN_LEN(FName) );
     *iRet = RWBERR_Ok;
   }
 
@@ -1093,8 +1077,8 @@ int k;
   if (k<0)
     *iRet = RWBERR_NoChannel;
   else  {
-    Channel[k]->Write();
-    *iRet = Channel[k]->ErrCode;
+    channel[k]->Write();
+    *iRet = channel[k]->ErrCode;
   }
 
   LastRC = *iRet;
@@ -1116,23 +1100,23 @@ int k;
 
   if (k<0)
     *iRet = RWBERR_NoChannel;
-  else if (Channel[k]->nRead==1)  {
-    Channel[k]->Write();
-    *iRet = Channel[k]->ErrCode;
-    if (!(*iRet))  { 
-      delete Channel[k];
-      Channel[k] = NULL;
+  else if (channel[k]->nRead==1)  {
+    channel[k]->Write();
+    *iRet = channel[k]->ErrCode;
+    if (!(*iRet))  {
+      delete channel[k];
+      channel[k] = NULL;
     }
   } else  {
-    delete Channel[k];
-    Channel[k] = NULL;
+    delete channel[k];
+    channel[k] = NULL;
     *iRet = RWBERR_Ok;
   }
 
   LastRC = *iRet;
 
 }
-  
+
 
 
 FORTRAN_SUBR ( MMDB_F_ADVANCE, mmdb_f_advance,
@@ -1157,7 +1141,7 @@ FORTRAN_SUBR ( MMDB_F_ADVANCE, mmdb_f_advance,
 UNUSED_ARGUMENT(iOut);
 
 int    k;
-PCAtom atom;
+mmdb::PAtom atom;
 
   strcpy ( LastFunc,"mmdb_f_advance" );
   LastUnit = *iUnit;
@@ -1168,17 +1152,17 @@ PCAtom atom;
 
     *iRet = RWBERR_NoChannel;
 
-  else if (Channel[k]->nRead==0)  {
+  else if (channel[k]->nRead==0)  {
 
     // in the input file, try to get pointer on the next atom
 
     do {
-      Channel[k]->fPos++;  // advance the pointer on Atom array
-      if (Channel[k]->EndOfFile())  {
+      channel[k]->fPos++;  // advance the pointer on Atom array
+      if (channel[k]->EndOfFile())  {
         atom = NULL;
         break;
       }
-      atom = Channel[k]->GetAtomI ( Channel[k]->fPos );
+      atom = channel[k]->GetAtomI ( channel[k]->fPos );
       if (atom)  {
         if ((atom->Ter) && (*iTer==0))  {
           // ignore 'ter' card if iTer is set to 0
@@ -1196,14 +1180,14 @@ PCAtom atom;
 
     // in the output file, just advance the pointer
 
-    if (Channel[k]->fPos==0)  {
-      Channel[k]->fPos++;
+    if (channel[k]->fPos==0)  {
+      channel[k]->fPos++;
       *iRet = 0;
     } else  {
-      atom = Channel[k]->GetAtomI ( Channel[k]->fPos );
+      atom = channel[k]->GetAtomI ( channel[k]->fPos );
       if (atom)  {
         // the previous atom was set -- advance the pointer
-        Channel[k]->fPos++;
+        channel[k]->fPos++;
         *iRet = 0;
       } else
         // no atom was set; make no advancement
@@ -1229,8 +1213,8 @@ int k;
 
   k = GetChannel ( *iUnit );
   if (k>=0)  {
-    Channel[k]->fPos = 0;
-    if (Channel[k]->nRead!=0)  *iRet = RWBWAR_RewOutput;
+    channel[k]->fPos = 0;
+    if (channel[k]->nRead!=0)  *iRet = RWBWAR_RewOutput;
                          else  *iRet = RWBERR_Ok;
   } else
     *iRet = RWBERR_NoChannel;
@@ -1253,9 +1237,9 @@ int k;
   k = GetChannel ( *iUnit );
   if (k>=0)  {
     *iRet = RWBERR_Ok;
-    if (Channel[k]->fPos==0)  *iRet |= RWBWAR_FileTop;
-                        else  Channel[k]->fPos--;
-    if (Channel[k]->nRead!=0) *iRet |= RWBWAR_RewOutput;
+    if (channel[k]->fPos==0)  *iRet |= RWBWAR_FileTop;
+                        else  channel[k]->fPos--;
+    if (channel[k]->nRead!=0) *iRet |= RWBWAR_RewOutput;
   } else
     *iRet = RWBERR_NoChannel;
 
@@ -1286,7 +1270,7 @@ FORTRAN_SUBR ( MMDB_F_SEEK, mmdb_f_seek,
                 int * iUnit, int * fPos, int * iRet
                ) )  {
 int    k;
-PCAtom atom;
+mmdb::PAtom atom;
 
   strcpy ( LastFunc,"MMDB_F_Seek" );
   LastUnit = *iUnit;
@@ -1300,18 +1284,18 @@ PCAtom atom;
   else  {
 
     // set the pointer
-    Channel[k]->fPos = IMax(0,*fPos);
+    channel[k]->fPos = mmdb::IMax(0,*fPos);
     if (*fPos==0)  *iRet = RWBWAR_FileTop;
              else  *iRet = RWBERR_Ok;
 
-    if (Channel[k]->nRead==0)  {
+    if (channel[k]->nRead==0)  {
 
       // in the input file, check the end-of-file state
       // and analyze the atom
 
-      if (Channel[k]->EndOfFile())  *iRet = 2;
+      if (channel[k]->EndOfFile())  *iRet = 2;
 
-      atom = Channel[k]->GetAtomI ( Channel[k]->fPos );
+      atom = channel[k]->GetAtomI ( channel[k]->fPos );
 
       if (!atom)          *iRet = RWBERR_EmptyPointer; // empty place
       else if (atom->Ter) *iRet = 1;  // 'ter' card encountered
@@ -1328,24 +1312,24 @@ PCAtom atom;
 }
 
 
-void  Make_AN_ID_IZ ( PCAtom atom, pstr AtNam, int AtNam_L,
-                      pstr ID, int ID_L, int * IZ, int * iRet )  {
+void  Make_AN_ID_IZ ( mmdb::PAtom atom, mmdb::pstr AtNam, int AtNam_L,
+                      mmdb::pstr ID, int ID_L, int * IZ, int * iRet )  {
 char chrg[10];
 int  i,k;
 
   if (atom->Ter)  {
 
-    strcpy_ns ( AtNam,pstr(" "),AtNam_L );
-    strcpy_ns ( ID   ,pstr(" "),ID_L    );
+    mmdb::strcpy_ns ( AtNam,mmdb::pstr(" "),AtNam_L );
+    mmdb::strcpy_ns ( ID   ,mmdb::pstr(" "),ID_L    );
     *IZ = 7;
 
   } else  {
 
-    if (atom->name[0]==' ')  strcpy_ns ( AtNam,&(atom->name[1]),4 );
-                       else  strcpy_ns ( AtNam,atom->name,4 );
+    if (atom->name[0]==' ')  mmdb::strcpy_ns ( AtNam,&(atom->name[1]),4 );
+                       else  mmdb::strcpy_ns ( AtNam,atom->name,4 );
 
     // first try to identify the atom with the element name
-    strcpy_ns ( ID,atom->element,ID_L );  // not more than ID_L symbols
+    mmdb::strcpy_ns ( ID,atom->element,ID_L );  // not more than ID_L symbols
                                 // from element until but not including
                                 // the terminated null are copied into
                                 // ID, and the latter is padded with
@@ -1359,44 +1343,44 @@ int  i,k;
     }
 
     k = 0;
-    while ((k<nElementNames) && 
-           ((atom->element[0]!=ElementName[k][0]) ||
-            (atom->element[1]!=ElementName[k][1])))  k++;
+    while ((k<mmdb::nElementNames) &&
+           ((atom->element[0]!=mmdb::ElementName[k][0]) ||
+            (atom->element[1]!=mmdb::ElementName[k][1])))  k++;
+
+    if (k>=mmdb::nElementNames)  {
 
-    if (k>=nElementNames)  {
-      
       // no match for atom ID -- make sure to set it blank
-      strcpy_ns ( ID,pstr(" "),ID_L );
+      mmdb::strcpy_ns ( ID,mmdb::pstr(" "),ID_L );
 
       //  try to identify the atom using the atom name
       k = 0;
-      while ((k<nElementNames) && 
-             ((atom->name[0]!=ElementName[k][0]) ||
-              (atom->name[1]!=ElementName[k][1])))  k++;
+      while ((k<mmdb::nElementNames) &&
+             ((atom->name[0]!=mmdb::ElementName[k][0]) ||
+              (atom->name[1]!=mmdb::ElementName[k][1])))  k++;
 
       // try to identify a heteroatom
       i = 0;
-      while ((i<nHydAtomNames) && (k>=nElementNames))  {
-        if ((atom->name[0]==HydAtomName[i][0]) && 
-            (atom->name[1]==HydAtomName[i][1]))
+      while ((i<mmdb::nHydAtomNames) && (k>=mmdb::nElementNames))  {
+        if ((atom->name[0]==mmdb::HydAtomName[i][0]) &&
+            (atom->name[1]==mmdb::HydAtomName[i][1]))
           k = 0;
         i++;
       }
 
-      if (k>=nElementNames)  {
+      if (k>=mmdb::nElementNames)  {
         // unknown or ambiguous formfactor
         k = -1;
-        if ((atom->name[0]==' ') && 
+        if ((atom->name[0]==' ') &&
             (atom->name[1]=='A'))  k = 6;
         if (k==-1)  *iRet |= RWBWAR_UnkFormFactor;
-       	      else  *iRet |= RWBWAR_AmbFormFactor;
+              else  *iRet |= RWBWAR_AmbFormFactor;
       }
 
     }
 
     *IZ = k+1;
     if (*IZ==0)
-      strcpy_ns ( ID,pstr(" "),ID_L );
+      mmdb::strcpy_ns ( ID,mmdb::pstr(" "),ID_L );
     else  {
       if (ID_L>3)  {
         if (ID[0]==' ')  {
@@ -1410,7 +1394,7 @@ int  i,k;
           ID[3] = ' ';
         }
       }
-      strcpy_ns ( ID,ElementName[k],IMin(2,ID_L) );
+      mmdb::strcpy_ns ( ID,mmdb::ElementName[k],mmdb::IMin(2,ID_L) );
     }
 
   }
@@ -1423,17 +1407,17 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
            (    // lengths-at-end list
             int * iUnit,    // unit number
             int * iSer,     // atom serial number
-            fpstr AtNam,    // atom name (left justified)
-            fpstr ResNam,   // residue name
-            fpstr ChnNam,   // chain name
+            mmdb::machine::fpstr AtNam,    // atom name (left justified)
+            mmdb::machine::fpstr ResNam,   // residue name
+            mmdb::machine::fpstr ChnNam,   // chain name
             int * iResN,    // residue number as an integer
-            fpstr ResNo,    // residue number as character (input only)
-            fpstr InsCod,   // the insertion code
-            fpstr AltCod,   // the alternate conformation code
-            fpstr segID,    // segment ID
+            mmdb::machine::fpstr ResNo,    // residue number as character (input only)
+            mmdb::machine::fpstr InsCod,   // the insertion code
+            mmdb::machine::fpstr AltCod,   // the alternate conformation code
+            mmdb::machine::fpstr segID,    // segment ID
             int * IZ,       // atomic number (input only, returned as
                             // 7 from ambiguous atoms)
-            fpstr ID,       // atomic ID related to atomic number
+            mmdb::machine::fpstr ID,       // atomic ID related to atomic number
                             // (element symbol right justified), plus
                             // the ionic state +2, +3 etc..
                             //
@@ -1450,7 +1434,7 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
                             //  RWBWAR_WrongSerial   if serial number
                             //               differs from the position
                             //               number in the file
-                            //  RWBWAR_UnkFormFactor unknown formfactor 
+                            //  RWBWAR_UnkFormFactor unknown formfactor
                             //  RWBWAR_AmbFormFactor ambiguous formfactor
                             //
             int AtNam_len,  // fortran-hidden length of AtNam
@@ -1462,34 +1446,34 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
             int segID_len,  // fortran-hidden length of SegID
             int ID_len      // fortran-hidden length of ID
            ), ( // lengths-in-structure list
-            int * iUnit,  int * iSer,  fpstr AtNam,  fpstr ResNam,
-            fpstr ChnNam, int * iResN, fpstr ResNo,  fpstr InsCod,
-            fpstr AltCod, fpstr segID, int * IZ,     fpstr ID,
+            int * iUnit,  int * iSer,  mmdb::machine::fpstr AtNam,  mmdb::machine::fpstr ResNam,
+            mmdb::machine::fpstr ChnNam, int * iResN, mmdb::machine::fpstr ResNo,  mmdb::machine::fpstr InsCod,
+            mmdb::machine::fpstr AltCod, mmdb::machine::fpstr segID, int * IZ,     mmdb::machine::fpstr ID,
             int * iRet
            ), ( // lengths-follow list
             int * iUnit,  int * iSer,
-            fpstr AtNam,  int   AtNam_len,
-            fpstr ResNam, int   ResNam_len,
-            fpstr ChnNam, int   ChnNam_len,
+            mmdb::machine::fpstr AtNam,  int   AtNam_len,
+            mmdb::machine::fpstr ResNam, int   ResNam_len,
+            mmdb::machine::fpstr ChnNam, int   ChnNam_len,
             int * iResN,
-            fpstr ResNo,  int   ResNo_len,
-            fpstr InsCod, int   InsCod_len,
-            fpstr AltCod, int   AltCod_len,
-            fpstr segID,  int   segID_len,
+            mmdb::machine::fpstr ResNo,  int   ResNo_len,
+            mmdb::machine::fpstr InsCod, int   InsCod_len,
+            mmdb::machine::fpstr AltCod, int   AltCod_len,
+            mmdb::machine::fpstr segID,  int   segID_len,
             int * IZ,
-            fpstr ID,     int   ID_len,
+            mmdb::machine::fpstr ID,     int   ID_len,
             int * iRet
            ) )  {
-int      k,RC;
-ChainID  chainID;
-ResName  resName;
-InsCode  insCode;
-AtomName atomName;
-AltLoc   altLoc;
-SegID    sgID;
-Element  element;
-PCAtom   atom;
-char     charge[10];
+int            k,RC;
+mmdb::ChainID  chainID;
+mmdb::ResName  resName;
+mmdb::InsCode  insCode;
+mmdb::AtomName atomName;
+mmdb::AltLoc   altLoc;
+mmdb::SegID    sgID;
+mmdb::Element  element;
+mmdb::PAtom    atom;
+char           charge[10];
 
   strcpy ( LastFunc,"MMDB_F_Atom" );
   LastUnit = *iUnit;
@@ -1503,11 +1487,11 @@ char     charge[10];
 
   *iRet = RWBERR_Ok;
 
-  if (Channel[k]->nRead==0)  {
+  if (channel[k]->nRead==0)  {
 
     // reading the atom characteristics
 
-    atom = Channel[k]->GetAtomI ( Channel[k]->fPos );
+    atom = channel[k]->GetAtomI ( channel[k]->fPos );
     if (!atom)  {
       // atom position was not advanced properly
       *iRet  = RWBERR_EmptyPointer;
@@ -1516,42 +1500,42 @@ char     charge[10];
     }
 
     *iSer = atom->serNum;
-    if (*iSer!=Channel[k]->fPos)  *iRet |= RWBWAR_WrongSerial;
+    if (*iSer!=channel[k]->fPos)  *iRet |= RWBWAR_WrongSerial;
     LastSer = *iSer;
     Make_AN_ID_IZ ( atom,FTN_STR(AtNam),FTN_LEN(AtNam),
                     FTN_STR(ID),FTN_LEN(ID),IZ,iRet );
     if (atom->residue)  {
-      strcpy_ns  ( FTN_STR(ResNam),atom->residue->name,FTN_LEN(ResNam) );
+      mmdb::strcpy_ns  ( FTN_STR(ResNam),atom->residue->name,FTN_LEN(ResNam) );
       *iResN = atom->residue->seqNum;
-      PutInteger ( FTN_STR(ResNo),*iResN,IMin(4,FTN_LEN(ResNo)) );
-      strcpy_ns  ( FTN_STR(InsCod),atom->residue->insCode,FTN_LEN(InsCod) );
-      strcpy_ns  ( &(FTN_STR(ResNo)[4]),FTN_STR(InsCod),FTN_LEN(ResNo)-4 );
-      strcpy_ns  ( FTN_STR(ChnNam),atom->GetChainID(),FTN_LEN(ChnNam) );
+      mmdb::PutInteger ( FTN_STR(ResNo),*iResN,mmdb::IMin(4,FTN_LEN(ResNo)) );
+      mmdb::strcpy_ns  ( FTN_STR(InsCod),atom->residue->insCode,FTN_LEN(InsCod) );
+      mmdb::strcpy_ns  ( &(FTN_STR(ResNo)[4]),FTN_STR(InsCod),FTN_LEN(ResNo)-4 );
+      mmdb::strcpy_ns  ( FTN_STR(ChnNam),atom->GetChainID(),FTN_LEN(ChnNam) );
     } else  {
-      strcpy_ns  ( FTN_STR(ResNam),pstr("   "),FTN_LEN(ResNam) );
-      strcpy_ns  ( FTN_STR(ChnNam),pstr(" ")  ,FTN_LEN(ChnNam) );
+      mmdb::strcpy_ns  ( FTN_STR(ResNam),mmdb::pstr("   "),FTN_LEN(ResNam) );
+      mmdb::strcpy_ns  ( FTN_STR(ChnNam),mmdb::pstr(" ")  ,FTN_LEN(ChnNam) );
       *iResN = 0;
-      strcpy_ns  ( FTN_STR(ResNo) ,pstr("0")  ,FTN_LEN(ResNo)  );
-      strcpy_ns  ( FTN_STR(InsCod),pstr(" ")  ,FTN_LEN(InsCod) );
+      mmdb::strcpy_ns  ( FTN_STR(ResNo) ,mmdb::pstr("0")  ,FTN_LEN(ResNo)  );
+      mmdb::strcpy_ns  ( FTN_STR(InsCod),mmdb::pstr(" ")  ,FTN_LEN(InsCod) );
     }
-    strcpy_ns ( FTN_STR(AltCod),atom->altLoc,FTN_LEN(AltCod) );
-    strcpy_ns ( FTN_STR(segID) ,atom->segID ,FTN_LEN(segID)  );
- 
+    mmdb::strcpy_ns ( FTN_STR(AltCod),atom->altLoc,FTN_LEN(AltCod) );
+    mmdb::strcpy_ns ( FTN_STR(segID) ,atom->segID ,FTN_LEN(segID)  );
+
   } else  {
 
     // storing the atom characteristics
 
-    if (!Channel[k]->MMDBManager)  {
+    if (!channel[k]->MMDBManager)  {
       *iRet  = RWBERR_Error1;   // should never happen
       LastRC = *iRet;
       return;
     }
 
-    GetStrTer ( chainID,FTN_STR(ChnNam),1,sizeof(chainID),FTN_LEN(ChnNam) );
-    GetStrTer ( resName,FTN_STR(ResNam),3,sizeof(resName),FTN_LEN(ResNam) );
-    GetStrTer ( insCode,FTN_STR(InsCod),1,sizeof(insCode),FTN_LEN(InsCod) );
-    GetStrTer ( altLoc ,FTN_STR(AltCod),1,sizeof(altLoc) ,FTN_LEN(AltCod) );
-    GetStrTer ( sgID   ,FTN_STR(segID) ,4,sizeof(sgID)   ,FTN_LEN(segID)  );
+    mmdb::GetStrTer ( chainID,FTN_STR(ChnNam),1,sizeof(chainID),FTN_LEN(ChnNam) );
+    mmdb::GetStrTer ( resName,FTN_STR(ResNam),3,sizeof(resName),FTN_LEN(ResNam) );
+    mmdb::GetStrTer ( insCode,FTN_STR(InsCod),1,sizeof(insCode),FTN_LEN(InsCod) );
+    mmdb::GetStrTer ( altLoc ,FTN_STR(AltCod),1,sizeof(altLoc) ,FTN_LEN(AltCod) );
+    mmdb::GetStrTer ( sgID   ,FTN_STR(segID) ,4,sizeof(sgID)   ,FTN_LEN(segID)  );
     element[0] = FTN_STR(ID)[0];
     element[1] = FTN_STR(ID)[1];
     element[2] = char(0);
@@ -1567,21 +1551,21 @@ char     charge[10];
 //      if ((FTN_STR(AtNam)[1]=='H') ||
 //          ((FTN_STR(AtNam)[1]=='D') && (FTN_STR(ID)[2]=='D')))  {
 //        int i = 0;
-//        while ((i<nHydAtomNames) && 
+//        while ((i<nHydAtomNames) &&
 //               (FTN_STR(AtNam)[0]!=HydAtomName[i][0])) i++;
 //        if (i<nHydAtomNames)
 //          GetStrTer ( atomName,FTN_STR(AtNam),4,5,FTN_LEN(AtNam) );
 //      }
       if ((FTN_STR(AtNam)[0]=='H') && (FTN_STR(AtNam)[3]!=' '))
-        GetStrTer ( atomName,FTN_STR(AtNam),4,5,FTN_LEN(AtNam) );
+        mmdb::GetStrTer ( atomName,FTN_STR(AtNam),4,5,FTN_LEN(AtNam) );
       if (!atomName[0])  {
         atomName[0] = ' ';
-        GetStrTer ( &(atomName[1]),FTN_STR(AtNam),3,4,FTN_LEN(AtNam) );
+        mmdb::GetStrTer ( &(atomName[1]),FTN_STR(AtNam),3,4,FTN_LEN(AtNam) );
       }
     } else
-      GetStrTer ( atomName,FTN_STR(AtNam),4,5,4 );
+      mmdb::GetStrTer ( atomName,FTN_STR(AtNam),4,5,4 );
 
-    RC = Channel[k]->MMDBManager->PutAtom ( Channel[k]->fPos,*iSer,
+    RC = channel[k]->MMDBManager->PutAtom ( channel[k]->fPos,*iSer,
                               atomName,resName,chainID,*iResN,
                               insCode,altLoc,sgID,element );
 
@@ -1591,9 +1575,9 @@ char     charge[10];
       return;
     }
 
-    DelSpaces ( charge );
+    mmdb::DelSpaces ( charge );
     if (charge[0])  {
-      atom  = Channel[k]->GetAtomI ( Channel[k]->fPos );
+      atom  = channel[k]->GetAtomI ( channel[k]->fPos );
       if (!atom)  {
         *iRet  = RWBERR_EmptyPointer; // should never be so
         LastRC = *iRet;
@@ -1602,9 +1586,9 @@ char     charge[10];
       atom->SetCharge ( charge );
     }
 
-    if (*iSer!=Channel[k]->fPos)  {
+    if (*iSer!=channel[k]->fPos)  {
       *iRet |= RWBWAR_WrongSerial; // this is not the right thing at all
-      atom  = Channel[k]->GetAtomI ( Channel[k]->fPos );
+      atom  = channel[k]->GetAtomI ( channel[k]->fPos );
       if (!atom)  {
         *iRet  = RWBERR_EmptyPointer; // should never be so
         LastRC = *iRet;
@@ -1628,7 +1612,7 @@ FORTRAN_SUBR ( MMDB_F_SETTER, mmdb_f_setter,
                ( int * iUnit, int * iRet ),
                ( int * iUnit, int * iRet ) )  {
 int    k;
-PCAtom atom;
+mmdb::PAtom atom;
 
   strcpy ( LastFunc,"MMDB_F_SetTer" );
   LastUnit = *iUnit;
@@ -1640,7 +1624,7 @@ PCAtom atom;
     return;
   }
 
-  atom  = Channel[k]->GetAtomI ( Channel[k]->fPos );
+  atom  = channel[k]->GetAtomI ( channel[k]->fPos );
   *iRet = RWBERR_Ok;
 
   if (!atom)  {
@@ -1649,8 +1633,8 @@ PCAtom atom;
     return;
   }
 
-  atom->Ter       = True;
-  atom->WhatIsSet |= ASET_Coordinates;
+  atom->Ter       = true;
+  atom->WhatIsSet |= mmdb::ASET_Coordinates;
 
 }
 
@@ -1661,7 +1645,7 @@ FORTRAN_SUBR ( MMDB_F_SETHET, mmdb_f_sethet,
                ( int * iUnit, int * iRet ),
                ( int * iUnit, int * iRet ) )  {
 int    k;
-PCAtom atom;
+mmdb::PAtom atom;
 
   strcpy ( LastFunc,"MMDB_F_SetHet" );
   LastUnit = *iUnit;
@@ -1673,7 +1657,7 @@ PCAtom atom;
     return;
   }
 
-  atom  = Channel[k]->GetAtomI ( Channel[k]->fPos );
+  atom  = channel[k]->GetAtomI ( channel[k]->fPos );
   *iRet = RWBERR_Ok;
 
   if (!atom)  {
@@ -1682,8 +1666,8 @@ PCAtom atom;
     return;
   }
 
-  atom->Het = True;
-  atom->WhatIsSet |= ASET_Coordinates;
+  atom->Het = true;
+  atom->WhatIsSet |= mmdb::ASET_Coordinates;
 
 }
 
@@ -1692,13 +1676,13 @@ FORTRAN_SUBR ( MMDB_F_GETHET, mmdb_f_gethet,
                ( int * iUnit, int * isHet, int * iRet ),
                ( int * iUnit, int * isHet, int * iRet ) )  {
 int    k;
-PCAtom atom;
+mmdb::PAtom atom;
 
   strcpy ( LastFunc,"MMDB_F_GetHet" );
   LastUnit = *iUnit;
 
   *isHet = 0;  //  no HETATM record
-    
+
   k = GetChannel ( *iUnit );
   if (k<0)  {
     *iRet  = RWBERR_NoChannel;
@@ -1706,7 +1690,7 @@ PCAtom atom;
     return;
   }
 
-  atom  = Channel[k]->GetAtomI ( Channel[k]->fPos );
+  atom  = channel[k]->GetAtomI ( channel[k]->fPos );
   *iRet = RWBERR_Ok;
 
   if (!atom)  {
@@ -1716,7 +1700,7 @@ PCAtom atom;
   }
 
   if (atom->Het)  *isHet = 1;      // HETATM
-    
+
 }
 
 
@@ -1725,7 +1709,7 @@ FORTRAN_SUBR ( MMDB_F_COPYATOM, mmdb_f_copyatom,
                ( int * iUnit1, int * iUnit2, int * iRet ),
                ( int * iUnit1, int * iUnit2, int * iRet ) )  {
 int    k1,k2,RC;
-PCAtom atom;
+mmdb::PAtom atom;
 
   strcpy ( LastFunc,"mmdb_f_copyatom" );
   LastUnit = *iUnit1;
@@ -1744,7 +1728,7 @@ PCAtom atom;
     return;
   }
 
-  atom = Channel[k1]->GetAtomI ( Channel[k1]->fPos );
+  atom = channel[k1]->GetAtomI ( channel[k1]->fPos );
   *iRet = RWBERR_Ok;
 
   if (!atom)  {
@@ -1754,8 +1738,8 @@ PCAtom atom;
     return;
   }
 
-  RC = Channel[k2]->MMDBManager->PutAtom ( Channel[k2]->fPos,atom,
-					   atom->serNum );
+  RC = channel[k2]->MMDBManager->PutAtom ( channel[k2]->fPos,atom,
+             atom->serNum );
   if (RC)  {
     *iRet  = RWBERR_Error2;  // should never happen
     LastRC = *iRet;
@@ -1770,22 +1754,22 @@ PCAtom atom;
 FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
                (    // lengths-at-end list
                 int * iUnit,    // unit number
-                fpstr XFlag,    // "F" or "O" flag for the fractional
+                mmdb::machine::fpstr XFlag,    // "F" or "O" flag for the fractional
                                 // or orthogonal coordinates x,y,z
                                 // for output files XFlag may also be
                                 // set to "HF" or "HO", where "F" and
                                 // "O" have the same meaning as before
                                 // and "H" indicates that the atom
                                 // should be marked as heteroatom
-                fpstr BFlag ,   // "F" or "O" flag for temperature
+                mmdb::machine::fpstr BFlag ,   // "F" or "O" flag for temperature
                                 // factor in fractional or orthogonal
                                 // Us
-                apireal * x,    // x-coordinate
-                apireal * y,    // y-coordinate
-                apireal * z,    // z-coordinate
-                apireal * occ,  // occupancy
-                apireal * BIso, // isotropic temperature factor
-                apireal * U,    // array(6) of the anisotr. t-factor
+                mmdb::machine::apireal * x,    // x-coordinate
+                mmdb::machine::apireal * y,    // y-coordinate
+                mmdb::machine::apireal * z,    // z-coordinate
+                mmdb::machine::apireal * occ,  // occupancy
+                mmdb::machine::apireal * BIso, // isotropic temperature factor
+                mmdb::machine::apireal * U,    // array(6) of the anisotr. t-factor
                 int * iRet,     // returns
                                 //  RWBERR_NoChannel     if iUnit was not
                                 //                       initialized
@@ -1798,7 +1782,7 @@ FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
                                 //                       not set in the atom
                                 //
                                 //  >=0 : success, warning flags:
-                                //  RWBERR_NoOccupancy   if occupancy was  
+                                //  RWBERR_NoOccupancy   if occupancy was
                                 //                       not set in the atom
                                 //  RWBERR_NoTempFactor  if temp. factor was
                                 //                       not set in the atom
@@ -1806,26 +1790,26 @@ FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
                 int XFlag_len,  // fortran-hidden length of XFlag
                 int BFlag_len   // fortran-hidden length of BFlag
                ), ( // lengths-in-structure list
-                int * iUnit,   fpstr XFlag,    fpstr BFlag,
-                apireal * x,   apireal * y,    apireal * z,
-                apireal * occ, apireal * BIso, apireal * U,
+                int * iUnit,   mmdb::machine::fpstr XFlag,    mmdb::machine::fpstr BFlag,
+                mmdb::machine::apireal * x,   mmdb::machine::apireal * y,    mmdb::machine::apireal * z,
+                mmdb::machine::apireal * occ, mmdb::machine::apireal * BIso, mmdb::machine::apireal * U,
                 int * iRet
                ), ( // lengths-follow list
                 int * iUnit,
-                fpstr XFlag,   int XFlag_len,
-                fpstr BFlag,   int BFlag_len,
-                apireal * x,   apireal * y,    apireal * z,
-                apireal * occ, apireal * BIso, apireal * U,
+                mmdb::machine::fpstr XFlag,   int XFlag_len,
+                mmdb::machine::fpstr BFlag,   int BFlag_len,
+                mmdb::machine::apireal * x,   mmdb::machine::apireal * y,    mmdb::machine::apireal * z,
+                mmdb::machine::apireal * occ, mmdb::machine::apireal * BIso, mmdb::machine::apireal * U,
                 int * iRet
                ) )  {
 
 UNUSED_ARGUMENT(XFlag_len);
 UNUSED_ARGUMENT(BFlag_len);
 
-realtype AU[6];
-realtype xx,yy,zz;
-int      k,i,m;
-PCAtom   atom;
+mmdb::realtype AU[6];
+mmdb::realtype xx,yy,zz;
+int            k,i,m;
+mmdb::PAtom    atom;
 
   strcpy ( LastFunc,"MMDB_F_Coord" );
   LastUnit = *iUnit;
@@ -1837,7 +1821,7 @@ PCAtom   atom;
     return;
   }
 
-  atom  = Channel[k]->GetAtomI ( Channel[k]->fPos );
+  atom  = channel[k]->GetAtomI ( channel[k]->fPos );
   *iRet = RWBERR_Ok;
 
   if (!atom)  {
@@ -1850,7 +1834,7 @@ PCAtom   atom;
       (FTN_STR(XFlag)[0]=='h'))  m = 1;
                            else  m = 0;
 
-  if (Channel[k]->nRead==0)  {
+  if (channel[k]->nRead==0)  {
 
     // reading the atomic coordinates
 
@@ -1868,26 +1852,26 @@ PCAtom   atom;
       U[5]  = 0.0;
     } else  {
 
-      if (atom->WhatIsSet & ASET_Coordinates)  {
+      if (atom->WhatIsSet & mmdb::ASET_Coordinates)  {
         if ((FTN_STR(XFlag)[m]=='F') ||
             (FTN_STR(XFlag)[m]=='f'))  {
           //  receive fractional coordinates
-          if (Channel[k]->areCrystMatrices())  {
-            Channel[k]->Orth2Frac ( atom->x,atom->y,atom->z,xx,yy,zz );
-            *x = (apireal)xx;
-            *y = (apireal)yy;
-            *z = (apireal)zz;
+          if (channel[k]->areCrystMatrices())  {
+            channel[k]->Orth2Frac ( atom->x,atom->y,atom->z,xx,yy,zz );
+            *x = (mmdb::machine::apireal)xx;
+            *y = (mmdb::machine::apireal)yy;
+            *z = (mmdb::machine::apireal)zz;
           } else  {
-            *x = (apireal)atom->x;
-            *y = (apireal)atom->y;
-            *z = (apireal)atom->z;
+            *x = (mmdb::machine::apireal)atom->x;
+            *y = (mmdb::machine::apireal)atom->y;
+            *z = (mmdb::machine::apireal)atom->z;
             *iRet = RWBERR_NoMatrices;
           }
         } else  {
           // receive orthogonal coordinates
-          *x = (apireal)atom->x;
-          *y = (apireal)atom->y;
-          *z = (apireal)atom->z;
+          *x = (mmdb::machine::apireal)atom->x;
+          *y = (mmdb::machine::apireal)atom->y;
+          *z = (mmdb::machine::apireal)atom->z;
         }
       } else  {
         *x = 0.0;
@@ -1895,39 +1879,39 @@ PCAtom   atom;
         *z = 0.0;
         *iRet = RWBERR_NoCoordinates;
       }
- 
+
       // calculate isotropic Uf from Uo, and convert it
       // if necessary
-      if (atom->WhatIsSet & ASET_Anis_tFac)  {
+      if (atom->WhatIsSet & mmdb::ASET_Anis_tFac)  {
         AU[0] = atom->u11;  // this intermediate array is
         AU[1] = atom->u22;  // required because of possible
         AU[2] = atom->u33;  // type difference between
-        AU[3] = atom->u12;  // 'apireal' and 'realtype'
+        AU[3] = atom->u12;  // 'mmdb::machine::apireal' and 'realtype'
         AU[4] = atom->u13;
         AU[5] = atom->u23;
-        *BIso = (apireal)(8.0*Pi*Pi*(AU[0]+AU[1]+AU[2])/3.0);
+        *BIso = (mmdb::machine::apireal)(8.0*mmdb::Pi*mmdb::Pi*(AU[0]+AU[1]+AU[2])/3.0);
         if ((FTN_STR(BFlag)[0]=='F') ||
             (FTN_STR(BFlag)[0]=='f'))  {
-          if (Channel[k]->areCrystMatrices())
-             Channel[k]->Orth2Cryst ( AU );
+          if (channel[k]->areCrystMatrices())
+             channel[k]->Orth2Cryst ( AU );
           else if (*iRet==RWBERR_Ok)
              *iRet = RWBERR_NoMatrices;
         }
         for (i=0;i<6;i++)
-          U[i] = (apireal)AU[i];
+          U[i] = (mmdb::machine::apireal)AU[i];
       } else  {
         for (i=0;i<6;i++)
           U[i] = 0.0;
-        if (atom->WhatIsSet & ASET_tempFactor)
-          U[0] = (apireal)atom->tempFactor;
+        if (atom->WhatIsSet & mmdb::ASET_tempFactor)
+          U[0] = (mmdb::machine::apireal)atom->tempFactor;
         else if (*iRet>=RWBERR_Ok)
           *iRet |= RWBWAR_NoTempFactor;
         *BIso = U[0];
       }
 
       // get occupancy now
-      if (atom->WhatIsSet & ASET_Occupancy)
-        *occ = (apireal)atom->occupancy;
+      if (atom->WhatIsSet & mmdb::ASET_Occupancy)
+        *occ = (mmdb::machine::apireal)atom->occupancy;
       else  {
         *occ = 0.0;
         if (*iRet>=RWBERR_Ok)  *iRet |= RWBWAR_NoOccupancy;
@@ -1943,7 +1927,7 @@ PCAtom   atom;
       atom->x = 0.0;
       atom->y = 0.0;
       atom->z = 0.0;
-      atom->WhatIsSet |= ASET_Coordinates;
+      atom->WhatIsSet |= mmdb::ASET_Coordinates;
       atom->occupancy  = 1.0;
       atom->tempFactor = 1.0;
       atom->u11 = 0.0;
@@ -1957,29 +1941,29 @@ PCAtom   atom;
       if ((FTN_STR(XFlag)[m]=='F') ||
           (FTN_STR(XFlag)[m]=='f'))  {
         //  convert fractional coordinates
-        if (Channel[k]->areCrystMatrices())  {
+        if (channel[k]->areCrystMatrices())  {
           xx = *x;
           yy = *y;
           zz = *z;
-          Channel[k]->Frac2Orth ( xx,yy,zz,atom->x,atom->y,atom->z );
-          atom->WhatIsSet |= ASET_Coordinates;
+          channel[k]->Frac2Orth ( xx,yy,zz,atom->x,atom->y,atom->z );
+          atom->WhatIsSet |= mmdb::ASET_Coordinates;
         } else  {
           atom->x = *x;
           atom->y = *y;
           atom->z = *z;
           *iRet   = RWBERR_NoMatrices;
-          atom->WhatIsSet &= ~ASET_Coordinates;
+          atom->WhatIsSet &= ~mmdb::ASET_Coordinates;
         }
       } else  {
         // store orthogonal coordinates
         atom->x = *x;
         atom->y = *y;
         atom->z = *z;
-        atom->WhatIsSet |= ASET_Coordinates;
+        atom->WhatIsSet |= mmdb::ASET_Coordinates;
       }
 
       atom->Het = (m>0);
- 
+
       // calculate isotropic Uf from Uo, and convert it
       // if necessary
       if ((U[1]!=0.0) || (U[2]!=0.0))  {
@@ -1987,19 +1971,19 @@ PCAtom   atom;
           AU[i] = U[i];
         if ((FTN_STR(BFlag)[0]=='F') ||
             (FTN_STR(BFlag)[0]=='f'))  {
-          if (Channel[k]->areCrystMatrices())
-                Channel[k]->Cryst2Orth ( AU );
+          if (channel[k]->areCrystMatrices())
+                channel[k]->Cryst2Orth ( AU );
           else  *iRet = RWBERR_NoMatrices;
         }
-        *BIso = (apireal)(8.0*Pi*Pi*(AU[0]+AU[1]+AU[2])/3.0);
+        *BIso = (mmdb::machine::apireal)(8.0*mmdb::Pi*mmdb::Pi*(AU[0]+AU[1]+AU[2])/3.0);
         atom->tempFactor = *BIso;
-        atom->u11 = AU[0]; 
-        atom->u22 = AU[1];  
-        atom->u33 = AU[2];  
-        atom->u12 = AU[3];  
+        atom->u11 = AU[0];
+        atom->u22 = AU[1];
+        atom->u33 = AU[2];
+        atom->u12 = AU[3];
         atom->u13 = AU[4];
         atom->u23 = AU[5];
-        atom->WhatIsSet |= ASET_tempFactor | ASET_Anis_tFac;
+        atom->WhatIsSet |= mmdb::ASET_tempFactor | mmdb::ASET_Anis_tFac;
       } else  {
         *BIso = U[0];
         atom->tempFactor = *BIso;
@@ -2009,12 +1993,12 @@ PCAtom   atom;
         atom->u12 = 0.0;
         atom->u13 = 0.0;
         atom->u23 = 0.0;
-        atom->WhatIsSet |= ASET_tempFactor;
+        atom->WhatIsSet |= mmdb::ASET_tempFactor;
       }
 
       // store occupancy now
       atom->occupancy = *occ;
-      atom->WhatIsSet |= ASET_Occupancy;
+      atom->WhatIsSet |= mmdb::ASET_Occupancy;
 
     }
 
@@ -2029,12 +2013,12 @@ PCAtom   atom;
 FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
                (   //   lengths-at-end list
                 int     * iUnit,    // unit number
-                apireal * a,        // cell parameter a, angstroms
-                apireal * b,        // cell parameter b, angstroms
-                apireal * c,        // cell parameter c, angstroms
-                apireal * alpha,    // cell parameter alpha, degrees
-                apireal * beta,     // cell parameter beta,  degrees
-                apireal * gamma,    // cell parameter gamma, degrees
+                mmdb::machine::apireal * a,        // cell parameter a, angstroms
+                mmdb::machine::apireal * b,        // cell parameter b, angstroms
+                mmdb::machine::apireal * c,        // cell parameter c, angstroms
+                mmdb::machine::apireal * alpha,    // cell parameter alpha, degrees
+                mmdb::machine::apireal * beta,     // cell parameter beta,  degrees
+                mmdb::machine::apireal * gamma,    // cell parameter gamma, degrees
                 int     * ArgNCode, // orthogonalization code, 1-6
                 int     * iRet      // return code:
                                     //   RWBERR_Ok  - success
@@ -2045,26 +2029,26 @@ FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
                                     //              has been disposed
                                     //   RWBERR_Disagreement  if a
                                     //              disagreement in
-		                    //              cell parameters
-		                    //              was found
-		                    //   RWBERR_NoOrthCode    if no
+                        //              cell parameters
+                        //              was found
+                        //   RWBERR_NoOrthCode    if no
                                     //              orthogonalization
-		                    //              code was found
-		                    //   RWBERR_NoCheck       if check
-		                    //              of cell parameters
-		                    //              has failed.
+                        //              code was found
+                        //   RWBERR_NoCheck       if check
+                        //              of cell parameters
+                        //              has failed.
                                     //   The last three returns would
-		                    // rather indicate a programming
-		                    // error in mmdb_rwbrook.cpp
+                        // rather indicate a programming
+                        // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
                 int     * iUnit,
-                apireal * a,        apireal * b,    apireal * c,
-                apireal * alpha,    apireal * beta, apireal * gamma,
+                mmdb::machine::apireal * a,        mmdb::machine::apireal * b,    mmdb::machine::apireal * c,
+                mmdb::machine::apireal * alpha,    mmdb::machine::apireal * beta, mmdb::machine::apireal * gamma,
                 int     * ArgNCode, int     * iRet
                ), ( // lengths-follow list
                 int     * iUnit,
-                apireal * a,        apireal * b,    apireal * c,
-                apireal * alpha,    apireal * beta, apireal * gamma,
+                mmdb::machine::apireal * a,        mmdb::machine::apireal * b,    mmdb::machine::apireal * c,
+                mmdb::machine::apireal * alpha,    mmdb::machine::apireal * beta, mmdb::machine::apireal * gamma,
                 int     * ArgNCode, int     * iRet
                ) )  {
 int  k;
@@ -2074,10 +2058,10 @@ int  k;
     LastUnit = *iUnit;
 
   k = GetChannel ( LastUnit );
-  if (k<0)  
+  if (k<0)
     *iRet = RWBERR_NoChannel;
-  else  
-    *iRet = Channel[k]->SetCell ( *a,*b,*c,*alpha,*beta,*gamma,
+  else
+    *iRet = channel[k]->SetCell ( *a,*b,*c,*alpha,*beta,*gamma,
                                   *ArgNCode );
 
   LastRC = *iRet;
@@ -2089,7 +2073,7 @@ FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
                (   //   lengths-at-end list
                 int   * iUnit,  // unit number; *iUnit<=0 means
                                 // "the last mentioned unit"
-                fpstr spGroup,  // space group
+                mmdb::machine::fpstr spGroup,  // space group
                 int   * iRet,   // return code:
                                 //   RWBERR_Ok  - success
                                 //   RWBERR_NoChannel     if unit
@@ -2099,28 +2083,28 @@ FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
                                 //              has been disposed
                 int spGroup_len // fortran-hidden length of spGroup
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr spGroup, int * iRet
+                int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, fpstr spGroup, int spGroup_len,
+                int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
                 int * iRet
                )
-	     )  {
-int      k;
-SymGroup spaceGroup;
+       )  {
+int            k;
+mmdb::SymGroup spaceGroup;
 
   strcpy ( LastFunc,"MMDB_F_WBSpGrp" );
   if (*iUnit>0)
     LastUnit = *iUnit;
 
   k = GetChannel ( LastUnit );
-  if (k<0)  
+  if (k<0)
     *iRet = RWBERR_NoChannel;
   else  {
 //    GetStrTer ( spaceGroup,FTN_STR(spGroup),0,
 //                sizeof(spaceGroup),FTN_LEN(spGroup) );
-    strcpy_ncss(spaceGroup,FTN_STR(spGroup),IMin(FTN_LEN(spGroup),
+    mmdb::strcpy_ncss(spaceGroup,FTN_STR(spGroup),mmdb::IMin(FTN_LEN(spGroup),
                  sizeof(spaceGroup)-1) );
-    *iRet = Channel[k]->SetSpGroup ( spaceGroup );
+    *iRet = channel[k]->SetSpGroup ( spaceGroup );
   }
 
   LastRC = *iRet;
@@ -2133,7 +2117,7 @@ FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
                (   //   lengths-at-end list
                 int   * iUnit,  // unit number; *iUnit<=0 means
                                 // "the last mentioned unit"
-                fpstr spGroup,  // space group
+                mmdb::machine::fpstr spGroup,  // space group
                 int   * iRet,   // return code:
                                 //   RWBERR_Ok  - success
                                 //   RWBERR_NoChannel     if unit
@@ -2143,12 +2127,12 @@ FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
                                 //              has been disposed
                 int spGroup_len // fortran-hidden length of spGroup
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr spGroup, int * iRet
+                int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, fpstr spGroup, int spGroup_len,
+                int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
                 int * iRet
                )
-	     )  {
+       )  {
 int  k;
 char SpaceGroup[100];
 
@@ -2159,11 +2143,11 @@ char SpaceGroup[100];
   SpaceGroup[0] = char(0);
   k = GetChannel ( LastUnit );
   if (k<0)  *iRet = RWBERR_NoChannel;
-      else  *iRet = Channel[k]->GetSpGroup ( SpaceGroup );
+      else  *iRet = channel[k]->GetSpGroup ( SpaceGroup );
 
 // all extra "superficial spaces" are killed in the following
-  CutSpaces ( SpaceGroup,SCUTKEY_BEGEND );
-  strcpy_ns ( FTN_STR(spGroup),SpaceGroup,FTN_LEN(spGroup) );
+  mmdb::CutSpaces ( SpaceGroup,mmdb::SCUTKEY_BEGEND );
+  mmdb::strcpy_ns ( FTN_STR(spGroup),SpaceGroup,FTN_LEN(spGroup) );
 
   LastRC = *iRet;
 
@@ -2175,7 +2159,7 @@ FORTRAN_SUBR ( MMDB_F_WBCELL , mmdb_f_wbcell,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number; *iUnit<=0 means
                                     // "the last mentioned unit"
-                apireal * ArgCell,  // array to accept the cell parameters
+                mmdb::machine::apireal * ArgCell,  // array to accept the cell parameters
                                     // if ArgCell(1) is set to 0, then
                                     // the cell does not change
                 int     * ArgNCode, // orthogonalisation code
@@ -2190,10 +2174,10 @@ FORTRAN_SUBR ( MMDB_F_WBCELL , mmdb_f_wbcell,
                                     //   RWBERR_NoFile        if unit
                                     //              has been disposed
                ), ( // lengths-in-structure list
-                int * iUnit,    apireal * ArgCell,
+                int * iUnit,    mmdb::machine::apireal * ArgCell,
                 int * ArgNCode, int     * iRet
                ), ( // lengths-follow list
-                int * iUnit,    apireal * ArgCell,
+                int * iUnit,    mmdb::machine::apireal * ArgCell,
                 int * ArgNCode, int     * iRet
                )
              )  {
@@ -2204,10 +2188,10 @@ int k;
     LastUnit = *iUnit;
 
   k = GetChannel ( LastUnit );
-  if (k<0)  
+  if (k<0)
     *iRet = RWBERR_NoChannel;
-  else  
-    *iRet = Channel[k]->PutCell ( ArgCell[0],ArgCell[1],ArgCell[2],
+  else
+    *iRet = channel[k]->PutCell ( ArgCell[0],ArgCell[1],ArgCell[2],
                                   ArgCell[3],ArgCell[4],ArgCell[5],
                                   *ArgNCode );
 
@@ -2220,37 +2204,37 @@ int k;
 FORTRAN_SUBR ( MMDB_F_RBCELL, mmdb_f_rbcell,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number
-                apireal * celld,    // array to accept the cell parameters
-                apireal * cvol,     // returns the cell volume
+                mmdb::machine::apireal * celld,    // array to accept the cell parameters
+                mmdb::machine::apireal * cvol,     // returns the cell volume
                 int     * iRet      // return code
-		                    //   RWBERR_Ok  - success
-		                    //   RWBERR_NoChannel     if unit
-		                    //              iUnit was not
-		                    //              initialized
-		                    //   RWBERR_NoFile        if unit
-		                    //              has been disposed
-		                    //   RWBERR_Parameters    if the
-		                    //              cell parameters
-		                    //              were not set
-		                    //   RWBERR_NoOrthCode    if no
+                        //   RWBERR_Ok  - success
+                        //   RWBERR_NoChannel     if unit
+                        //              iUnit was not
+                        //              initialized
+                        //   RWBERR_NoFile        if unit
+                        //              has been disposed
+                        //   RWBERR_Parameters    if the
+                        //              cell parameters
+                        //              were not set
+                        //   RWBERR_NoOrthCode    if no
                                     //              orthogonalization
-		                    //              code was found
-		                    //   RWBERR_NoCheck       if check
-		                    //              of cell parameters
-		                    //              has failed.
+                        //              code was found
+                        //   RWBERR_NoCheck       if check
+                        //              of cell parameters
+                        //              has failed.
                                     //   The last three returns would
-		                    // rather indicate a programming
-		                    // error in mmdb_rwbrook.cpp
+                        // rather indicate a programming
+                        // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
-                int     * iUnit,  apireal * celld,
-                apireal * cvol,   int     * iRet
+                int     * iUnit,  mmdb::machine::apireal * celld,
+                mmdb::machine::apireal * cvol,   int     * iRet
                ), ( // lengths-follow list
-                int     * iUnit,  apireal * celld,
-                apireal * cvol,   int     * iRet
+                int     * iUnit,  mmdb::machine::apireal * celld,
+                mmdb::machine::apireal * cvol,   int     * iRet
                ) )  {
-realtype p[6];
-realtype v;
-int      k,i,nc;
+mmdb::realtype p[6];
+mmdb::realtype v;
+int            k,i,nc;
 
   strcpy ( LastFunc,"MMDB_F_RBCell" );
   if (*iUnit>0)
@@ -2263,12 +2247,12 @@ int      k,i,nc;
     return;
   }
 
-  *iRet = Channel[k]->GetCell ( p[0],p[1],p[2],p[3],p[4],p[5],v,nc );
+  *iRet = channel[k]->GetCell ( p[0],p[1],p[2],p[3],p[4],p[5],v,nc );
 
   if (*iRet==RWBERR_Ok)  {
     for (i=0;i<6;i++)
-      celld[i] = (apireal)p[i];
-    *cvol = (apireal)v;
+      celld[i] = (mmdb::machine::apireal)p[i];
+    *cvol = (mmdb::machine::apireal)v;
   }
 
   LastRC = *iRet;
@@ -2280,38 +2264,38 @@ int      k,i,nc;
 FORTRAN_SUBR ( MMDB_F_RBCELLN, mmdb_f_rbcelln,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number
-                apireal * celld,    // array to accept the cell parameters
-                apireal * cvol,     // returns the cell volume
+                mmdb::machine::apireal * celld,    // array to accept the cell parameters
+                mmdb::machine::apireal * cvol,     // returns the cell volume
                 int     * ArgNCode, // returns the orthogonalization code, 1-6
                 int     * iRet      // return code
-		                    //   RWBERR_Ok  - success
-		                    //   RWBERR_NoChannel     if unit
-		                    //              iUnit was not
-		                    //              initialized
-		                    //   RWBERR_NoFile        if unit
-		                    //              has been disposed
-		                    //   RWBERR_Parameters    if the
-		                    //              cell parameters
-		                    //              were not set
-		                    //   RWBERR_NoOrthCode    if no
+                        //   RWBERR_Ok  - success
+                        //   RWBERR_NoChannel     if unit
+                        //              iUnit was not
+                        //              initialized
+                        //   RWBERR_NoFile        if unit
+                        //              has been disposed
+                        //   RWBERR_Parameters    if the
+                        //              cell parameters
+                        //              were not set
+                        //   RWBERR_NoOrthCode    if no
                                     //              orthogonalization
-		                    //              code was found
-		                    //   RWBERR_NoCheck       if check
-		                    //              of cell parameters
-		                    //              has failed.
+                        //              code was found
+                        //   RWBERR_NoCheck       if check
+                        //              of cell parameters
+                        //              has failed.
                                     //   The last three returns would
-		                    // rather indicate a programming
-		                    // error in mmdb_rwbrook.cpp
+                        // rather indicate a programming
+                        // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
-                int * iUnit,    apireal * celld, apireal * cvol,
+                int * iUnit,    mmdb::machine::apireal * celld, mmdb::machine::apireal * cvol,
                 int * ArgNCode, int     * iRet
                ), ( // lengths-follow list
-                int * iUnit,    apireal * celld, apireal * cvol,
+                int * iUnit,    mmdb::machine::apireal * celld, mmdb::machine::apireal * cvol,
                 int * ArgNCode, int     * iRet
                ) )  {
-realtype p[6];
-realtype v;
-int      k,i,nc;
+mmdb::realtype p[6];
+mmdb::realtype v;
+int            k,i,nc;
 
   strcpy ( LastFunc,"MMDB_F_RBCellN" );
   if (*iUnit>0)
@@ -2323,12 +2307,12 @@ int      k,i,nc;
     LastRC = *iRet;
     return;
   }
-  
-  *iRet = Channel[k]->GetCell ( p[0],p[1],p[2],p[3],p[4],p[5],v,nc );
+
+  *iRet = channel[k]->GetCell ( p[0],p[1],p[2],p[3],p[4],p[5],v,nc );
   if (*iRet==RWBERR_Ok)  {
     for (i=0;i<6;i++)
-      celld[i] = (apireal)p[i];
-    *cvol     = (apireal)v;
+      celld[i] = (mmdb::machine::apireal)p[i];
+    *cvol     = (mmdb::machine::apireal)v;
     *ArgNCode = nc;
   }
 
@@ -2341,38 +2325,38 @@ int      k,i,nc;
 FORTRAN_SUBR ( MMDB_F_RBRCEL, mmdb_f_rbrcel,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number
-                apireal * rcell,    // array to accept the reciprocal
+                mmdb::machine::apireal * rcell,    // array to accept the reciprocal
                                     // cell parameters
-                apireal * rvol,     // returns the reciprocal cell volume
+                mmdb::machine::apireal * rvol,     // returns the reciprocal cell volume
                 int     * iRet      // return code
-		                    //   RWBERR_Ok  - success
-		                    //   RWBERR_NoChannel     if unit
-		                    //              iUnit was not
-		                    //              initialized
-		                    //   RWBERR_NoFile        if unit
-		                    //              has been disposed
-		                    //   RWBERR_Parameters    if the
-		                    //              cell parameters
-		                    //              were not set
-		                    //   RWBERR_NoOrthCode    if no
+                        //   RWBERR_Ok  - success
+                        //   RWBERR_NoChannel     if unit
+                        //              iUnit was not
+                        //              initialized
+                        //   RWBERR_NoFile        if unit
+                        //              has been disposed
+                        //   RWBERR_Parameters    if the
+                        //              cell parameters
+                        //              were not set
+                        //   RWBERR_NoOrthCode    if no
                                     //              orthogonalization
-		                    //              code was found
-		                    //   RWBERR_NoCheck       if check
-		                    //              of cell parameters
-		                    //              has failed.
+                        //              code was found
+                        //   RWBERR_NoCheck       if check
+                        //              of cell parameters
+                        //              has failed.
                                     //   The last three returns would
-		                    // rather indicate a programming
-		                    // error in mmdb_rwbrook.cpp
+                        // rather indicate a programming
+                        // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
-                int * iUnit,    apireal * rcell, apireal * rvol,
+                int * iUnit,    mmdb::machine::apireal * rcell, mmdb::machine::apireal * rvol,
                 int * iRet
                ), ( // lengths-follow list
-                int * iUnit,    apireal * rcell, apireal * rvol,
+                int * iUnit,    mmdb::machine::apireal * rcell, mmdb::machine::apireal * rvol,
                 int * iRet
                ) )  {
-realtype p[6];
-realtype v;
-int      k,i;
+mmdb::realtype p[6];
+mmdb::realtype v;
+int            k,i;
 
   strcpy ( LastFunc,"MMDB_F_RBRCel" );
   if (*iUnit>0)
@@ -2384,12 +2368,12 @@ int      k,i;
     LastRC = *iRet;
     return;
   }
-  
-  *iRet = Channel[k]->GetRCell ( p[0],p[1],p[2],p[3],p[4],p[5],v );
+
+  *iRet = channel[k]->GetRCell ( p[0],p[1],p[2],p[3],p[4],p[5],v );
   if (*iRet==RWBERR_Ok)  {
     for (i=0;i<6;i++)
-      rcell[i] = (apireal)p[i];
-    *rvol = (apireal)v;
+      rcell[i] = (mmdb::machine::apireal)p[i];
+    *rvol = (mmdb::machine::apireal)v;
   }
 
   LastRC = *iRet;
@@ -2401,8 +2385,8 @@ int      k,i;
 FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
                (     // lengths-at-end list
                 int     * iUnit, // unit number
-                apireal * RO,    // array for orthogonalising matrix
-                apireal * RF,    // array for fractionalising matrix
+                mmdb::machine::apireal * RO,    // array for orthogonalising matrix
+                mmdb::machine::apireal * RF,    // array for fractionalising matrix
                 int     * LCode, // buffer for orthogonalisation code
                 int     * iRet   // return code:
                                  //   RWBERR_Ok  - success
@@ -2414,16 +2398,16 @@ FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
                                  //   RWBERR_NoMatrices    if the
                                  //              orthogonalisation
                                  //              matrices were not
-                                 //              calculated 
+                                 //              calculated
                ), (  // lengths-in-structure list
-                int * iUnit, apireal * RO, apireal * RF,
+                int * iUnit, mmdb::machine::apireal * RO, mmdb::machine::apireal * RF,
                 int * LCode, int * iRet
                ), (  // lengths-follow list
-                int * iUnit, apireal * RO, apireal * RF,
+                int * iUnit, mmdb::machine::apireal * RO, mmdb::machine::apireal * RF,
                 int * LCode, int * iRet )
                )  {
 int         i,j,k,l;
-PCMMDBCryst Cryst;
+mmdb::PCryst Cryst;
 
   strcpy ( LastFunc,"MMDB_F_RBORF" );
   if (*iUnit>0)
@@ -2436,7 +2420,7 @@ PCMMDBCryst Cryst;
     return;
   }
 
-  Cryst = Channel[k]->GetCryst();
+  Cryst = channel[k]->GetCryst();
   if (Cryst==NULL)  {
     *iRet  = RWBERR_NoFile;
     LastRC = *iRet;
@@ -2450,12 +2434,12 @@ PCMMDBCryst Cryst;
   if (RO[0]<=0.0000000001)  {
     for (j=0;j<4;j++)
       for (i=0;i<4;i++)  {
-        RF[l] = (apireal)Cryst->RF[i][j];
-        RO[l] = (apireal)Cryst->RO[i][j];
+        RF[l] = (mmdb::machine::apireal)Cryst->RF[i][j];
+        RO[l] = (mmdb::machine::apireal)Cryst->RO[i][j];
         l++;
       }
     *LCode = Cryst->NCode;
-    if (!(Cryst->WhatIsSet & CSET_Transforms))
+    if (!(Cryst->WhatIsSet & mmdb::CSET_Transforms))
       *iRet = RWBERR_NoMatrices;
   } else  {
     for (j=0;j<4;j++)
@@ -2465,7 +2449,7 @@ PCMMDBCryst Cryst;
         l++;
       }
     Cryst->NCode = *LCode;
-    Cryst->WhatIsSet |= CSET_Transforms;
+    Cryst->WhatIsSet |= mmdb::CSET_Transforms;
   }
 
   LastRC = *iRet;
@@ -2477,12 +2461,12 @@ FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
                (     // lengths-at-end list
                 int     * iUnit, // unit number; *iUnit<=0 means
                                  // "the last mentioned unit"
-                apireal * Cell,  // array of cell parameters:
+                mmdb::machine::apireal * Cell,  // array of cell parameters:
                                  //  Cell(1) - a   Cell(4) - alpha
                                  //  Cell(2) - b   Cell(5) - beta
                                  //  Cell(3) - c   Cell(6) - gamma
-                apireal * Vol,   // returns cell volume
-                apireal * RRR,   // array (3,3,6), returns
+                mmdb::machine::apireal * Vol,   // returns cell volume
+                mmdb::machine::apireal * RRR,   // array (3,3,6), returns
                                  // orthogonalisation matrices
                 int     * iRet   // return code:
                                  //   RWBERR_Ok  - success
@@ -2496,16 +2480,16 @@ FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
                                  //              matrices were not
                                  //              calculated
                ), ( // lengths-in-structure list
-                int     * iUnit, apireal * Cell, apireal * Vol,
-                apireal * RRR,   int * iRet
+                int     * iUnit, mmdb::machine::apireal * Cell, mmdb::machine::apireal * Vol,
+                mmdb::machine::apireal * RRR,   int * iRet
                ), ( // lengths-follow list
-                int     * iUnit, apireal * Cell, apireal * Vol,
-                apireal * RRR,   int * iRet
+                int     * iUnit, mmdb::machine::apireal * Cell, mmdb::machine::apireal * Vol,
+                mmdb::machine::apireal * RRR,   int * iRet
                )
              )  {
-int         i,j,k,l,m;
-PCMMDBCryst Cryst;
-realtype    CelDel;
+int            i,j,k,l,m;
+mmdb::PCryst   Cryst;
+mmdb::realtype CelDel;
 
   strcpy ( LastFunc,"MMDB_F_OrthMat" );
   if (*iUnit>0)
@@ -2518,7 +2502,7 @@ realtype    CelDel;
     return;
   }
 
-  Cryst = Channel[k]->GetCryst();
+  Cryst = channel[k]->GetCryst();
   if (Cryst==NULL)  {
     *iRet  = RWBERR_NoFile;
     LastRC = *iRet;
@@ -2527,18 +2511,18 @@ realtype    CelDel;
 
   CelDel = 0.0;
   if (Cell[0]>0.0)  {
-    if ((Cryst->WhatIsSet & CSET_CellParams)==CSET_CellParams)  {
+    if ((Cryst->WhatIsSet & mmdb::CSET_CellParams)==mmdb::CSET_CellParams)  {
       CelDel = fabs((Cell[0]-Cryst->a)/Cell[0]);
       if (Cell[1]!=0.0)
-        CelDel = RMax(CelDel,fabs((Cell[1]-Cryst->b)/Cell[1]));
+        CelDel = mmdb::RMax(CelDel,fabs((Cell[1]-Cryst->b)/Cell[1]));
       if (Cell[2]!=0.0)
-        CelDel = RMax(CelDel,fabs((Cell[2]-Cryst->c)/Cell[2]));
+        CelDel = mmdb::RMax(CelDel,fabs((Cell[2]-Cryst->c)/Cell[2]));
       if (Cell[3]!=0.0)
-        CelDel = RMax(CelDel,fabs((Cell[3]-Cryst->alpha)/Cell[3]));
+        CelDel = mmdb::RMax(CelDel,fabs((Cell[3]-Cryst->alpha)/Cell[3]));
       if (Cell[4]!=0.0)
-        CelDel = RMax(CelDel,fabs((Cell[4]-Cryst->beta )/Cell[4]));
+        CelDel = mmdb::RMax(CelDel,fabs((Cell[4]-Cryst->beta )/Cell[4]));
       if (Cell[5]!=0.0)
-        CelDel = RMax(CelDel,fabs((Cell[5]-Cryst->gamma)/Cell[5]));
+        CelDel = mmdb::RMax(CelDel,fabs((Cell[5]-Cryst->gamma)/Cell[5]));
       if (FSimRWBROOK && (CelDel>0.01))
         printf ( "\n Inconsistency in Cell Dimensions"
                  " - replacing old:\n"
@@ -2556,17 +2540,17 @@ realtype    CelDel;
     Cryst->alpha = Cell[3];
     Cryst->beta  = Cell[4];
     Cryst->gamma = Cell[5];
-    Cryst->WhatIsSet |= CSET_CellParams;
+    Cryst->WhatIsSet |= mmdb::CSET_CellParams;
   } else  {
-    Cell[0] = (apireal)Cryst->a;
-    Cell[1] = (apireal)Cryst->b;
-    Cell[2] = (apireal)Cryst->c;
-    Cell[3] = (apireal)Cryst->alpha;
-    Cell[4] = (apireal)Cryst->beta;
-    Cell[5] = (apireal)Cryst->gamma;
+    Cell[0] = (mmdb::machine::apireal)Cryst->a;
+    Cell[1] = (mmdb::machine::apireal)Cryst->b;
+    Cell[2] = (mmdb::machine::apireal)Cryst->c;
+    Cell[3] = (mmdb::machine::apireal)Cryst->alpha;
+    Cell[4] = (mmdb::machine::apireal)Cryst->beta;
+    Cell[5] = (mmdb::machine::apireal)Cryst->gamma;
   }
 
-  if ((Cryst->WhatIsSet & CSET_CellParams)!=CSET_CellParams)  {
+  if ((Cryst->WhatIsSet & mmdb::CSET_CellParams)!=mmdb::CSET_CellParams)  {
     *iRet  = RWBERR_NoCellParams;
     LastRC = *iRet;
     return;
@@ -2576,16 +2560,16 @@ realtype    CelDel;
 
   //  Cryst->CalcOrthMatrices();  <-- old version, changed 09.01.2004
   Cryst->CalcCoordTransforms();
-  Cryst->WhatIsSet |= CSET_Transforms;
+  Cryst->WhatIsSet |= mmdb::CSET_Transforms;
 
-  if (CelDel>0.01)  *Vol = -(apireal)Cryst->Vol;
-              else  *Vol =  (apireal)Cryst->Vol;
+  if (CelDel>0.01)  *Vol = -(mmdb::machine::apireal)Cryst->Vol;
+              else  *Vol =  (mmdb::machine::apireal)Cryst->Vol;
 
   l = 0;
   for (j=0;j<3;j++)
     for (i=0;i<3;i++)
       for (m=0;m<6;m++)
-        RRR[l++] = (apireal)Cryst->RR[m][j][i];
+        RRR[l++] = (mmdb::machine::apireal)Cryst->RR[m][j][i];
 
   LastRC = *iRet;
 
@@ -2596,7 +2580,7 @@ FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
                (     // lengths-at-end list
                 int     * iUnit, // unit number; *iUnit<=0 means
                                  // "the last mentioned unit"
-                apireal * U,     // array of coordinates to convert
+                mmdb::machine::apireal * U,     // array of coordinates to convert
                 int     * iFlag, // =0: convert from fract. to orthog.
                                  // =1: convert from orthog. to fract.
                 int     * iRet   // return code:
@@ -2611,14 +2595,14 @@ FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
                                  //              matrices were not
                                  //              calculated
                ), ( // lengths-in-structure list
-                int * iUnit, apireal * U, int * iFlag, int * iRet
+                int * iUnit, mmdb::machine::apireal * U, int * iFlag, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, apireal * U, int * iFlag, int * iRet
+                int * iUnit, mmdb::machine::apireal * U, int * iFlag, int * iRet
                )
              )  {
-int         k,i;
-PCMMDBCryst Cryst;
-realtype    U1[6];
+int            k,i;
+mmdb::PCryst   Cryst;
+mmdb::realtype U1[6];
 
   strcpy ( LastFunc,"MMDB_F_CVAnisou" );
   if (*iUnit>0)
@@ -2631,7 +2615,7 @@ realtype    U1[6];
     return;
   }
 
-  Cryst = Channel[k]->GetCryst();
+  Cryst = channel[k]->GetCryst();
   if (Cryst==NULL)  {
     *iRet  = RWBERR_NoFile;
     LastRC = *iRet;
@@ -2650,7 +2634,7 @@ realtype    U1[6];
 
   if (*iRet==RWBERR_Ok)
     for (i=0;i<6;i++)
-      U[i] = (apireal)U1[i];
+      U[i] = (mmdb::machine::apireal)U1[i];
 
   LastRC = *iRet;
 
@@ -2662,7 +2646,7 @@ FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
                (    // lengths-at-end list
                 int     * iUnit, // unit number; *iUnit<=0 means
                                  // "the last mentioned unit"
-                fpstr     Line,  // line to be added
+                mmdb::machine::fpstr     Line,  // line to be added
                 int     * iRet,  // return code:
                                  //   RWBERR_Ok  - success
                                  //   RWBERR_NoChannel     if unit
@@ -2674,9 +2658,9 @@ FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
                                  // returned by xyzopen1_(..)
                 int    Line_len  // fortran-hidden length of Line
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr Line, int * iRet
+                int * iUnit, mmdb::machine::fpstr Line, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, fpstr Line, int Line_len, int *iRet
+                int * iUnit, mmdb::machine::fpstr Line, int Line_len, int *iRet
                )
              )  {
 int  k;
@@ -2693,22 +2677,22 @@ char S[500];
     return;
   }
 
-  if (Channel[k]->MMDBManager)  {
-    GetStrTer ( S,FTN_STR(Line),FTN_LEN(Line),sizeof(S),FTN_LEN(Line) );
-    *iRet =  Channel[k]->MMDBManager->PutPDBString ( S );
+  if (channel[k]->MMDBManager)  {
+    mmdb::GetStrTer ( S,FTN_STR(Line),FTN_LEN(Line),sizeof(S),FTN_LEN(Line) );
+    *iRet =  channel[k]->MMDBManager->PutPDBString ( S );
   } else
     *iRet = RWBERR_NoFile;
 
   LastRC = *iRet;
-  
+
 }
 
 
 /*
 FORTRAN_SUBR ( RBRINV, rbrinv,
-               ( apireal * A, apireal * AI ),
-               ( apireal * A, apireal * AI ),
-               ( apireal * A, apireal * AI ) )  {
+               ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+               ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+               ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ) )  {
 mat44  A1,AI1;
 int    i,j,k;
 
@@ -2729,16 +2713,16 @@ int    i,j,k;
 /*
 FORTRAN_SUBR ( RES3TO1, res3to1,
                (     // lengths-at-end list
-                fpstr ResNm3,   // 3-char name, 4th char
+                mmdb::machine::fpstr ResNm3,   // 3-char name, 4th char
                                 // will be set blank
-                fpstr ResNm1,   // 1-char name
+                mmdb::machine::fpstr ResNm1,   // 1-char name
                 int ResNm3_len, // fortran-hidden length of ResNm3
                 int ResNm1_len  // fortran-hidden length of ResNm3
                ), ( // lengths-in-structure list
-                fpstr ResNm3, fpstr ResNm1
+                mmdb::machine::fpstr ResNm3, mmdb::machine::fpstr ResNm1
                ), ( // lengths-follow list
-                fpstr ResNm3, int ResNm3_len,
-                fpstr ResNm1, int ResNm1_len
+                mmdb::machine::fpstr ResNm3, int ResNm3_len,
+                mmdb::machine::fpstr ResNm1, int ResNm1_len
                )
              )  {
 int i;
@@ -2774,71 +2758,71 @@ int i;
 }
 */
 
-static pstr MSG_NoChannel       = pstr("unassigned unit");
-static pstr MSG_NoFile          = pstr("unassigned unit or disposed file");
-static pstr MSG_NoLogicalName   = pstr("logical name does not exist");
-
-static pstr MSG_CantOpenFile    = pstr("cannot open a file");
-static pstr MSG_WrongInteger    = pstr("unrecognized integer at reading a file");
-static pstr MSG_WrongModelNo    = pstr("wrong model number read from a file");
-static pstr MSG_DuplicatedModel = pstr("duplicated model number");
-static pstr MSG_ForeignFile     = pstr("unknown file format");
-static pstr MSG_WrongEdition    = pstr("unknown file version");
-
-static pstr MSG_ATOM_Unrecognd  = pstr("unrecognized data in coordinate section");
-static pstr MSG_ATOM_AlreadySet = pstr("duplicate atom serial number");
-static pstr MSG_ATOM_NoResidue  = pstr("residue for atom cannot be found");
-static pstr MSG_ATOM_Unmatch    = pstr("ambiguous data in coordinate section");
-
-static pstr MSG_NoAdvance       = pstr("atom position was not advanced");
-static pstr MSG_EmptyPointer    = pstr("atom was not allocated");
-static pstr MSG_NoMatrices      = pstr("no coordinate transformation matrices");
-
-static pstr MSG_NoCoordinates   = pstr("no atom coordinates set");
-
-static pstr MSG_Disagreement    = pstr("ambiguous cell parameters");
-static pstr MSG_NoOrthCode      = pstr("no orthogonalization code");
-static pstr MSG_NoCheck         = pstr("missing check of cell parameters");
-
-static pstr MSG_NoCellParams    = pstr("no cell parameters");
-
-static pstr MSG_NotACIFFile     = pstr("not a CIF file: 'data_' tag missing");
-static pstr MSG_NoData          = pstr("expected data is not met at reading a file");
-static pstr MSG_UnrecognCIFItems  = pstr("unrecognized CIF items (syntax error?)");
-static pstr MSG_MissingCIFField   = pstr("missing CIF data field");
-static pstr MSG_EmptyCIFLoop      = pstr("CIF loop does not contain any data");
-static pstr MSG_UnexpEndOfCIF     = pstr("unexpected end of CIF file");
-static pstr MSG_MissgCIFLoopField = pstr("CIF loop is incomplete");
-static pstr MSG_NotACIFStructure  = pstr("wrong use of CIF structure (as a loop?)");
-static pstr MSG_NotACIFLoop       = pstr("wrong use of CIF loop (as a structure?)");
-static pstr MSG_WrongReal         = pstr("unrecognized real at reading a file");
-
-static pstr MSG_WrongChainID      = pstr("Wrong or inconsistent chain ID");
-static pstr MSG_WrongEntryID      = pstr("Wrong or insonsistent entry ID");
-static pstr MSG_SEQRES_serNum     = pstr("Wrong serial number in SEQRES");
-static pstr MSG_SEQRES_numRes     = pstr("Wrong number of residues in SEQRES");
-static pstr MSG_SEQRES_extraRes   = pstr("Extra residues in SEQRES");
-static pstr MSG_NCSM_Unrecogn     = pstr("Unrecognized item in NCSM cards");
-static pstr MSG_NCSM_AlreadySet   = pstr("Attempt to reset NCSM");
-static pstr MSG_NCSM_WrongSerial  = pstr("Wrong serial number in NCSM cards");
-static pstr MSG_NCSM_UnmatchIG    = pstr("Unmatched IG parameter in NCSM cards");
-static pstr MSG_NoModel           = pstr("MMDB's error in structuring models");
-static pstr MSG_NoSheetID         = pstr("No sheet ID on SHEET card(s)");
-static pstr MSG_WrongSheetID      = pstr("Wrong sheet ID on SHEET card(s)");
-static pstr MSG_WrongStrandNo     = pstr("Wrong strand no. on SHEET card(s)");
-static pstr MSG_WrongNofStrands   = pstr("Wrong number of strands in sheet");
-static pstr MSG_WrongSheetOrder   = pstr("Wrong sheet ordering");
-static pstr MSG_HBondInconsistency = pstr("Inconsistency in H-bonds");
-static pstr MSG_EmptyResidueName  = pstr("No (blank) residue name");
-static pstr MSG_DuplicateSeqNum   = pstr("Duplicated sequence number and insertion code");
-static pstr MSG_GeneralError1     = pstr("MMDB's general error #1");
-
-
-static pstr MSG_Error1          = pstr("internal error #1 -- report to developer");
-static pstr MSG_Error2          = pstr("internal error #2 -- report to developer");
-static pstr MSG_Error3          = pstr("internal error #3 -- report to developer");
-
-static pstr MSG_Unknown         = pstr("unknown return code");
+static mmdb::pstr MSG_NoChannel       = mmdb::pstr("unassigned unit");
+static mmdb::pstr MSG_NoFile          = mmdb::pstr("unassigned unit or disposed file");
+static mmdb::pstr MSG_NoLogicalName   = mmdb::pstr("logical name does not exist");
+
+static mmdb::pstr MSG_CantOpenFile    = mmdb::pstr("cannot open a file");
+static mmdb::pstr MSG_WrongInteger    = mmdb::pstr("unrecognized integer at reading a file");
+static mmdb::pstr MSG_WrongModelNo    = mmdb::pstr("wrong model number read from a file");
+static mmdb::pstr MSG_DuplicatedModel = mmdb::pstr("duplicated model number");
+static mmdb::pstr MSG_ForeignFile     = mmdb::pstr("unknown file format");
+static mmdb::pstr MSG_WrongEdition    = mmdb::pstr("unknown file version");
+
+static mmdb::pstr MSG_ATOM_Unrecognd  = mmdb::pstr("unrecognized data in coordinate section");
+static mmdb::pstr MSG_ATOM_AlreadySet = mmdb::pstr("duplicate atom serial number");
+static mmdb::pstr MSG_ATOM_NoResidue  = mmdb::pstr("residue for atom cannot be found");
+static mmdb::pstr MSG_ATOM_Unmatch    = mmdb::pstr("ambiguous data in coordinate section");
+
+static mmdb::pstr MSG_NoAdvance       = mmdb::pstr("atom position was not advanced");
+static mmdb::pstr MSG_EmptyPointer    = mmdb::pstr("atom was not allocated");
+static mmdb::pstr MSG_NoMatrices      = mmdb::pstr("no coordinate transformation matrices");
+
+static mmdb::pstr MSG_NoCoordinates   = mmdb::pstr("no atom coordinates set");
+
+static mmdb::pstr MSG_Disagreement    = mmdb::pstr("ambiguous cell parameters");
+static mmdb::pstr MSG_NoOrthCode      = mmdb::pstr("no orthogonalization code");
+static mmdb::pstr MSG_NoCheck         = mmdb::pstr("missing check of cell parameters");
+
+static mmdb::pstr MSG_NoCellParams    = mmdb::pstr("no cell parameters");
+
+static mmdb::pstr MSG_NotACIFFile     = mmdb::pstr("not a CIF file: 'data_' tag missing");
+static mmdb::pstr MSG_NoData          = mmdb::pstr("expected data is not met at reading a file");
+static mmdb::pstr MSG_UnrecognCIFItems  = mmdb::pstr("unrecognized CIF items (syntax error?)");
+static mmdb::pstr MSG_MissingCIFField   = mmdb::pstr("missing CIF data field");
+static mmdb::pstr MSG_EmptyCIFLoop      = mmdb::pstr("CIF loop does not contain any data");
+static mmdb::pstr MSG_UnexpEndOfCIF     = mmdb::pstr("unexpected end of CIF file");
+static mmdb::pstr MSG_MissgCIFLoopField = mmdb::pstr("CIF loop is incomplete");
+static mmdb::pstr MSG_NotACIFStructure  = mmdb::pstr("wrong use of CIF structure (as a loop?)");
+static mmdb::pstr MSG_NotACIFLoop       = mmdb::pstr("wrong use of CIF loop (as a structure?)");
+static mmdb::pstr MSG_WrongReal         = mmdb::pstr("unrecognized real at reading a file");
+
+static mmdb::pstr MSG_WrongChainID      = mmdb::pstr("Wrong or inconsistent chain ID");
+static mmdb::pstr MSG_WrongEntryID      = mmdb::pstr("Wrong or insonsistent entry ID");
+static mmdb::pstr MSG_SEQRES_serNum     = mmdb::pstr("Wrong serial number in SEQRES");
+static mmdb::pstr MSG_SEQRES_numRes     = mmdb::pstr("Wrong number of residues in SEQRES");
+static mmdb::pstr MSG_SEQRES_extraRes   = mmdb::pstr("Extra residues in SEQRES");
+static mmdb::pstr MSG_NCSM_Unrecogn     = mmdb::pstr("Unrecognized item in NCSM cards");
+static mmdb::pstr MSG_NCSM_AlreadySet   = mmdb::pstr("Attempt to reset NCSM");
+static mmdb::pstr MSG_NCSM_WrongSerial  = mmdb::pstr("Wrong serial number in NCSM cards");
+static mmdb::pstr MSG_NCSM_UnmatchIG    = mmdb::pstr("Unmatched IG parameter in NCSM cards");
+static mmdb::pstr MSG_NoModel           = mmdb::pstr("MMDB's error in structuring models");
+static mmdb::pstr MSG_NoSheetID         = mmdb::pstr("No sheet ID on SHEET card(s)");
+static mmdb::pstr MSG_WrongSheetID      = mmdb::pstr("Wrong sheet ID on SHEET card(s)");
+static mmdb::pstr MSG_WrongStrandNo     = mmdb::pstr("Wrong strand no. on SHEET card(s)");
+static mmdb::pstr MSG_WrongNofStrands   = mmdb::pstr("Wrong number of strands in sheet");
+static mmdb::pstr MSG_WrongSheetOrder   = mmdb::pstr("Wrong sheet ordering");
+static mmdb::pstr MSG_HBondInconsistency = mmdb::pstr("Inconsistency in H-bonds");
+static mmdb::pstr MSG_EmptyResidueName  = mmdb::pstr("No (blank) residue name");
+static mmdb::pstr MSG_DuplicateSeqNum   = mmdb::pstr("Duplicated sequence number and insertion code");
+static mmdb::pstr MSG_GeneralError1     = mmdb::pstr("MMDB's general error #1");
+
+
+static mmdb::pstr MSG_Error1          = mmdb::pstr("internal error #1 -- report to developer");
+static mmdb::pstr MSG_Error2          = mmdb::pstr("internal error #2 -- report to developer");
+static mmdb::pstr MSG_Error3          = mmdb::pstr("internal error #3 -- report to developer");
+
+static mmdb::pstr MSG_Unknown         = mmdb::pstr("unknown return code");
 
 
 #define nWarnings  7
@@ -2853,14 +2837,14 @@ static int RWBWarCode[nWarnings] = {
   RWBWAR_NoTempFactor
 };
 
-static pstr RWBWarning[nWarnings] = {
-  pstr("output file rewind"),
-  pstr("rewind or backspace at top of file"),
-  pstr("atom serial number does not match position"),
-  pstr("unknown form factor encountered"),
-  pstr("ambiguous form factor encountered"),
-  pstr("occupancy was not set"),
-  pstr("temperature factor was not set")
+static mmdb::pstr RWBWarning[nWarnings] = {
+  mmdb::pstr("output file rewind"),
+  mmdb::pstr("rewind or backspace at top of file"),
+  mmdb::pstr("atom serial number does not match position"),
+  mmdb::pstr("unknown form factor encountered"),
+  mmdb::pstr("ambiguous form factor encountered"),
+  mmdb::pstr("occupancy was not set"),
+  mmdb::pstr("temperature factor was not set")
 };
 
 
@@ -2878,9 +2862,9 @@ FORTRAN_SUBR ( RBERRSTOP, rberrstop,
                 int * iPlace, int * iRet,
                 int * iUnit,  int * iStop
                ) )  {
-int  i,k,lcount;
-pstr Msg;
-char ErrLine[500];
+int        i,k,lcount;
+mmdb::pstr Msg;
+char       ErrLine[500];
 
   strcpy ( ErrLine,"" );
   lcount = -11;
@@ -2918,7 +2902,7 @@ char ErrLine[500];
     case RWBERR_NoOrthCode        : Msg = MSG_NoOrthCode;         break;
     case RWBERR_NoCheck           : Msg = MSG_NoCheck;            break;
 
-    case RWBERR_NoCellParams      : Msg = MSG_NoCellParams;       break; 
+    case RWBERR_NoCellParams      : Msg = MSG_NoCellParams;       break;
 
     case RWBERR_NotACIFFile       : Msg = MSG_NotACIFFile;        break;
     case RWBERR_NoData            : Msg = MSG_NoData;             break;
@@ -2954,15 +2938,15 @@ char ErrLine[500];
     case RWBERR_Error1            : Msg = MSG_Error1;             break;
     case RWBERR_Error2            : Msg = MSG_Error2;             break;
     case RWBERR_Error3            : Msg = MSG_Error3;             break;
-  
+
     default                     :
       if ((*iRet & RWBWAR_Warning)==RWBWAR_Warning)  {
         Msg = NULL;
         printf ( "\n\n *** Warning(s): point code unit    function\n" );
         printf ( " ***             %5i %4i %4i    %s\n",
                            *iPlace,*iRet,*iUnit,LastFunc );
-        if (k>=0) 
-          printf ( " *** file   : %s\n",Channel[k]->FName );
+        if (k>=0)
+          printf ( " *** file   : %s\n",channel[k]->FName );
         for (i=0;i<nWarnings;i++)
           if ((*iRet & RWBWarCode[i])==RWBWarCode[i])  {
             Msg = RWBWarning[i];
@@ -2970,7 +2954,7 @@ char ErrLine[500];
             if ((*iRet & RWBWAR_WrongSerial)==RWBWAR_WrongSerial)  {
               if (k>0)
                 printf ( " *** position %i, serial number %i\n",
-                         Channel[k]->fPos,LastSer );
+                         channel[k]->fPos,LastSer );
               else
                 printf ( " *** position unavailable, serial number %i\n",
                          LastSer );
@@ -2988,20 +2972,20 @@ char ErrLine[500];
       ((*iRet<=RWBERR_ATOM_Unrecognd) && (*iRet>=RWBERR_ATOM_Unmatch))    ||
       ((*iRet<=RWBERR_NoData)         && (*iRet>=RWBERR_DuplicateSeqNum))
      ))
-    Channel[k]->GetInputBuffer ( ErrLine,lcount );
+    channel[k]->GetInputBuffer ( ErrLine,lcount );
 
   printf ( " \n *** RWBROOK error: point code unit    function\n"    );
   printf ( " ***                %5i %4i %4i    %s\n",*iPlace,*iRet,
                                                      *iUnit,LastFunc );
   k = GetChannel(*iUnit);
-  if (k>=0) 
-    printf ( " *** file   : %s\n",Channel[k]->FName );
+  if (k>=0)
+    printf ( " *** file   : %s\n",channel[k]->FName );
 
   printf ( " *** reason : %s\n",Msg );
   if (lcount>=0)
     printf ( " ***          at input line #%i:\n"
              " %s\n",lcount,ErrLine );
-  else if (lcount==-1) 
+  else if (lcount==-1)
     printf ( " ***          at taking the following data from CIF:\n"
              "              %s\n",ErrLine );
 
@@ -3044,9 +3028,12 @@ FORTRAN_SUBR ( RBCHECKERR, rbcheckerr,
 */
 
 FORTRAN_SUBR ( HY36ENCODE_F, hy36encode_f,
-               (const int *iwidth, int *value, fpstr strval, int strval_len),
-               (const int *iwidth, int *value, fpstr strval),
-               (const int *iwidth, int *value, fpstr strval, int strval_len))
+               (const int *iwidth, int *value,
+                mmdb::machine::fpstr strval, int strval_len),
+               (const int *iwidth, int *value,
+                mmdb::machine::fpstr strval),
+               (const int *iwidth, int *value,
+                mmdb::machine::fpstr strval, int strval_len))
 {
   unsigned width;
   char result[6];
@@ -3056,7 +3043,7 @@ FORTRAN_SUBR ( HY36ENCODE_F, hy36encode_f,
   if (hy36encode(width, *value, result)) {
     printf("problem in hy36encode_f! \n");
   }
-  strcpy_ns(FTN_STR(strval),result,FTN_LEN(strval));
+  mmdb::strcpy_ns(FTN_STR(strval),result,FTN_LEN(strval));
 
 }
 
@@ -3072,9 +3059,12 @@ FORTRAN_SUBR ( HY36ENCODE_F, hy36encode_f,
 
 
 FORTRAN_SUBR ( HY36DECODE_F, hy36decode_f,
-               (const int *iwidth, fpstr strval, int *value, int strval_len),
-               (const int *iwidth, fpstr strval, int *value),
-               (const int *iwidth, fpstr strval, int strval_len, int *value))
+               (const int *iwidth,
+                mmdb::machine::fpstr strval, int *value, int strval_len),
+               (const int *iwidth,
+                mmdb::machine::fpstr strval, int *value),
+               (const int *iwidth,
+                mmdb::machine::fpstr strval, int strval_len, int *value))
 { UNUSED_ARGUMENT(strval);
   unsigned width;
   size_t length = FTN_LEN(strval);
diff --git a/mmdb/mmdb_rwbrook.h b/mmdb2/mmdb_rwbrook.h
old mode 100755
new mode 100644
similarity index 79%
rename from mmdb/mmdb_rwbrook.h
rename to mmdb2/mmdb_rwbrook.h
index 94d05fa..2f59f5f
--- a/mmdb/mmdb_rwbrook.h
+++ b/mmdb2/mmdb_rwbrook.h
@@ -1,4 +1,4 @@
-//  $Id: mmdb_rwbrook.h,v 1.19 2012/01/26 17:52:20 ekr Exp $
+//  $Id: mmdb_rwbrook.h $
 //  =================================================================
 //
 //   CCP4 Coordinate Library: support of coordinate-related
@@ -6,13 +6,13 @@
 //
 //   Copyright (C) Eugene Krissinel 2000-2008.
 //
-//    This library is free software: you can redistribute it and/or 
-//    modify it under the terms of the GNU Lesser General Public 
-//    License version 3, modified in accordance with the provisions 
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
 //    of the license to address the requirements of UK law.
 //
-//    You should have received a copy of the modified GNU Lesser 
-//    General Public License along with this library. If not, copies 
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
 //    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
 //
 //    This program is distributed in the hope that it will be useful,
@@ -22,7 +22,7 @@
 //
 //  =================================================================
 //
-//    07.11.02   <--  Date of Last Modification.
+//    16.09.13   <--  Date of Last Modification.
 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //  -----------------------------------------------------------------
 //
@@ -64,7 +64,7 @@
 //                   rberrstop_       ( error messenger                   )
 //                   rbcheckerr_      ( a simple error messenger          )
 //
-//  (C) E. Krissinel 2000-2008
+//  (C) E. Krissinel 2000-2013
 //
 //  =================================================================
 //
@@ -73,96 +73,93 @@
 #ifndef  __MMDB_RWBrook__
 #define  __MMDB_RWBrook__
 
-#ifndef  __MatType__
-#include "mattype_.h"
-#endif
-
-#ifndef  __Machine__
-#include "machine_.h"
-#endif
+#include "mmdb_mattype.h"
+#include "mmdb_machine_.h"
 
 
 // ****** mmdb_rwbrook error codes
 
-#define  RWBERR_Ok                  0
-#define  RWBERR_NoChannel          -1
-#define  RWBERR_NoFile             -2
-#define  RWBERR_NoLogicalName      -3
-
-#define  RWBERR_CantOpenFile       -4
-#define  RWBERR_WrongInteger       -5
-#define  RWBERR_WrongModelNo       -6
-#define  RWBERR_DuplicatedModel    -7
-#define  RWBERR_ForeignFile        -8
-#define  RWBERR_WrongEdition       -9
-
-#define  RWBERR_ATOM_Unrecognd     -10
-#define  RWBERR_ATOM_AlreadySet    -11
-#define  RWBERR_ATOM_NoResidue     -12
-#define  RWBERR_ATOM_Unmatch       -13
-
-#define  RWBERR_NoAdvance          -14
-#define  RWBERR_EmptyPointer       -15
-#define  RWBERR_NoMatrices         -16
-
-#define  RWBERR_NoCoordinates      -17
-
-#define  RWBERR_Disagreement       -18
-#define  RWBERR_NoOrthCode         -19
-#define  RWBERR_NoCheck            -20
-
-#define  RWBERR_NoCellParams       -21
-
-#define  RWBERR_NotACIFFile        -22
-#define  RWBERR_NoData             -23
-#define  RWBERR_UnrecognCIFItems   -24
-#define  RWBERR_MissingCIFField    -25
-#define  RWBERR_EmptyCIFLoop       -26
-#define  RWBERR_UnexpEndOfCIF      -27
-#define  RWBERR_MissgCIFLoopField  -28
-#define  RWBERR_NotACIFStructure   -29
-#define  RWBERR_NotACIFLoop        -30
-#define  RWBERR_WrongReal          -31
-
-#define  RWBERR_WrongChainID       -32
-#define  RWBERR_WrongEntryID       -33
-#define  RWBERR_SEQRES_serNum      -34
-#define  RWBERR_SEQRES_numRes      -35
-#define  RWBERR_SEQRES_exraRes     -36
-#define  RWBERR_NCSM_Unrecogn      -37
-#define  RWBERR_NCSM_AlreadySet    -38
-#define  RWBERR_NCSM_WrongSerial   -39
-#define  RWBERR_NCSM_UnmatchIG     -40
-#define  RWBERR_NoModel            -41
-#define  RWBERR_NoSheetID          -42
-#define  RWBERR_WrongSheetID       -43
-#define  RWBERR_WrongStrandNo      -44
-#define  RWBERR_WrongNofStrands    -45
-#define  RWBERR_WrongSheetOrder    -46
-#define  RWBERR_HBondInconsis      -47
-#define  RWBERR_EmptyResidueName   -48
-#define  RWBERR_DuplicateSeqNum    -49
-#define  RWBERR_GeneralError1      -50
-
-
-#define  RWBERR_Error1             -101
-#define  RWBERR_Error2             -102
-#define  RWBERR_Error3             -103
-
+enum RWB_ERROR  {
+
+  RWBERR_Ok                =  0,
+  RWBERR_NoChannel         = -1,
+  RWBERR_NoFile            = -2,
+  RWBERR_NoLogicalName     = -3,
+
+  RWBERR_CantOpenFile      = -4,
+  RWBERR_WrongInteger      = -5,
+  RWBERR_WrongModelNo      = -6,
+  RWBERR_DuplicatedModel   = -7,
+  RWBERR_ForeignFile       = -8,
+  RWBERR_WrongEdition      = -9,
+
+  RWBERR_ATOM_Unrecognd    = -10,
+  RWBERR_ATOM_AlreadySet   = -11,
+  RWBERR_ATOM_NoResidue    = -12,
+  RWBERR_ATOM_Unmatch      = -13,
+
+  RWBERR_NoAdvance         = -14,
+  RWBERR_EmptyPointer      = -15,
+  RWBERR_NoMatrices        = -16,
+
+  RWBERR_NoCoordinates     = -17,
+
+  RWBERR_Disagreement      = -18,
+  RWBERR_NoOrthCode        = -19,
+  RWBERR_NoCheck           = -20,
+
+  RWBERR_NoCellParams      = -21,
+
+  RWBERR_NotACIFFile       = -22,
+  RWBERR_NoData            = -23,
+  RWBERR_UnrecognCIFItems  = -24,
+  RWBERR_MissingCIFField   = -25,
+  RWBERR_EmptyCIFLoop      = -26,
+  RWBERR_UnexpEndOfCIF     = -27,
+  RWBERR_MissgCIFLoopField = -28,
+  RWBERR_NotACIFStructure  = -29,
+  RWBERR_NotACIFLoop       = -30,
+  RWBERR_WrongReal         = -31,
+
+  RWBERR_WrongChainID      = -32,
+  RWBERR_WrongEntryID      = -33,
+  RWBERR_SEQRES_serNum     = -34,
+  RWBERR_SEQRES_numRes     = -35,
+  RWBERR_SEQRES_exraRes    = -36,
+  RWBERR_NCSM_Unrecogn     = -37,
+  RWBERR_NCSM_AlreadySet   = -38,
+  RWBERR_NCSM_WrongSerial  = -39,
+  RWBERR_NCSM_UnmatchIG    = -40,
+  RWBERR_NoModel           = -41,
+  RWBERR_NoSheetID         = -42,
+  RWBERR_WrongSheetID      = -43,
+  RWBERR_WrongStrandNo     = -44,
+  RWBERR_WrongNofStrands   = -45,
+  RWBERR_WrongSheetOrder   = -46,
+  RWBERR_HBondInconsis     = -47,
+  RWBERR_EmptyResidueName  = -48,
+  RWBERR_DuplicateSeqNum   = -49,
+  RWBERR_GeneralError1     = -50,
+
+  RWBERR_Error1            = -101,
+  RWBERR_Error2            = -102,
+  RWBERR_Error3            = -103
+
+};
 
 //  ***** mmdb_rwbrook warning flags
 //        0x00004000 means "it's a warning"
 
-#define  RWBWAR_Warning         0x00004000
-#define  RWBWAR_RewOutput       0x00004010
-#define  RWBWAR_FileTop         0x00004020
-#define  RWBWAR_WrongSerial     0x00004040
-#define  RWBWAR_UnkFormFactor   0x00004080
-#define  RWBWAR_AmbFormFactor   0x00004100
-#define  RWBWAR_NoOccupancy     0x00004200
-#define  RWBWAR_NoTempFactor    0x00004400
-
-
+enum RWB_WARNING  {
+  RWBWAR_Warning       = 0x00004000,
+  RWBWAR_RewOutput     = 0x00004010,
+  RWBWAR_FileTop       = 0x00004020,
+  RWBWAR_WrongSerial   = 0x00004040,
+  RWBWAR_UnkFormFactor = 0x00004080,
+  RWBWAR_AmbFormFactor = 0x00004100,
+  RWBWAR_NoOccupancy   = 0x00004200,
+  RWBWAR_NoTempFactor  = 0x00004400
+};
 
 // ------------------------------------------------------------------
 
@@ -174,7 +171,7 @@
 
 FORTRAN_SUBR ( MMDB_F_INIT, mmdb_f_init, (),(),() );
 
-                            
+
 // ------------------------------------------------------------------
 
 //    mmdb_f_quit_() disposes the file system. A correct use assumes that
@@ -184,7 +181,7 @@ FORTRAN_SUBR ( MMDB_F_INIT, mmdb_f_init, (),(),() );
 //  ~~~~~~~~~~~~~~~~~~~
 
 FORTRAN_SUBR ( MMDB_F_QUIT, mmdb_f_quit, (),(),() );
-                              
+
 
 // ------------------------------------------------------------------
 
@@ -217,7 +214,7 @@ FORTRAN_SUBR ( AUTOSERIALS,autoserials,
                ( int * iOnOff ),
                ( int * iOnOff ),
                ( int * iOnOff ) );
-                              
+
 
 // ------------------------------------------------------------------
 
@@ -236,7 +233,7 @@ FORTRAN_SUBR ( SETREADCOORDS,setreadcoords,
                ( int * iOnOff ),
                ( int * iOnOff ),
                ( int * iOnOff ) );
-                              
+
 
 // ------------------------------------------------------------------
 
@@ -299,25 +296,27 @@ FORTRAN_SUBR ( SIMRWBROOK,simrwbrook,
 //  FORTRAN equivalent:   subroutine MMDB_F_Open ( LName,RWStat,FType,
 //  ~~~~~~~~~~~~~~~~~~~                        iUnit,iRet )
 //                        character*(*)  LName,RWStat,FType
-//                        integer        iUnit,iRet 
+//                        integer        iUnit,iRet
 
 FORTRAN_SUBR ( MMDB_F_OPEN, mmdb_f_open,
                (    // lengths-at-end list
-                fpstr LName,      // logical name
-                fpstr RWStat,     // "INPUT" or "OUTPUT"
-                fpstr FType,      // "PDB", "CIF", "BIN" or " "
+                mmdb::machine::fpstr LName,  // logical name
+                mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+                mmdb::machine::fpstr FType,  // "PDB", "CIF", "BIN" or " "
                 int * iUnit,      // channel number
                 int * iRet,       // returns error code
                 int   LName_len,  // fortran-hidden length of LName
                 int   RWStat_len, // fortran-hidden length of RWStat
                 int   FType_len   // fortran-hidden length of FType
                ), ( // lengths-in-structure list
-                fpstr LName,  fpstr RWStat, fpstr FType,      
-                int * iUnit,  int * iRet       
+                mmdb::machine::fpstr LName,
+                mmdb::machine::fpstr RWStat,
+                mmdb::machine::fpstr FType,
+                int * iUnit,  int * iRet
                ), ( // lengths-follow list
-                fpstr LName,   int LName_len,    
-                fpstr RWStat,  int RWStat_len,   
-                fpstr FType,   int FType_len,   
+                mmdb::machine::fpstr LName,   int LName_len,
+                mmdb::machine::fpstr RWStat,  int RWStat_len,
+                mmdb::machine::fpstr FType,   int FType_len,
                 int * iUnit,   int * iRet
                ) );
 
@@ -331,25 +330,27 @@ FORTRAN_SUBR ( MMDB_F_OPEN, mmdb_f_open,
 //  FORTRAN equivalent:   subroutine MMDB_F_Open1 ( FName,RWStat,FType,
 //  ~~~~~~~~~~~~~~~~~~~                         iUnit,iRet )
 //                        character*(*)  FName,RWStat,FType
-//                        integer        iUnit,iRet 
+//                        integer        iUnit,iRet
 
 FORTRAN_SUBR ( MMDB_F_OPEN1, mmdb_f_open1,
                (    // lengths-at-end list
-                fpstr FName,      // file name
-                fpstr RWStat,     // "INPUT" or "OUTPUT"
-                fpstr FType,      // "PDB", "CIF", "BIN" or " "
+                mmdb::machine::fpstr FName,  // file name
+                mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
+                mmdb::machine::fpstr FType,  // "PDB", "CIF", "BIN" or " "
                 int * iUnit,      // channel number
                 int * iRet,       // returns error code
                 int   FName_len,  // fortran-hidden length of FName
                 int   RWStat_len, // fortran-hidden length of RWStat
                 int   FType_len   // fortran-hidden length of FType
                ), ( // lengths-in-structure list
-                fpstr FName,  fpstr RWStat, fpstr FType,      
-                int * iUnit,  int * iRet       
+                mmdb::machine::fpstr FName,
+                mmdb::machine::fpstr RWStat,
+                mmdb::machine::fpstr FType,
+                int * iUnit,  int * iRet
                ), ( // lengths-follow list
-                fpstr FName,   int FName_len,    
-                fpstr RWStat,  int RWStat_len,   
-                fpstr FType,   int FType_len,   
+                mmdb::machine::fpstr FName,   int FName_len,
+                mmdb::machine::fpstr RWStat,  int RWStat_len,
+                mmdb::machine::fpstr FType,   int FType_len,
                 int * iUnit,   int * iRet
                ) );
 
@@ -447,21 +448,21 @@ FORTRAN_SUBR ( MMDB_F_DELETE, mmdb_f_delete,
 FORTRAN_SUBR ( MMDB_F_SETTYPE, mmdb_f_settype,
                (    // lengths-at-end list
                 int * iUnit,     // unit number
-                fpstr FType,     // "PDB", "CIF", "BIN" or " "
-                fpstr RWStat,    // "INPUT" or "OUTPUT"
+                mmdb::machine::fpstr FType,  // "PDB", "CIF", "BIN" or " "
+                mmdb::machine::fpstr RWStat, // "INPUT" or "OUTPUT"
                 int * iRet,      // returns -1 if unit not found,
                                  // otherwise 0
                 int   FType_len, // fortran-hidden length of FType
                 int   RWStat_len // fortran-hidden length of RWStat
                ), ( // lengths-in-structure list
-                int * iUnit,  fpstr FType,
-                fpstr RWStat, int * iRet
+                int * iUnit,  mmdb::machine::fpstr FType,
+                mmdb::machine::fpstr RWStat, int * iRet
                ), ( // lengths-follow list
-                int * iUnit,     
-                fpstr FType,   int FType_len,  
-                fpstr RWStat,  int RWStat_len,
+                int * iUnit,
+                mmdb::machine::fpstr FType,   int FType_len,
+                mmdb::machine::fpstr RWStat,  int RWStat_len,
                 int * iRet
-               ) );            
+               ) );
 
 
 
@@ -483,15 +484,15 @@ FORTRAN_SUBR ( MMDB_F_SETTYPE, mmdb_f_settype,
 FORTRAN_SUBR ( MMDB_F_SETNAME, mmdb_f_setname,
                (    // lengths-at-end list
                 int * iUnit,    // unit number
-                fpstr FName,    // file name
+                mmdb::machine::fpstr FName,    // file name
                 int * iRet,     // returns -1 if unit not found,
                                 // otherwise 0
                 int   FName_len // fortran-hidden length of FName
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr FName, int * iRet
+                int * iUnit, mmdb::machine::fpstr FName, int * iRet
                ), ( // lengths-follow list
                 int * iUnit,
-                fpstr FName, int FName_len,
+                mmdb::machine::fpstr FName, int FName_len,
                 int * iRet
                ) );
 
@@ -540,7 +541,7 @@ FORTRAN_SUBR ( MMDB_F_CLOSE,  mmdb_f_close,
 
 //   If unit iUnit is associated with input, mmdb_f_advance_(..) sets
 // the internal pointer on the next atom in the file. The atom
-// properties may then be retrieved using mmdb_f_atom_(..) and 
+// properties may then be retrieved using mmdb_f_atom_(..) and
 // mmdb_f_coord_(..). If iTer is set to 0, then 'ter' cards are
 // completely ignored. If iTer is set to 1, then 'ter' card will
 // cause return with iRet=1 with internal pointer left on this 'ter'
@@ -697,17 +698,17 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
            (    // lengths-at-end list
             int * iUnit,    // unit number
             int * iSer,     // atom serial number
-            fpstr AtNam,    // atom name (left justified)
-            fpstr ResNam,   // residue name
-            fpstr ChnNam,   // chain name
+            mmdb::machine::fpstr AtNam,    // atom name (left justified)
+            mmdb::machine::fpstr ResNam,   // residue name
+            mmdb::machine::fpstr ChnNam,   // chain name
             int * iResN,    // residue number as an integer
-            fpstr ResNo,    // residue number as character (input only)
-            fpstr InsCod,   // the insertion code
-            fpstr AltCod,   // the alternate conformation code
-            fpstr segID,    // segment ID
+            mmdb::machine::fpstr ResNo,    // residue number as character (input only)
+            mmdb::machine::fpstr InsCod,   // the insertion code
+            mmdb::machine::fpstr AltCod,   // the alternate conformation code
+            mmdb::machine::fpstr segID,    // segment ID
             int * IZ,       // atomic number (input only, returned as
                             // 7 from ambiguous atoms)
-            fpstr ID,       // atomic ID related to atomic number
+            mmdb::machine::fpstr ID,       // atomic ID related to atomic number
                             // (element symbol right justified), plus
                             // the ionic state +2, +3 etc..
                             //
@@ -724,7 +725,7 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
                             //  RWBWAR_WrongSerial   if serial number
                             //               differs from the position
                             //               number in the file
-                            //  RWBWAR_UnkFormFactor unknown formfactor 
+                            //  RWBWAR_UnkFormFactor unknown formfactor
                             //  RWBWAR_AmbFormFactor ambiguous formfactor
                             //
             int AtNam_len,  // fortran-hidden length of AtNam
@@ -736,22 +737,28 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
             int segID_len,  // fortran-hidden length of SegID
             int ID_len      // fortran-hidden length of ID
            ), ( // lengths-in-structure list
-            int * iUnit,  int * iSer,  fpstr AtNam,  fpstr ResNam,
-            fpstr ChnNam, int * iResN, fpstr ResNo,  fpstr InsCod,
-            fpstr AltCod, fpstr segID, int * IZ,     fpstr ID,
+            int * iUnit,  int * iSer,
+            mmdb::machine::fpstr AtNam,
+            mmdb::machine::fpstr ResNam,
+            mmdb::machine::fpstr ChnNam, int * iResN,
+            mmdb::machine::fpstr ResNo,
+            mmdb::machine::fpstr InsCod,
+            mmdb::machine::fpstr AltCod,
+            mmdb::machine::fpstr segID, int * IZ,
+            mmdb::machine::fpstr ID,
             int * iRet
            ), ( // lengths-follow list
             int * iUnit,  int * iSer,
-            fpstr AtNam,  int   AtNam_len,
-            fpstr ResNam, int   ResNam_len,
-            fpstr ChnNam, int   ChnNam_len,
+            mmdb::machine::fpstr AtNam,  int   AtNam_len,
+            mmdb::machine::fpstr ResNam, int   ResNam_len,
+            mmdb::machine::fpstr ChnNam, int   ChnNam_len,
             int * iResN,
-            fpstr ResNo,  int   ResNo_len,
-            fpstr InsCod, int   InsCod_len,
-            fpstr AltCod, int   AltCod_len,
-            fpstr segID,  int   segID_len,
+            mmdb::machine::fpstr ResNo,  int   ResNo_len,
+            mmdb::machine::fpstr InsCod, int   InsCod_len,
+            mmdb::machine::fpstr AltCod, int   AltCod_len,
+            mmdb::machine::fpstr segID,  int   segID_len,
             int * IZ,
-            fpstr ID,     int   ID_len,
+            mmdb::machine::fpstr ID,     int   ID_len,
             int * iRet
            ) );
 
@@ -767,7 +774,7 @@ FORTRAN_SUBR ( MMDB_F_ATOM,  mmdb_f_atom,
 
 FORTRAN_SUBR ( MMDB_F_COPYATOM, mmdb_f_copyatom,
                ( // length-at-end list
-		int * iUnit1, // source channel number
+    int * iUnit1, // source channel number
                 int * iUnit2, // destination channel number
                 int * iRet    // returns
                               //  RWBERR_NoChannel     if iUnit was not
@@ -775,7 +782,7 @@ FORTRAN_SUBR ( MMDB_F_COPYATOM, mmdb_f_copyatom,
                               //  RWBERR_EmptyPointer  if atom was not
                               //                       advanced
                               //  >=0 : success
-	       ), ( // length-in-structure list
+         ), ( // length-in-structure list
                 int * iUnit1, int * iUnit2, int * iRet
                ), ( // length-follow list
                 int * iUnit1, int * iUnit2, int * iRet
@@ -806,22 +813,22 @@ FORTRAN_SUBR ( MMDB_F_COPYATOM, mmdb_f_copyatom,
 FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
                (    // lengths-at-end list
                 int * iUnit,    // unit number
-                fpstr XFlag,    // "F" or "O" flag for the fractional
+                mmdb::machine::fpstr XFlag,    // "F" or "O" flag for the fractional
                                 // or orthogonal coordinates x,y,z
                                 // for output files XFlag may also be
                                 // set to "HF" or "HO", where "F" and
                                 // "O" have the same meaning as before
                                 // and "H" indicates that the atom
                                 // should be marked as heteroatom
-                fpstr BFlag ,   // "F" or "O" flag for temperature
+                mmdb::machine::fpstr BFlag ,   // "F" or "O" flag for temperature
                                 // factor in fractional or orthogonal
                                 // Us
-                apireal * x,    // x-coordinate
-                apireal * y,    // y-coordinate
-                apireal * z,    // z-coordinate
-                apireal * occ,  // occupancy
-                apireal * BIso, // isotropic temperature factor
-                apireal * U,    // array(6) of the anisotr. t-factor
+                mmdb::machine::apireal * x,    // x-coordinate
+                mmdb::machine::apireal * y,    // y-coordinate
+                mmdb::machine::apireal * z,    // z-coordinate
+                mmdb::machine::apireal * occ,  // occupancy
+                mmdb::machine::apireal * BIso, // isotropic temperature factor
+                mmdb::machine::apireal * U,    // array(6) of the anisotr. t-factor
                 int * iRet,     // returns
                                 //  RWBERR_NoChannel     if iUnit was not
                                 //                       initialized
@@ -834,7 +841,7 @@ FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
                                 //                       not set in the atom
                                 //
                                 //  >=0 : success, warning flags:
-                                //  RWBERR_NoOccupancy   if occupancy was  
+                                //  RWBERR_NoOccupancy   if occupancy was
                                 //                       not set in the atom
                                 //  RWBERR_NoTempFactor  if temp. factor was
                                 //                       not set in the atom
@@ -842,16 +849,26 @@ FORTRAN_SUBR ( MMDB_F_COORD, mmdb_f_coord,
                 int XFlag_len,  // fortran-hidden length of XFlag
                 int BFlag_len   // fortran-hidden length of BFlag
                ), ( // lengths-in-structure list
-                int * iUnit,   fpstr XFlag,    fpstr BFlag,
-                apireal * x,   apireal * y,    apireal * z,
-                apireal * occ, apireal * BIso, apireal * U,
+                int * iUnit,
+                mmdb::machine::fpstr XFlag,
+                mmdb::machine::fpstr BFlag,
+                mmdb::machine::apireal * x,
+                mmdb::machine::apireal * y,
+                mmdb::machine::apireal * z,
+                mmdb::machine::apireal * occ,
+                mmdb::machine::apireal * BIso,
+                mmdb::machine::apireal * U,
                 int * iRet
                ), ( // lengths-follow list
                 int * iUnit,
-                fpstr XFlag,   int XFlag_len,
-                fpstr BFlag,   int BFlag_len,
-                apireal * x,   apireal * y,    apireal * z,
-                apireal * occ, apireal * BIso, apireal * U,
+                mmdb::machine::fpstr XFlag,   int XFlag_len,
+                mmdb::machine::fpstr BFlag,   int BFlag_len,
+                mmdb::machine::apireal * x,
+                mmdb::machine::apireal * y,
+                mmdb::machine::apireal * z,
+                mmdb::machine::apireal * occ,
+                mmdb::machine::apireal * BIso,
+                mmdb::machine::apireal * U,
                 int * iRet
                ) );
 
@@ -903,10 +920,10 @@ FORTRAN_SUBR ( MMDB_F_SETHET, mmdb_f_sethet,
 //                        real          a,b,c,alpha,beta,gamma
 
 
-//  Relation to the former RBFRAC2 FORTRAN subroutine:     
+//  Relation to the former RBFRAC2 FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBFRAC2 ( a,b,c,alpha,beta,gamma,ArgNCode )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -914,12 +931,12 @@ FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
                (   //   lengths-at-end list
                 int     * iUnit,    // unit number; *iUnit<=0 means
                                     // "the last mentioned unit"
-                apireal * a,        // cell parameter a, angstroms
-                apireal * b,        // cell parameter b, angstroms
-                apireal * c,        // cell parameter c, angstroms
-                apireal * alpha,    // cell parameter alpha, degrees
-                apireal * beta,     // cell parameter beta,  degrees
-                apireal * gamma,    // cell parameter gamma, degrees
+                mmdb::machine::apireal * a,     // cell parameter a, angstroms
+                mmdb::machine::apireal * b,     // cell parameter b, angstroms
+                mmdb::machine::apireal * c,     // cell parameter c, angstroms
+                mmdb::machine::apireal * alpha, // cell parameter alpha, degrees
+                mmdb::machine::apireal * beta,  // cell parameter beta,  degrees
+                mmdb::machine::apireal * gamma, // cell parameter gamma, degrees
                 int     * ArgNCode, // orthogonalization code, 1-6
                 int     * iRet      // return code:
                                     //   RWBERR_Ok  - success
@@ -943,13 +960,21 @@ FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
                                     // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
                 int     * iUnit,
-                apireal * a,        apireal * b,    apireal * c,
-                apireal * alpha,    apireal * beta, apireal * gamma,
+                mmdb::machine::apireal * a,
+                mmdb::machine::apireal * b,
+                mmdb::machine::apireal * c,
+                mmdb::machine::apireal * alpha,
+                mmdb::machine::apireal * beta,
+                mmdb::machine::apireal * gamma,
                 int     * ArgNCode, int     * iRet
                ), ( // lengths-follow list
                 int     * iUnit,
-                apireal * a,        apireal * b,    apireal * c,
-                apireal * alpha,    apireal * beta, apireal * gamma,
+                mmdb::machine::apireal * a,
+                mmdb::machine::apireal * b,
+                mmdb::machine::apireal * c,
+                mmdb::machine::apireal * alpha,
+                mmdb::machine::apireal * beta,
+                mmdb::machine::apireal * gamma,
                 int     * ArgNCode, int     * iRet
                )
              );
@@ -968,7 +993,7 @@ FORTRAN_SUBR ( MMDB_F_SETCELL, mmdb_f_setcell,
 //  Relation to the former WBSpGrp FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  WBSpGrp ( spGroup )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -976,7 +1001,7 @@ FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
                (   //   lengths-at-end list
                 int * iUnit,    // unit number; *iUnit<=0 means
                                 // "the last mentioned unit"
-                fpstr spGroup,  // space group
+                mmdb::machine::fpstr spGroup,  // space group
                 int * iRet,     // return code:
                                 //   RWBERR_Ok  - success
                                 //   RWBERR_NoChannel     if unit
@@ -986,9 +1011,9 @@ FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
                                 //              has been disposed
                 int spGroup_len // fortran-hidden length of spGroup
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr spGroup, int * iRet
+                int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, fpstr spGroup, int spGroup_len,
+                int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
                 int * iRet
                )
              );
@@ -1007,7 +1032,7 @@ FORTRAN_SUBR ( MMDB_F_WBSPGRP, mmdb_f_wbspgrp,
 //  Relation to the former RBSpGrp FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBSpGrp ( spGroup )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -1015,7 +1040,7 @@ FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
                (   //   lengths-at-end list
                 int * iUnit,    // unit number; *iUnit<=0 means
                                 // "the last mentioned unit"
-                fpstr spGroup,  // space group
+                mmdb::machine::fpstr spGroup,  // space group
                 int * iRet,     // return code:
                                 //   RWBERR_Ok  - success
                                 //   RWBERR_NoChannel     if unit
@@ -1025,9 +1050,9 @@ FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
                                 //              has been disposed
                 int spGroup_len // fortran-hidden length of spGroup
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr spGroup, int * iRet
+                int * iUnit, mmdb::machine::fpstr spGroup, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, fpstr spGroup, int spGroup_len,
+                int * iUnit, mmdb::machine::fpstr spGroup, int spGroup_len,
                 int * iRet
                )
              );
@@ -1043,19 +1068,19 @@ FORTRAN_SUBR ( MMDB_F_RBSPGRP, mmdb_f_rbspgrp,
 //  ~~~~~~~~~~~~~~~~~~~                        ArgNCode,iRet )
 //                        integer iUnit,ArgNCode,iRet
 //                        real    ArgCell(6)
-//                        
+//
 
-//  Relation to the former WBCELL FORTRAN subroutine:     
+//  Relation to the former WBCELL FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  WBCELL ( iUnit,ArgCell,ArgNCode )
-//   
+//
 //  ** the buffer for the return code iRet has to be supplied
 
 FORTRAN_SUBR ( MMDB_F_WBCELL, mmdb_f_wbcell,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number; *iUnit<=0 means
                                     // "the last mentioned unit"
-                apireal * ArgCell,  // array to accept the cell parameters
+                mmdb::machine::apireal * ArgCell,  // array to accept the cell parameters
                                     // if ArgCell(1) is set to 0, then
                                     // the cell does not change
                 int     * ArgNCode, // orthogonalisation code
@@ -1070,10 +1095,10 @@ FORTRAN_SUBR ( MMDB_F_WBCELL, mmdb_f_wbcell,
                                     //   RWBERR_NoFile        if unit
                                     //              has been disposed
                ), ( // lengths-in-structure list
-                int * iUnit,    apireal * ArgCell,
+                int * iUnit,    mmdb::machine::apireal * ArgCell,
                 int * ArgNCode, int     * iRet
                ), ( // lengths-follow list
-                int * iUnit,    apireal * ArgCell,
+                int * iUnit,    mmdb::machine::apireal * ArgCell,
                 int * ArgNCode, int     * iRet
                )
              );
@@ -1090,10 +1115,10 @@ FORTRAN_SUBR ( MMDB_F_WBCELL, mmdb_f_wbcell,
 //                        real          celld(6),cvol
 //                        character*(*) spGroup
 
-//  Relation to the former RBCELL FORTRAN subroutine:     
+//  Relation to the former RBCELL FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBCELL ( celld,cvol )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -1101,33 +1126,33 @@ FORTRAN_SUBR ( MMDB_F_RBCELL, mmdb_f_rbcell,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number; *iUnit<=0 means
                                     // "the last mentioned unit"
-                apireal * celld,    // array to accept the cell parameters
-                apireal * cvol,     // returns the cell volume
+                mmdb::machine::apireal * celld,    // array to accept the cell parameters
+                mmdb::machine::apireal * cvol,     // returns the cell volume
                 int     * iRet      // return code
-		                    //   RWBERR_Ok  - success
-		                    //   RWBERR_NoChannel     if unit
-		                    //              iUnit was not
-		                    //              initialized
-		                    //   RWBERR_NoFile        if unit
-		                    //              has been disposed
-		                    //   RWBERR_Parameters    if the
-		                    //              cell parameters
-		                    //              were not set
-		                    //   RWBERR_NoOrthCode    if no
+                        //   RWBERR_Ok  - success
+                        //   RWBERR_NoChannel     if unit
+                        //              iUnit was not
+                        //              initialized
+                        //   RWBERR_NoFile        if unit
+                        //              has been disposed
+                        //   RWBERR_Parameters    if the
+                        //              cell parameters
+                        //              were not set
+                        //   RWBERR_NoOrthCode    if no
                                     //              orthogonalization
-		                    //              code was found
-		                    //   RWBERR_NoCheck       if check
-		                    //              of cell parameters
-		                    //              has failed.
+                        //              code was found
+                        //   RWBERR_NoCheck       if check
+                        //              of cell parameters
+                        //              has failed.
                                     //   The last three returns would
-		                    // rather indicate a programming
-		                    // error in mmdb_rwbrook.cpp
+                        // rather indicate a programming
+                        // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
-                int     * iUnit,  apireal * celld,
-                apireal * cvol,   int     * iRet
+                int     * iUnit,  mmdb::machine::apireal * celld,
+                mmdb::machine::apireal * cvol,   int     * iRet
                ), ( // lengths-follow list
-                int     * iUnit,  apireal * celld,
-                apireal * cvol,   int     * iRet
+                int     * iUnit,  mmdb::machine::apireal * celld,
+                mmdb::machine::apireal * cvol,   int     * iRet
                ) );
 
 
@@ -1142,10 +1167,10 @@ FORTRAN_SUBR ( MMDB_F_RBCELL, mmdb_f_rbcell,
 //                        integer       iUnit,ArgNCode,iRet
 //                        real          celld(6),cvol
 
-//  Relation to the former RBCELL FORTRAN subroutine:     
+//  Relation to the former RBCELL FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBCELL ( celld,cvol )
-//   
+//
 //  ** the unit number iUnit, buffer for orthogonalization code
 //     ArgNCode and for the return code iRet have to be supplied.
 
@@ -1153,8 +1178,8 @@ FORTRAN_SUBR ( MMDB_F_RBCELLN, mmdb_f_rbcelln,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number; *iUnit<=0 means
                                     // "the last mentioned unit"
-                apireal * celld,    // array to accept the cell parameters
-                apireal * cvol,     // returns the cell volume
+                mmdb::machine::apireal * celld,    // array to accept the cell parameters
+                mmdb::machine::apireal * cvol,     // returns the cell volume
                 int     * ArgNCode, // returns the orthogonalization code, 1-6
                 int     * iRet      // return code
                                     //   RWBERR_Ok  - success
@@ -1176,10 +1201,14 @@ FORTRAN_SUBR ( MMDB_F_RBCELLN, mmdb_f_rbcelln,
                                     // rather indicate a programming
                                     // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
-                int * iUnit,    apireal * celld, apireal * cvol,
+                int * iUnit,
+                mmdb::machine::apireal * celld,
+                mmdb::machine::apireal * cvol,
                 int * ArgNCode, int     * iRet
                ), ( // lengths-follow list
-                int * iUnit,    apireal * celld, apireal * cvol,
+                int * iUnit,
+                mmdb::machine::apireal * celld,
+                mmdb::machine::apireal * cvol,
                 int * ArgNCode, int     * iRet
                )
              );
@@ -1196,43 +1225,47 @@ FORTRAN_SUBR ( MMDB_F_RBCELLN, mmdb_f_rbcelln,
 //                        integer       iUnit,iRet
 //                        real          rcell(6),rvol
 
-//  Relation to the former RBRCEL FORTRAN subroutine:     
+//  Relation to the former RBRCEL FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBRCEL ( rcell,rvol )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 // have to be supplied.
 
 FORTRAN_SUBR ( MMDB_F_RBRCEL, mmdb_f_rbrcel,
                (    // lengths-at-end list
                 int     * iUnit,    // unit number
-                apireal * rcell,    // array to accept the reciprocal
+                mmdb::machine::apireal * rcell,    // array to accept the reciprocal
                                     // cell parameters
-                apireal * rvol,     // returns the reciprocal cell volume
+                mmdb::machine::apireal * rvol,     // returns the reciprocal cell volume
                 int     * iRet      // return code
-		                    //   RWBERR_Ok  - success
-		                    //   RWBERR_NoChannel     if unit
-		                    //              iUnit was not
-		                    //              initialized
-		                    //   RWBERR_NoFile        if unit
-		                    //              has been disposed
-		                    //   RWBERR_Parameters    if the
-		                    //              cell parameters
-		                    //              were not set
-		                    //   RWBERR_NoOrthCode    if no
+                        //   RWBERR_Ok  - success
+                        //   RWBERR_NoChannel     if unit
+                        //              iUnit was not
+                        //              initialized
+                        //   RWBERR_NoFile        if unit
+                        //              has been disposed
+                        //   RWBERR_Parameters    if the
+                        //              cell parameters
+                        //              were not set
+                        //   RWBERR_NoOrthCode    if no
                                     //              orthogonalization
-		                    //              code was found
-		                    //   RWBERR_NoCheck       if check
-		                    //              of cell parameters
-		                    //              has failed.
+                        //              code was found
+                        //   RWBERR_NoCheck       if check
+                        //              of cell parameters
+                        //              has failed.
                                     //   The last three returns would
-		                    // rather indicate a programming
-		                    // error in mmdb_rwbrook.cpp
+                        // rather indicate a programming
+                        // error in mmdb_rwbrook.cpp
                ), ( // lengths-in-structure list
-                int * iUnit,    apireal * rcell, apireal * rvol,
+                int * iUnit,
+                mmdb::machine::apireal * rcell,
+                mmdb::machine::apireal * rvol,
                 int * iRet
                ), ( // lengths-follow list
-                int * iUnit,    apireal * rcell, apireal * rvol,
+                int * iUnit,
+                mmdb::machine::apireal * rcell,
+                mmdb::machine::apireal * rvol,
                 int * iRet
                ) );
 
@@ -1251,10 +1284,10 @@ FORTRAN_SUBR ( MMDB_F_RBRCEL, mmdb_f_rbrcel,
 //                        integer  iUnit,LCode,iRet
 //                        real     RO(4,4),RF(4,4)
 
-//  Relation to the former RBRORF2 FORTRAN subroutine:     
+//  Relation to the former RBRORF2 FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBRORF2 ( RO,RF,LCode )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -1262,8 +1295,8 @@ FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
                (     // lengths-at-end list
                  int     * iUnit, // unit number; *iUnit<=0 means
                                   // "the last mentioned unit"
-                 apireal * RO,    // array for orthogonalising matrix
-                 apireal * RF,    // array for fractionalising matrix
+                 mmdb::machine::apireal * RO,    // array for orthogonalising matrix
+                 mmdb::machine::apireal * RF,    // array for fractionalising matrix
                  int     * LCode, // buffer for orthogonalisation code
                  int     * iRet   // return code:
                                   //   RWBERR_Ok  - success
@@ -1277,10 +1310,14 @@ FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
                                   //              matrices were not
                                   //              calculated
                 ), ( // lengths-in-structure list
-                 int * iUnit, apireal * RO, apireal * RF,
+                 int * iUnit,
+                 mmdb::machine::apireal * RO,
+                 mmdb::machine::apireal * RF,
                  int * LCode, int * iRet
                 ), ( // lengths-follow list
-                 int * iUnit, apireal * RO, apireal * RF,
+                 int * iUnit,
+                 mmdb::machine::apireal * RO,
+                 mmdb::machine::apireal * RF,
                  int * LCode, int * iRet
                 )
              );
@@ -1300,10 +1337,10 @@ FORTRAN_SUBR ( MMDB_F_RBORF, mmdb_f_rborf,
 //                        integer  iUnit,iRet
 //                        real     Cell(6),Vol,RRR(3,3,6)
 
-//  Relation to the former RBFRO1 FORTRAN subroutine:     
+//  Relation to the former RBFRO1 FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  RBFRO1 ( Cell,Vol,RRR )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -1311,12 +1348,12 @@ FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
                (     // lengths-at-end list
                 int     * iUnit, // unit number; *iUnit<=0 means
                                  // "the last mentioned unit"
-                apireal * Cell,  // array of cell parameters:
+                mmdb::machine::apireal * Cell,  // array of cell parameters:
                                  //  Cell(1) - a   Cell(4) - alpha
                                  //  Cell(2) - b   Cell(5) - beta
                                  //  Cell(3) - c   Cell(6) - gamma
-                apireal * Vol,   // returns cell volume
-                apireal * RRR,   // array (3,3,6), returns
+                mmdb::machine::apireal * Vol,   // returns cell volume
+                mmdb::machine::apireal * RRR,   // array (3,3,6), returns
                                  // orthogonalisation matrices
                 int     * iRet   // return code:
                                  //   RWBERR_Ok  - success
@@ -1330,11 +1367,15 @@ FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
                                  //              matrices were not
                                  //              calculated
                ), ( // lengths-in-structure list
-                int     * iUnit, apireal * Cell, apireal * Vol,
-                apireal * RRR,   int * iRet
+                int     * iUnit,
+                mmdb::machine::apireal * Cell,
+                mmdb::machine::apireal * Vol,
+                mmdb::machine::apireal * RRR,   int * iRet
                ), ( // lengths-follow list
-                int     * iUnit, apireal * Cell, apireal * Vol,
-                apireal * RRR,   int * iRet
+                int     * iUnit,
+                mmdb::machine::apireal * Cell,
+                mmdb::machine::apireal * Vol,
+                mmdb::machine::apireal * RRR,   int * iRet
                )
              );
 
@@ -1349,10 +1390,10 @@ FORTRAN_SUBR ( MMDB_F_ORTHMAT, mmdb_f_orthmat,
 //  ~~~~~~~~~~~~~~~~~~~   integer  iUnit,iFlag,iRet
 //                        real     U(6)
 
-//  Relation to the former CVANISOU FORTRAN subroutine:     
+//  Relation to the former CVANISOU FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  CVANISOU ( U,iFlag )
-//   
+//
 //  ** the unit number iUnit and buffer for the return code iRet
 //     have to be supplied.
 
@@ -1360,7 +1401,7 @@ FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
                (     // lengths-at-end list
                 int     * iUnit, // unit number; *iUnit<=0 means
                                  // "the last mentioned unit"
-                apireal * U,     // array of coordinates to convert
+                mmdb::machine::apireal * U,     // array of coordinates to convert
                 int     * iFlag, // =0: convert from fract. to orthog.
                                  // =1: convert from orthog. to fract.
                 int     * iRet   // return code:
@@ -1375,9 +1416,11 @@ FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
                                  //              matrices were not
                                  //              calculated
                ), ( // lengths-in-structure list
-                int * iUnit, apireal * U, int * iFlag, int * iRet
+                int * iUnit,
+                mmdb::machine::apireal * U, int * iFlag, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, apireal * U, int * iFlag, int * iRet
+                int * iUnit,
+                mmdb::machine::apireal * U, int * iFlag, int * iRet
                )
              );
 
@@ -1398,17 +1441,17 @@ FORTRAN_SUBR ( MMDB_F_CVANISOU, mmdb_f_cvanisou,
 //  ~~~~~~~~~~~~~~~~~~~   integer       iUnit,iRet
 //                        character*(*) Line
 
-//  Relation to the former WRemark FORTRAN subroutine:     
+//  Relation to the former WRemark FORTRAN subroutine:
 //  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //     subroutine  WRemark ( iUnit,Line )
-//   
+//
 //  ** the buffer for return code iRet has to be supplied
 
 FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
                (    // lengths-at-end list
                 int     * iUnit, // unit number; *iUnit<=0 means
                                  // "the last mentioned unit"
-                fpstr     Line,  // line to be added
+                mmdb::machine::fpstr     Line,  // line to be added
                 int     * iRet,  // return code:
                                  //   RWBERR_Ok  - success
                                  //   RWBERR_NoChannel     if unit
@@ -1420,9 +1463,11 @@ FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
                                  // returned by mmdb_f_open1_(..)
                 int    Line_len  // fortran-hidden length of Line
                ), ( // lengths-in-structure list
-                int * iUnit, fpstr Line, int * iRet
+                int * iUnit,
+                mmdb::machine::fpstr Line, int * iRet
                ), ( // lengths-follow list
-                int * iUnit, fpstr Line, int Line_len, int *iRet
+                int * iUnit,
+                mmdb::machine::fpstr Line, int Line_len, int *iRet
                )
              );
 
@@ -1437,9 +1482,9 @@ FORTRAN_SUBR ( MMDB_F_WREMARK, mmdb_f_wremark,
 //  ~~~~~~~~~~~~~~~~~~~   real  A(4,4),AI(4,4)
 
 FORTRAN_SUBR ( RBRINV, rbrinv,
-               ( apireal * A, apireal * AI ),
-               ( apireal * A, apireal * AI ),
-               ( apireal * A, apireal * AI )
+               ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+               ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI ),
+               ( mmdb::machine::apireal * A, mmdb::machine::apireal * AI )
              );
 
 */
@@ -1457,16 +1502,16 @@ FORTRAN_SUBR ( RBRINV, rbrinv,
 
 FORTRAN_SUBR ( RES3TO1, res3to1,
                (     // lengths-at-end list
-                fpstr ResNm3,   // 3-char name, 4th char
+                mmdb::machine::fpstr ResNm3,   // 3-char name, 4th char
                                 // will be set blank
-                fpstr ResNm1,   // 1-char name
+                mmdb::machine::fpstr ResNm1,   // 1-char name
                 int ResNm3_len, // fortran-hidden length of ResNm3
                 int ResNm1_len  // fortran-hidden length of ResNm3
                ), ( // lengths-in-structure list
-                fpstr ResNm3, fpstr ResNm1
+                mmdb::machine::fpstr ResNm3, mmdb::machine::fpstr ResNm1
                ), ( // lengths-follow list
-                fpstr ResNm3, int ResNm3_len,
-                fpstr ResNm1, int ResNm1_len
+                mmdb::machine::fpstr ResNm3, int ResNm3_len,
+                mmdb::machine::fpstr ResNm1, int ResNm1_len
                )
              );
 
diff --git a/mmdb2/mmdb_selmngr.cpp b/mmdb2/mmdb_selmngr.cpp
new file mode 100644
index 0000000..3aeec25
--- /dev/null
+++ b/mmdb2/mmdb_selmngr.cpp
@@ -0,0 +1,3421 @@
+//  $Id: mmdb_selmngr.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    15.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_selmngr <implementation>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Manager ( MMDB atom selection manager )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_selmngr.h"
+
+
+namespace mmdb  {
+
+  const int ANY_RES = MinInt4;
+
+  //  ====================   SelManager   =====================
+
+  SelManager::SelManager() : CoorManager()  {
+    InitSelManager();
+  }
+
+  SelManager::SelManager ( io::RPStream Object )
+                 : CoorManager(Object)  {
+    InitSelManager();
+  }
+
+  SelManager::~SelManager()  {
+    DeleteAllSelections();
+  }
+
+  void  SelManager::ResetManager()  {
+    CoorManager::ResetManager();
+    DeleteAllSelections();
+    InitSelManager ();
+  }
+
+  void  SelManager::InitSelManager()  {
+    nSelections = 0;     // number of selections
+    mask        = NULL;  // vector of selections
+    selType     = NULL;  // vector of selection types
+    nSelItems   = NULL;  // numbers of selected items
+    selection   = NULL;  // vector of selected items
+  }
+
+
+  // ------------------------  Selection  -----------------------------
+
+  int  SelManager::NewSelection()  {
+  PMask    M;
+  PPMask   Mask1;
+  PPMask * Selection1;
+  ivector  nSelItems1;
+  SELECTION_TYPE * SelType1;
+  int      i,l;
+
+    M = new Mask();
+    M->NewMask ( mask,nSelections );
+
+    i = 0;
+    while (i<nSelections)
+      if (!mask[i])  break;
+               else  i++;
+
+    if (i>=nSelections)  {
+      l          = nSelections+10;
+      Mask1      = new PMask [l];
+      Selection1 = new PPMask[l];
+      nSelItems1 = new int[l];
+      SelType1   = new SELECTION_TYPE[l];
+      for (i=0;i<nSelections;i++)  {
+        Mask1     [i] = mask     [i];
+        Selection1[i] = selection[i];
+        nSelItems1[i] = nSelItems[i];
+        SelType1  [i] = selType  [i];
+      }
+      for (i=nSelections;i<l;i++)  {
+        Mask1     [i] = NULL;
+        Selection1[i] = NULL;
+        nSelItems1[i] = 0;
+        SelType1  [i] = STYPE_UNDEFINED;
+      }
+      if (mask)      delete[] mask;
+      if (selection) delete[] selection;
+      if (nSelItems) delete[] nSelItems;
+      if (selType)   delete[] selType;
+      mask        = Mask1;
+      selection   = Selection1;
+      nSelItems   = nSelItems1;
+      selType     = SelType1;
+      i           = nSelections;
+      nSelections = l;
+    }
+
+    mask[i] = M;
+    if (selection[i])  delete[] selection[i];
+    selection[i] = NULL;
+    nSelItems[i] = 0;
+    selType  [i] = STYPE_UNDEFINED;
+
+    return i+1;
+
+  }
+
+  int  SelManager::GetSelType ( int selHnd )  {
+  int k;
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      k = selHnd-1;
+      if (mask[k])  return selType[k];
+    }
+    return STYPE_INVALID;
+  }
+
+  void  SelManager::DeleteSelection ( int selHnd )  {
+  int i,k;
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      k = selHnd-1;
+      if (mask[k])  {
+        for (i=0;i<nSelItems[k];i++)
+          if (selection[k][i])
+            selection[k][i]->RemoveMask ( mask[k] );
+
+        //      for (i=0;i<nAtoms;i++)
+        //        if (atom[i])
+        //          atom[i]->RemoveMask ( mask[k] );
+
+        delete mask[k];
+      }
+      mask[k] = NULL;
+      if (selection[k])  delete[] selection[k];
+      selection[k] = NULL;
+      nSelItems[k] = 0;
+      selType  [k] = STYPE_UNDEFINED;
+    }
+  }
+
+
+  PMask SelManager::GetSelMask ( int selHnd )  {
+    if ((selHnd>0) && (selHnd<=nSelections))
+         return mask[selHnd-1];
+    else return NULL;
+  }
+
+  void  SelManager::DeleteAllSelections()  {
+  PResidue res  ,res1;
+  PChain   chain,chain1;
+  PModel   model,model1;
+  int      i;
+
+    if (mask)  {
+      res   = NULL;
+      chain = NULL;
+      model = NULL;
+      if (atom)
+        for (i=0;i<nAtoms;i++)
+          if (atom[i])  {
+            atom[i]->ClearMask();
+            res1 = atom[i]->GetResidue();
+            if (res1!=res)  {
+              res = res1;
+              res->ClearMask();
+              chain1 = res->GetChain();
+              if (chain1!=chain)  {
+                chain = chain1;
+                chain->ClearMask();
+                model1 = chain->GetModel();
+                if (model1!=model)  {
+                  model = model1;
+                  model->ClearMask();
+                }
+              }
+            }
+          }
+      for (i=0;i<nSelections;i++)  {
+        if (mask     [i])  delete   mask[i];
+        if (selection[i])  delete[] selection[i];
+      }
+      delete[] mask;
+      if (selection) delete[] selection;
+      if (nSelItems) delete[] nSelItems;
+      if (selType)   delete[] selType;
+    }
+
+    nSelections = 0;
+    mask        = NULL;
+    selection   = NULL;
+    nSelItems   = NULL;
+    selType     = NULL;
+
+  }
+
+  void  SelManager::SelectAtoms ( int selHnd, int iSer1, int iSer2,
+                                  SELECTION_KEY sKey )  {
+  //   SelectAtoms(..) selects atoms in the serial number range
+  // of iSer1 to iSer2 by adding them to the set of atoms
+  // marked by the given mask. If iSer1=iSer2=0 then all atoms
+  // are selected. Each atom may be selected by a number of masks
+  // simultaneously
+  int           i,s1,s2,k,nsel;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+             selType[k] = STYPE_ATOM;
+    else if (selType[k]!=STYPE_ATOM)  return;
+
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nAtoms;i++)
+                        if (atom[i])  atom[i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;             break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      case SKEY_XAND: nsel = 0;             break;
+    }
+
+    if ((iSer1==0) && (iSer2==0))  {
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)
+            SelectAtom ( atom[i],k,sk,nsel );
+        }
+    } else  {
+      if (iSer1<=iSer2)  {
+        s1 = iSer1;
+        s2 = iSer2;
+      } else  {
+        s1 = iSer2;
+        s2 = iSer1;
+      }
+      // for a very general use, we allow the serial number
+      // to differ from the atom's index, although this is
+      // against PDB format. Therefore we apply here the most
+      // primitive and less efficient way of selection
+      for (i=0;i<nAtoms;i++)
+        if (atom[i])  {
+          if (!atom[i]->Ter)  {
+            if ((s1<=atom[i]->serNum) && (atom[i]->serNum<=s2))
+              SelectAtom ( atom[i],k,sk,nsel );
+            else if (sk==SKEY_AND)
+              atom[i]->RemoveMask ( mask[k] );
+          }
+        }
+    }
+
+    MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+  }
+
+
+  void  SelManager::SelectAtoms ( int selHnd, ivector asn, int nsn,
+                                  SELECTION_KEY selKey )  {
+  //   SelectAtoms(..) selects atoms with serial numbers given in
+  // vector asn[0..nsn-1].
+  QuickSort     QS;
+  ivector       asn1;
+  int           i,k,nsn1,j,j1,j2, sn,nsel;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
+
+    k  = selHnd-1;
+    sk = selKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) ||
+        (selKey==SKEY_NEW))           selType[k] = STYPE_ATOM;
+    else if (selType[k]!=STYPE_ATOM)  return;
+
+    switch (selKey)  {
+      case SKEY_NEW : for (i=0;i<nAtoms;i++)
+                        if (atom[i])  atom[i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;             break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      case SKEY_XAND: nsel = 0;             break;
+    }
+
+    GetVectorMemory ( asn1,nsn,0 );
+    for (i=0;i<nsn;i++)
+      asn1[i] = asn[i];
+
+    QS.Sort ( asn1,nsn );
+    nsn1 = nsn-1;
+
+    for (i=0;i<nAtoms;i++)
+      if (atom[i])  {
+        if (!atom[i]->Ter)  {
+          sn = atom[i]->serNum;
+          if ((asn1[0]<=sn) && (sn<=asn1[nsn1]))  {
+            // binary search
+            j1 = 0;
+            j2 = nsn1;
+            do  {
+              j = (j1+j2)/2;
+              if (sn<asn1[j])      j2 = j;
+              else if (sn>asn1[j]) j1 = j;
+                              else j1 = j2;
+            } while (j1<j2-1);
+            if ((sn==asn1[j]) || (sn==asn1[j1]) || (sn==asn1[j2]))
+              SelectAtom ( atom[i],k,sk,nsel );
+            else if (sk==SKEY_AND)
+              atom[i]->RemoveMask ( mask[k] );
+          } else if (sk==SKEY_AND)
+            atom[i]->RemoveMask ( mask[k] );
+        }
+      }
+
+    FreeVectorMemory ( asn1,0 );
+
+    MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+  }
+
+
+  void  SelManager::UnselectAtoms ( int selHnd, int iSer1, int iSer2 )  {
+  //   UnselectAtoms(..) clears the specified mask for atoms in
+  // the serial number range of iSer1 to iSer2. If iSer1=iSer2=0
+  // then all atoms are cleared of the specified mask. If selHnd
+  // is set to 0, then the atoms are cleared of any mask.
+  int i,s1,s2,k;
+
+    if ((selHnd<=nSelections) && (nAtoms>0))  {
+
+      k = selHnd-1;
+
+      if (selType[k]==STYPE_UNDEFINED)  selType[k] = STYPE_ATOM;
+      else if (selType[k]!=STYPE_ATOM)  return;
+
+      if ((iSer1==0) && (iSer2==0))  {
+        if (k<0) {
+          for (i=0;i<nAtoms;i++)
+            if (atom[i]) atom[i]->ClearMask();
+        } else  {
+          for (i=0;i<nAtoms;i++)
+            if (atom[i]) atom[i]->RemoveMask ( mask[k] );
+        }
+      } else  {
+        if (iSer1<=iSer2)  {
+          s1 = iSer1;
+          s2 = iSer2;
+        } else  {
+          s1 = iSer2;
+          s2 = iSer1;
+        }
+        // for a very general use, we allow the serial number
+        // to differ from the atom's index, although this is
+        // against PDB format. Therefore we apply here the most
+        // primitive and less efficient way of selection
+        if (k<0)  {
+          for (i=0;i<nAtoms;i++)
+            if (atom[i])  {
+              if ((s1<=atom[i]->serNum) && (atom[i]->serNum<=s2))
+                atom[i]->ClearMask();
+            }
+        } else  {
+          for (i=0;i<nAtoms;i++)
+            if (atom[i])  {
+              if ((s1<=atom[i]->serNum) && (atom[i]->serNum<=s2))
+                atom[i]->RemoveMask ( mask[k] );
+            }
+        }
+      }
+
+      MakeSelIndex ( selHnd,STYPE_ATOM,-1 );
+
+    }
+
+  }
+
+
+  pstr MakeList ( cpstr S )  {
+  // makes the list of selecting items:
+  //   1st character - special use,
+  //       then each item from S embraced by commas
+  pstr L;
+  int  i,j;
+    i = 0;
+    while (S[i]==' ')  i++;
+    if (S[i]!='*')  {
+      // compile a searchable list
+      L = new char[strlen(S)+5];
+      if (S[i]=='!')  {
+        L[0] = '!';
+        i++;
+      } else
+        L[0] = ' ';
+      if (strchr(S,'['))  L[1] = '"';
+                    else  L[1] = ' ';
+      L[2] = ',';
+      j    = 3;
+      while (S[i])  {
+        while (S[i]==' ')  i++;
+        if (S[i]=='[')  {
+          while (S[i] && (S[i]!=']'))
+            L[j++] = S[i++];
+          L[j++] = ']';
+          if (S[i]==']')  i++;
+        } else
+          while (S[i] && (S[i]!=' ') && (S[i]!=','))
+            L[j++] = S[i++];
+        while (S[i]==' ')  i++;
+        L[j++] = ',';
+        if (S[i]==',')  {
+          i++;
+          if (!S[i])  L[j++] = ',';  // blank chain ID at the end assumed
+        }
+      }
+      if (j==3)  L[j++] = ',';
+      L[j] = char(0);
+    } else
+      L = NULL;
+    return L;
+  }
+
+  bool MatchName ( pstr L, pstr N )  {
+  char M[sizeof(maxMMDBName)+5];
+  int  i,j;
+    if (L)  {
+      i    = 0;
+      M[0] = ',';
+      j    = 1;
+      while (N[i])
+        if (N[i]==' ')  i++;
+                  else  M[j++] = N[i++];
+      M[j++] = ',';
+      M[j]   = char(0);
+      if (strstr(&(L[2]),M))  return (L[0]!='!');
+      else if (L[1]!='"')     return (L[0]=='!');
+      else  {
+        strcpy ( M,",[" );
+        strcat ( M,N    );
+        strcat ( M,"]," );
+        if (strstr(&(L[2]),M))  return (L[0]!='!');
+                          else  return (L[0]=='!');
+      }
+    } else
+      return true;
+  }
+
+  bool MatchCharge ( pstr L, PAtom atom )  {
+  char N[100];
+    if (L)  {
+      if (atom->WhatIsSet & ASET_Charge)  {
+        sprintf ( N,"%+2i",mround(atom->charge) );
+        return MatchName ( L,N );
+      } else
+        return false;
+    } else
+      return true;
+  }
+
+
+  void SelManager::SelectAtom ( int selHnd, PAtom A,
+                                SELECTION_KEY selKey,
+                                bool makeIndex )  {
+  int           i, k, nsel;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    k  = selHnd-1;
+    sk = selKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) ||
+        (selKey==SKEY_NEW))           selType[k] = STYPE_ATOM;
+    else if (selType[k]!=STYPE_ATOM)  return;
+
+    switch (selKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      case SKEY_XAND: nsel = 0;             break;
+    }
+
+    SelectAtom ( A,k,sk,nsel);
+    if (makeIndex)  MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+  }
+
+
+  void SelManager::SelectResidue ( int selHnd, PResidue Res,
+                                   SELECTION_TYPE sType,
+                                   SELECTION_KEY  sKey,
+                                   bool makeIndex )  {
+  //  Selects residue Res or all its atoms depending on selType
+  PPAtom        A;
+  int           i, k, nsel, nat;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+       selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      case SKEY_XAND: nsel = 0;             break;
+    }
+
+    switch (sType)  {
+      case STYPE_ATOM    :  Res->GetAtomTable ( A,nat );
+                            for (i=0;i<nat;i++)
+                              if (A[i])  {
+                                if (!A[i]->Ter)
+                                  SelectAtom ( A[i],k,sk,nsel);
+                              }
+                          break ;
+      case STYPE_RESIDUE :  SelectObject ( Res,k,sk,nsel );
+                          break ;
+      default : ;
+    }
+
+    if (makeIndex)  MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectChain ( int selHnd, PChain Chain,
+                                 SELECTION_TYPE sType,
+                                 SELECTION_KEY  sKey,
+                                 bool makeIndex )  {
+  //  Selects chain Chain or all its residues or atoms depending on selType
+  PPAtom    A;
+  PPResidue Res;
+  int       i,j, k, nsel, nat,nres;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+       selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      case SKEY_XAND: nsel = 0;             break;
+    }
+
+    switch (sType)  {
+      case STYPE_ATOM    :  Chain->GetResidueTable ( Res,nres );
+                            for (i=0;i<nres;i++)
+                              if (Res[i])  {
+                                Res[i]->GetAtomTable ( A,nat );
+                                for (j=0;j<nat;j++)
+                                  if (A[j])  {
+                                    if (!A[j]->Ter)
+                                      SelectAtom ( A[j],k,sk,nsel);
+                                  }
+                              }
+                          break ;
+      case STYPE_RESIDUE :  Chain->GetResidueTable ( Res,nres );
+                            for (i=0;i<nres;i++)
+                              if (Res[i])
+                                SelectObject ( Res[i],k,sk,nsel );
+                          break ;
+      case STYPE_CHAIN   :  SelectObject ( Chain,k,sk,nsel );
+                          break ;
+      default : ;
+    }
+
+    if (makeIndex)  MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectModel ( int selHnd, PModel model,
+                                 SELECTION_TYPE sType,
+                                 SELECTION_KEY  sKey,
+                                 bool makeIndex )  {
+  //  Selects model or all its chains or residues or atoms depending
+  // on selType
+  PPAtom    A;
+  PPResidue Res;
+  PPChain   Chain;
+  int       i,j,n, k, nsel, nat,nres,nch;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+             selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      case SKEY_XAND: nsel = 0;             break;
+    }
+
+    switch (sType)  {
+      case STYPE_ATOM    :  model->GetChainTable ( Chain,nch );
+                            for (i=0;i<nch;i++)
+                              if (Chain[i])  {
+                                Chain[i]->GetResidueTable ( Res,nres );
+                                for (j=0;j<nres;j++)
+                                  if (Res[j])  {
+                                    Res[j]->GetAtomTable ( A,nat );
+                                    for (n=0;n<nat;n++)
+                                      if (A[n])  {
+                                        if (!A[n]->Ter)
+                                          SelectAtom ( A[n],k,sk,nsel);
+                                      }
+                                  }
+                              }
+                          break ;
+      case STYPE_RESIDUE :  model->GetChainTable ( Chain,nch );
+                            for (i=0;i<nch;i++)
+                              if (Chain[i])  {
+                                Chain[i]->GetResidueTable ( Res,nres );
+                                for (j=0;j<nres;j++)
+                                  if (Res[j])
+                                    SelectObject ( Res[j],k,sk,nsel );
+                              }
+                          break ;
+      case STYPE_CHAIN   :  model->GetChainTable ( Chain,nch );
+                            for (i=0;i<nch;i++)
+                              if (Chain[i])
+                                SelectObject ( Chain[i],k,sk,nsel );
+                          break ;
+      case STYPE_MODEL   :  SelectObject ( model,k,sk,nsel );
+                          break ;
+      default : ;
+    }
+
+    if (makeIndex)  MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  int SelManager::MakeSelIndex ( int selHnd )  {
+  int k;
+    if ((selHnd<=0) || (selHnd>nSelections))  return 0;
+    k = selHnd-1;
+    if (selType[k]==STYPE_UNDEFINED)  return 0;
+    MakeSelIndex ( selHnd,selType[k],-1 );
+    return nSelItems[k];
+  }
+
+  void SelManager::MakeAllSelIndexes()  {
+  int k;
+    for (k=0;k<nSelections;k++)
+      if (selType[k]!=STYPE_UNDEFINED)
+        MakeSelIndex ( k+1,selType[k],-1 );
+  }
+
+  void  SelManager::SelectAtoms (
+               int   selHnd,   // must be obtained from NewSelection()
+               int   iModel,   // model number; iModel=0 means
+                               // 'any models'
+               cpstr Chains,   // may be several chains "A,B,W";
+                               // "*" means 'any chain' (in model)
+               int   ResNo1,   // starting residue number
+               cpstr Ins1,     // starting residue insertion code;
+                               // "*" means 'any code'
+               int   ResNo2,   // ending residue number.
+                               // ResNo1=ResNo2=ANY_RES
+                               // means 'any residue number'
+                               // (in chain)
+               cpstr Ins2,     // ending residue insertion code
+                               // "*" means 'any code'
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means
+                               // 'any residue name'
+               cpstr ANames,   // may be several names "CA,CB";
+                               // "*" means 'any atom' (in residue)
+               cpstr Elements, // may be several element types like
+                               // "H,C,O,CU"; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means 'any
+                               // alternative location'
+               cpstr Segments, // may be several segment IDs like
+                               // "S1,S2,A234"; "*" means 'any
+                               // segment'
+               cpstr Charges,  // may be several charges like
+                               // "+1,-2,  "; "*" means 'any charge'
+               realtype occ1,  // lowest occupancy
+               realtype occ2,  // highest occupancy;
+                               // occ1=occ2<0.0 means
+                               // "any occupancy"
+               realtype x0,    // reference x-point
+               realtype y0,    // reference y-point
+               realtype z0,    // reference z-point
+               realtype d0,    // selection distance from the reference
+                               // reference point; d0<=0.0 means
+                               // 'any distance" and values of
+                               // x0, y0 and z0 are ignored
+               SELECTION_KEY selKey     // selection key
+                      )  {
+
+    Select ( selHnd,STYPE_ATOM,iModel,Chains,ResNo1,Ins1,ResNo2,Ins2,
+             RNames,ANames,Elements,altLocs,Segments,Charges,
+             occ1,occ2,x0,y0,z0,d0,selKey );
+
+  }
+
+
+  #define  hetIndicator '@'
+
+  void  SelManager::Select (
+               int   selHnd,   // must be obtained from NewSelection()
+               SELECTION_TYPE sType,  // selection type STYPE_XXXXX
+               int   iModel,   // model number; iModel=0 means
+                               // 'any models'
+               cpstr Chains,   // may be several chains "A,B,W";
+                               // "*" means 'any chain' (in model)
+               int   ResNo1,   // starting residue number
+               cpstr Ins1,     // starting residue insertion code;
+                               // "*" means 'any code'
+               int   ResNo2,   // ending residue number.
+                               // ResNo1=ResNo2=ANY_RES means 'any
+                               // residue number' (in chain)
+               cpstr Ins2,     // ending residue insertion code
+                               // "*" means 'any code'
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means 'any
+                               // residue name'
+               cpstr ANames,   // may be several names "CA,CB";"*"
+                               // means 'any atom' (in residue)
+               cpstr Elements, // may be several element types like
+                               // "H,C,O,CU"; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means 'any
+                               // alternative location'
+               cpstr Segments, // may be several segment IDs like
+                               // "S1,S2,A234"; "*" means 'any
+                               // segment'
+               cpstr Charges,  // may be several charges like
+                               // "+1,-2,  "; "*" means 'any charge'
+               realtype occ1,  // lowest occupancy
+               realtype occ2,  // highest occupancy;
+                               // occ1=occ2<0.0 means
+                               // "any occupancy"
+               realtype x0,    // reference x-point
+               realtype y0,    // reference y-point
+               realtype z0,    // reference z-point
+               realtype d0,    // selection distance from the reference
+                               // reference point; d0<=0.0 means
+                               // 'any distance" and values of
+                               // x0, y0 and z0 are ignored
+               SELECTION_KEY sKey     // selection key
+                      )  {
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  PAtom    atom;
+  pstr     chain_l;
+  pstr     res_l;
+  pstr     atom_l;
+  pstr     elem_l;
+  pstr     altLocs1;
+  pstr     aloc_l;
+  pstr     segm_l;
+  pstr     charge_l;
+  realtype dx,dy,dz,d02;
+  int      i,j,k,n,m1,m2,c, nsel;
+  bool     noRes,Occ,Dist,Sel,selAND;
+  bool     modelSel,chainSel,resSel;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
+
+    modelSel = false;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+             selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;             break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+    selAND   = (sKey==SKEY_AND);
+
+    altLocs1 = NULL;
+    if (altLocs)  {
+      if (strchr(altLocs,hetIndicator))  {
+        CreateCopy ( altLocs1,altLocs );
+        DelSpaces  ( altLocs1 );
+        aloc_l = strchr ( altLocs1,hetIndicator );
+        aloc_l[0] = ' ';
+        if (aloc_l[1])  aloc_l[1] = ' ';  // instead of comma
+        else if (aloc_l!=altLocs1)  {
+          aloc_l--;
+          aloc_l[0] = ' ';
+        }
+        DelSpaces  ( altLocs1 );
+        aloc_l = MakeList ( altLocs1 );
+      } else
+        aloc_l = MakeList ( altLocs );
+    } else
+      aloc_l = MakeList ( altLocs );
+
+    chain_l  = MakeList ( Chains   );
+    res_l    = MakeList ( RNames   );
+    atom_l   = MakeList ( ANames   );
+    elem_l   = MakeList ( Elements );
+    segm_l   = MakeList ( Segments );
+    charge_l = MakeList ( Charges  );
+
+    //  noRes==true means no residue restrictions
+    noRes = (ResNo1==ResNo2)   && (ResNo1==ANY_RES) &&
+            (Ins1[0]==Ins2[0]) && (Ins1[0]=='*');
+
+    Occ  = (occ1>=0.0) || (occ2>=0.0);
+    Dist = (d0>0.0);
+    d02  = d0*d0;
+
+    m1   = iModel-1;
+
+    if (m1>=0)
+      m2 = m1+1;     // will take only this model
+    else  {
+      m1 = 0;        // will take
+      m2 = nModels;  //   all models
+    }
+
+    if (m1>=nModels)  return;
+
+    for (n=0;n<nModels;n++)  {
+      mdl = model[n];
+      if (mdl)  {  // check for safety
+        if ((m1<=n) && (n<m2))  {
+          modelSel = false; // will be true on any selection in the model
+          for (c=0;c<mdl->nChains;c++)  {
+            chain = mdl->chain[c];
+            if (chain)  {   // again check for safety
+              if (MatchName(chain_l,chain->chainID))  {
+                // the chain has to be taken
+                i = 0;
+                if (!noRes)
+                  while (i<chain->nResidues)  {
+                    res = chain->residue[i];
+                    if (res)  {
+                      if ((res->seqNum==ResNo1) &&
+                          MatchName(res_l,res->name) &&
+                          ((Ins1[0]=='*') ||
+                           (!strcmp(res->insCode,Ins1))))
+                        break;
+                      else if (selAND)  {
+                        if (sType==STYPE_ATOM)
+                          res->UnmaskAtoms ( mask[k] );
+                        else if (sType==STYPE_RESIDUE)
+                          res->RemoveMask ( mask[k] );
+                      }
+                    }
+                    i++;
+                  }
+                while (i<chain->nResidues)  {
+                  res = chain->residue[i];
+                  if (res)  {
+                    resSel = false; // will be true on 1st sel-n in the res-e
+                    if (MatchName(res_l,res->name))  {
+                      for (j=0;j<res->nAtoms;j++)  {
+                        atom = res->atom[j];
+                        if (atom)  {
+                          if ((!atom->Ter)                      &&
+                              MatchName(atom_l  ,atom->name   ) &&
+                              MatchName(elem_l  ,atom->element) &&
+                              MatchName(aloc_l  ,atom->altLoc ) &&
+                              MatchName(segm_l  ,atom->segID  ) &&
+                              MatchCharge(charge_l,atom       ) &&
+                              ((!altLocs1) || atom->Het))  {
+                            Sel = true;
+                            if (Occ)
+                              Sel = ((occ1<=atom->occupancy) &&
+                                     (atom->occupancy<=occ2));
+                            if (Dist)  {
+                              dx  = atom->x - x0;
+                              dy  = atom->y - y0;
+                              dz  = atom->z - z0;
+                              Sel = Sel && ((dx*dx+dy*dy+dz*dz)<=d02);
+                            }
+                          } else
+                            Sel = false;
+                          if (Sel)  {
+                            SelectObject ( sType,atom,k,sk,nsel );
+                            resSel   = true;
+                            chainSel = true;
+                            modelSel = true;
+                          } else if (selAND && (sType==STYPE_ATOM))
+                            atom->RemoveMask ( mask[k] );
+                        }
+                        if (resSel && (sType!=STYPE_ATOM))  break;
+                      }
+                    } else if (selAND && (sType==STYPE_ATOM))
+                        res->UnmaskAtoms ( mask[k] );
+                    if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+                      res->RemoveMask ( mask[k] );
+                    if (chainSel && (sType>STYPE_RESIDUE))  break;
+                    if (!noRes)  {
+                      if ((res->seqNum==ResNo2) &&
+                          ((Ins2[0]=='*') || (!strcmp(res->insCode,Ins2)))
+                         )  break;
+                    }
+                  }
+                  i++;
+                }
+                if (selAND)  {
+                  if (sType==STYPE_ATOM)
+                    while (i<chain->nResidues)  {
+                      res = chain->residue[i];
+                      if (res)  res->UnmaskAtoms ( mask[k] );
+                      i++;
+                    }
+                  if (sType==STYPE_RESIDUE)
+                    while (i<chain->nResidues)  {
+                      res = chain->residue[i];
+                      if (res)  res->RemoveMask ( mask[k] );
+                      i++;
+                    }
+                }
+              } else if (selAND)
+                switch (sType)  {
+                  case STYPE_ATOM    : chain->UnmaskAtoms    ( mask[k] ); break;
+                  case STYPE_RESIDUE : chain->UnmaskResidues ( mask[k] ); break;
+                  case STYPE_CHAIN   : chain->RemoveMask     ( mask[k] ); break;
+                  default            : ;
+                }
+              if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+                chain->RemoveMask ( mask[k] );
+              if (modelSel && (sType>STYPE_CHAIN))  break;
+            }
+          }
+        } else if (selAND)
+          switch (sType)  {
+            case STYPE_ATOM    : mdl->UnmaskAtoms    ( mask[k] ); break;
+            case STYPE_RESIDUE : mdl->UnmaskResidues ( mask[k] ); break;
+            case STYPE_CHAIN   : mdl->UnmaskChains   ( mask[k] ); break;
+            default            : ;
+          }
+        if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+          mdl->RemoveMask ( mask[k] );
+      }
+    }
+
+    // release dynamic memory
+    if (chain_l)  delete[] chain_l;
+    if (res_l)    delete[] res_l;
+    if (atom_l)   delete[] atom_l;
+    if (elem_l)   delete[] elem_l;
+    if (altLocs1) delete[] altLocs1;
+    if (aloc_l)   delete[] aloc_l;
+    if (segm_l)   delete[] segm_l;
+    if (charge_l) delete[] charge_l;
+
+    MakeSelIndex ( selHnd,STYPE_ATOM,nsel );
+
+  }
+
+
+  void  SelManager::SelectAtoms (
+               int   selHnd,   // must be obtained from NewSelection()
+               int   iModel,   // model number; iModel=0 means
+                               // 'any models'
+               cpstr Chains,   // may be several chains "A,B,W";
+                               // "*" means 'any chain' (in model)
+               int   ResNo1,   // starting residue number
+               cpstr Ins1,     // starting residue insertion code;
+                               // "*" means 'any code'
+               int   ResNo2,   // ending residue number.
+                               // ResNo1=ResNo2=ANY_RES means 'any
+                               // residue number' (in chain)
+               cpstr Ins2,     // ending residue insertion code
+                               // "*" means 'any code'
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means 'any
+                               // residue name'
+               cpstr ANames,   // may be several names "CA,CB"; "*"
+                               // means 'any atom' (in residue)
+               cpstr Elements, // may be several element types like
+                               // "H,C,O,CU"; "*" means 'any
+                               // element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means 'any
+                               // alternative location'
+               SELECTION_KEY sKey    // selection key
+                      )  {
+    Select ( selHnd,STYPE_ATOM,iModel,Chains,ResNo1,Ins1,ResNo2,Ins2,
+             RNames,ANames,Elements,altLocs,sKey );
+  }
+
+
+  int  SelManager::Select (
+               int           selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               cpstr          CID,   // coordinate ID
+               SELECTION_KEY  sKey   // selection key
+                      )  {
+  InsCode insCode1,insCode2;
+  pstr    RNames;
+  pstr    ANames;
+  pstr    Elements;
+  pstr    altLocs;
+  pstr    Chains;
+  int     seqNum1 ,seqNum2;
+  int     iModel,l,RC;
+
+    l = IMax(10,strlen(CID))+1;
+    Chains   = new char[l];
+    RNames   = new char[l];
+    ANames   = new char[l];
+    Elements = new char[l];
+    altLocs  = new char[l];
+
+    if (strcmp(CID,"-all"))  {
+      RC = ParseSelectionPath ( CID,iModel,Chains,seqNum1,insCode1,
+                                seqNum2,insCode2,RNames,ANames,
+                                Elements,altLocs );
+    } else  {
+      iModel = 0;
+      strcpy ( Chains,"*" );
+      seqNum1 = ANY_RES;
+      seqNum2 = ANY_RES;
+      strcpy ( insCode1,"*" );
+      strcpy ( insCode2,"*" );
+      strcpy ( RNames  ,"*" );
+      strcpy ( ANames  ,"*" );
+      strcpy ( Elements,"*" );
+      strcpy ( altLocs ,""  ); // only main conformation by default
+      RC = 0;
+    }
+
+    if (!RC)  {
+      Select ( selHnd,sType,iModel,Chains,seqNum1,insCode1,
+               seqNum2,insCode2,RNames,ANames,Elements,altLocs,sKey );
+      RC = 0;
+    }
+
+    delete[] Chains;
+    delete[] RNames;
+    delete[] ANames;
+    delete[] Elements;
+    delete[] altLocs;
+
+    return RC;
+
+  }
+
+  void  SelManager::Select (
+               int   selHnd,   // must be obtained from NewSelection()
+               SELECTION_TYPE sType,  // selection type STYPE_XXXXX
+               int   iModel,   // model number; iModel=0 means
+                               // 'any model'
+               cpstr Chains,   // may be several chains "A,B,W";
+                               // "*" means 'any chain' (in model)
+               int   ResNo1,   // starting residue number
+               cpstr Ins1,     // starting residue insertion code;
+                               // "*" means 'any code'
+               int   ResNo2,   // ending residue number.
+                               // ResNo1=ResNo2=ANY_RES means 'any
+                               // residue number' (in chain)
+               cpstr Ins2,     // ending residue insertion code
+                               // "*" means 'any code'
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means 'any
+                               // residue name'
+               cpstr ANames,   // may be several names "CA,CB"; "*"
+                               // means 'any atom' (in residue)
+               cpstr Elements, // may be several element types like
+                               // "H,C,O,CU"; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means 'any
+                               // alternative location'
+               SELECTION_KEY sKey    // selection key
+                      )  {
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  PAtom    atom;
+  pstr     chain_l;
+  pstr     res_l;
+  pstr     atom_l;
+  pstr     elem_l;
+  pstr     altLocs1;
+  pstr     aloc_l;
+  int      i,j,k,n,m1,m2,c, nsel;
+  bool     noRes,modelSel,chainSel,resSel,selAND;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
+
+    modelSel = false;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+             selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;             break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+    selAND  = (sKey==SKEY_AND);
+
+    altLocs1 = NULL;
+    if (altLocs)  {
+      if (strchr(altLocs,hetIndicator))  {
+        CreateCopy ( altLocs1,altLocs );
+        DelSpaces  ( altLocs1 );
+        aloc_l = strchr ( altLocs1,hetIndicator );
+        aloc_l[0] = ' ';
+        if (aloc_l[1])  aloc_l[1] = ' ';  // instead of comma
+        else if (aloc_l!=altLocs1)  {
+          aloc_l--;
+          aloc_l[0] = ' ';
+        }
+        DelSpaces  ( altLocs1 );
+        aloc_l = MakeList ( altLocs1 );
+      } else
+        aloc_l = MakeList ( altLocs );
+    } else
+      aloc_l = MakeList ( altLocs );
+
+    chain_l = MakeList ( Chains   );
+    res_l   = MakeList ( RNames   );
+    atom_l  = MakeList ( ANames   );
+    elem_l  = MakeList ( Elements );
+
+    //  noRes==true means no residue restrictions
+    noRes   = (ResNo1==ResNo2) && (ResNo1==ANY_RES) &&
+              (Ins1[0]=='*')   && (Ins2[0]=='*');
+
+    m1      = iModel-1;
+    if (m1>=0)
+      m2 = m1+1;     // will take only this model
+    else  {
+      m1 = 0;        // will take
+      m2 = nModels;  //   all models
+    }
+
+    if (m1>=nModels)  return;
+
+    for (n=0;n<nModels;n++)  {
+      mdl = model[n];
+      if (mdl)  {  // check for safety
+        if ((m1<=n) && (n<m2))  {
+          modelSel = false; // will be true on any selection in the model
+          for (c=0;c<mdl->nChains;c++)  {
+            chain = mdl->chain[c];
+            if (chain)  {  // again check for safety
+              chainSel = false; // will be true on 1st sel-n in the chain
+              if (MatchName(chain_l,chain->chainID))  {
+                // the chain is to be taken
+                i = 0;
+                if (!noRes)  // skip "leading" residues
+                  while (i<chain->nResidues)  {
+                    res = chain->residue[i];
+                    if (res)  {
+                      if ((res->seqNum==ResNo1) &&
+                          MatchName(res_l,res->name) &&
+                          ((Ins1[0]=='*') ||
+                           (!strcmp(res->insCode,Ins1))))
+                        break;
+                      else if (selAND)  {
+                        if (sType==STYPE_ATOM)
+                          res->UnmaskAtoms ( mask[k] );
+                        else if (sType==STYPE_RESIDUE)
+                          res->RemoveMask ( mask[k] );
+                      }
+                    }
+                    i++;
+                  }
+                while (i<chain->nResidues)  {
+                  res = chain->residue[i];
+                  i++;
+                  if (res)  {
+                    resSel = false; // will be true on 1st selection
+                                    // in the residue
+                    if (MatchName(res_l,res->name))  {
+                      for (j=0;j<res->nAtoms;j++)  {
+                        atom = res->atom[j];
+                        if (atom)  {
+                          if ((!atom->Ter)                    &&
+                              MatchName(atom_l,atom->name   ) &&
+                              MatchName(elem_l,atom->element) &&
+                              MatchName(aloc_l,atom->altLoc ) &&
+                              ((!altLocs1) || atom->Het))  {
+                            SelectObject ( sType,atom,k,sk,nsel );
+                            resSel   = true;
+                            chainSel = true;
+                            modelSel = true;
+                          } else if (selAND && (sType==STYPE_ATOM))
+                            atom->RemoveMask ( mask[k] );
+                        }
+                        if (resSel && (sType!=STYPE_ATOM))  break;
+                      }
+                    } else if (selAND && (sType==STYPE_ATOM))
+                        res->UnmaskAtoms ( mask[k] );
+                    if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+                      res->RemoveMask ( mask[k] );
+                    if (chainSel && (sType>STYPE_RESIDUE))  break;
+                    if (!noRes)  {
+                      if ((res->seqNum==ResNo2) &&
+                          ((Ins2[0]=='*') || (!strcmp(res->insCode,Ins2)))
+                         ) break;
+                    }
+                  }
+                }
+                if (selAND)  {
+                  if (sType==STYPE_ATOM)
+                    while (i<chain->nResidues)  {
+                      res = chain->residue[i];
+                      if (res)  res->UnmaskAtoms ( mask[k] );
+                      i++;
+                    }
+                  if (sType==STYPE_RESIDUE)
+                    while (i<chain->nResidues)  {
+                      res = chain->residue[i];
+                      if (res)  res->RemoveMask ( mask[k] );
+                      i++;
+                    }
+                }
+              } else if (selAND)
+                switch (sType)  {
+                  case STYPE_ATOM    : chain->UnmaskAtoms    ( mask[k] ); break;
+                  case STYPE_RESIDUE : chain->UnmaskResidues ( mask[k] ); break;
+                  default            : ;
+                }
+              if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+                chain->RemoveMask ( mask[k] );
+              if (modelSel && (sType>STYPE_CHAIN))  break;
+            }
+          }
+        } else if (selAND)
+          switch (sType)  {
+            case STYPE_ATOM    : mdl->UnmaskAtoms    ( mask[k] ); break;
+            case STYPE_RESIDUE : mdl->UnmaskResidues ( mask[k] ); break;
+            case STYPE_CHAIN   : mdl->UnmaskChains   ( mask[k] ); break;
+            default            : ;
+          }
+        if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+          mdl->RemoveMask ( mask[k] );
+      }
+    }
+
+    // release dynamic memory
+    if (chain_l)  delete[] chain_l;
+    if (res_l)    delete[] res_l;
+    if (atom_l)   delete[] atom_l;
+    if (elem_l)   delete[] elem_l;
+    if (altLocs1) delete[] altLocs1;
+    if (aloc_l)   delete[] aloc_l;
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::Select (
+               int          selHnd1, // destination, must be obtained
+                                     //   from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               int          selHnd2, // source, must be obtained from
+                                     // NewSelection() and have been
+                                     //   used for selection
+               SELECTION_KEY sKey    // selection key
+                               )  {
+  //  SKEY_XOR works only downward the hierarchy!
+  PAtom    atom;
+  PResidue res;
+  PChain   chain;
+  PModel   model;
+  int      k1,k2,i,j,l,n,nsel;
+  SELECTION_KEY sk;
+
+    if ((selHnd1<=0) || (selHnd1>nSelections) ||
+        (selHnd2<=0) || (selHnd2>nSelections) || (nAtoms<=0))  return;
+
+    k1 = selHnd1-1;
+    k2 = selHnd2-1;
+    sk = sKey;
+
+    if ((selType[k1]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+             selType[k1] = sType;
+    else if (selType[k1]!=sType)  return;
+
+    if (selType[k2]==STYPE_UNDEFINED)  return;
+
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k1];i++)
+                        if (selection[k1][i])
+                            selection[k1][i]->RemoveMask ( mask[k1] );
+                      nSelItems[k1] = 0;
+                      sk   = SKEY_OR;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k1]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k1];
+                    break;
+      case SKEY_AND : if (nSelItems[k1]==0)  return;
+                      sk   = SKEY_XAND;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k1];  break;
+      case SKEY_CLR : nsel = nSelItems[k1];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+
+    switch (selType[k2])  {
+
+      case STYPE_ATOM    :
+          for (i=0;i<nSelItems[k2];i++)  {
+            atom = (PAtom)selection[k2][i];
+            if (atom)  {
+              if (!atom->Ter)
+                SelectObject ( sType,atom,k1,sk,nsel );
+            }
+          }
+        break;
+
+      case STYPE_RESIDUE :
+          for (i=0;i<nSelItems[k2];i++)  {
+            res = (PResidue)selection[k2][i];
+            if (res)
+              switch (sType)  {
+                case STYPE_ATOM  : for (j=0;j<res->nAtoms;j++)  {
+                                     atom = res->atom[j];
+                                     if (atom)  {
+                                       if (!atom->Ter)
+                                         SelectObject (atom,k1,sk,nsel);
+                                     }
+                                   }
+                                 break;
+                case STYPE_RESIDUE : //if (res->chain)
+                                     SelectObject ( res,k1,sk,nsel );
+                                 break;
+                case STYPE_CHAIN : if (res->chain)
+                                     SelectObject ( res->chain,k1,
+                                                    sk,nsel );
+                                 break;
+                case STYPE_MODEL : if (res->chain)  {
+                                     if (res->chain->model)
+                                       SelectObject ( res->chain->model,
+                                                      k1,sk,nsel );
+                                   }
+                default          : ;
+              }
+          }
+        break;
+
+      case STYPE_CHAIN   :
+          for (i=0;i<nSelItems[k2];i++)  {
+            chain = (PChain)selection[k2][i];
+            if (chain)
+              switch (sType)  {
+                case STYPE_ATOM    : for (j=0;j<chain->nResidues;j++)  {
+                                       res = chain->residue[j];
+                                       if (res)
+                                         for (l=0;l<res->nAtoms;l++)  {
+                                           atom = res->atom[l];
+                                           if (atom)  {
+                                             if (!atom->Ter)
+                                               SelectObject ( atom,k1,
+                                                               sk,nsel );
+                                           }
+                                         }
+                                     }
+                                 break;
+                case STYPE_RESIDUE : for (j=0;j<chain->nResidues;j++)  {
+                                       res = chain->residue[j];
+                                       if (res)
+                                         SelectObject ( res,k1,sk,nsel );
+                                     }
+                                 break;
+                case STYPE_CHAIN   : //if (chain->model)
+                                       SelectObject ( chain,k1,sk,nsel );
+                                 break;
+                case STYPE_MODEL   : if (chain->model)
+                                       SelectObject ( chain->model,k1,
+                                                      sk,nsel );
+                default            : ;
+              }
+          }
+        break;
+
+      case STYPE_MODEL   :
+          for (i=0;i<nSelItems[k2];i++)  {
+            model = (PModel)selection[k2][i];
+            if (model)
+              switch (sType)  {
+                case STYPE_ATOM    :
+                          for (j=0;j<model->nChains;j++)  {
+                            chain = model->chain[j];
+                            if (chain)
+                              for (l=0;l<chain->nResidues;l++) {
+                                res = chain->residue[l];
+                                if (res)
+                                  for (n=0;n<res->nAtoms;n++)  {
+                                    atom = res->atom[n];
+                                    if (atom)  {
+                                      if (!atom->Ter)
+                                        SelectObject ( atom,k1,sk,nsel );
+                                    }
+                                  }
+                              }
+                          }
+                        break;
+                case STYPE_RESIDUE :
+                          for (j=0;j<model->nChains;j++)  {
+                            chain = model->chain[j];
+                            if (chain)
+                              for (l=0;l<chain->nResidues;l++)  {
+                                res = chain->residue[j];
+                                if (res)
+                                  SelectObject ( res,k1,sk,nsel );
+                              }
+                          }
+                        break;
+                case STYPE_CHAIN   : for (j=0;j<model->nChains;j++)  {
+                                       chain = model->chain[j];
+                                       if (chain)
+                                         SelectObject (chain,k1,sk,nsel);
+                                     }
+                                 break;
+                case STYPE_MODEL   : SelectObject ( model,k1,sk,nsel );
+                default            : ;
+              }
+          }
+        break;
+
+      default : ;
+
+    }
+
+    if (sKey==SKEY_AND)
+      for (i=0;i<nSelItems[k1];i++)
+        if (selection[k1][i])
+          selection[k1][i]->XadMask ( mask[k1] );
+
+    MakeSelIndex ( selHnd1,sType,nsel );
+
+  }
+
+  void  SelManager::SelectProperty (
+                    int  selHnd, // must be obtained from NewSelection()
+                    SELECTION_PROPERTY propKey, // property key
+                    SELECTION_TYPE     sType, // selection type STYPE_XXXXX
+                    SELECTION_KEY      sKey  // selection key
+                  )  {
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  int      i,k,selHnd1,nsel, m,c,r;
+  bool     doSelect;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (nAtoms<=0))  return;
+
+    k  = selHnd-1;
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    if (sType!=STYPE_RESIDUE)  {
+      selHnd1 = NewSelection();
+      if ((sKey==SKEY_AND) || (sKey==SKEY_CLR))
+        Select ( selHnd1,STYPE_RESIDUE,selHnd,SKEY_NEW );
+    } else
+      selHnd1 = selHnd;
+
+    k          = selHnd1-1;
+    selType[k] = STYPE_RESIDUE;
+    sk         = sKey;
+
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      sk   = SKEY_OR;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      sk   = SKEY_XAND;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+    if ((sKey==SKEY_AND) || (sKey==SKEY_CLR))  {
+
+      for (i=0;i<nSelItems[k];i++)  {
+        res = (PResidue)selection[k][i];
+        if (res)  {
+          switch (propKey)  {
+            case SELPROP_Solvent    : doSelect = res->isSolvent();
+                                    break;
+            case SELPROP_Aminoacid  : doSelect = res->isAminoacid();
+                                    break;
+            case SELPROP_Nucleotide : doSelect = res->isNucleotide();
+                                    break;
+            case SELPROP_Sugar      : doSelect = res->isSugar();
+                                    break;
+            case SELPROP_ModRes     : doSelect = res->isModRes();
+                                    break;
+            default : doSelect = false;
+          }
+          if (doSelect)  SelectObject ( res,k,sk,nsel );
+        }
+      }
+
+      if (sKey==SKEY_AND)
+        for (i=0;i<nSelItems[k];i++)
+          if (selection[k][i])
+            selection[k][i]->XadMask ( mask[k] );
+
+    } else  {
+
+      for (m=0;m<nModels;m++)  {
+        mdl = model[m];
+        if (mdl)  {
+          for (c=0;c<mdl->nChains;c++)  {
+            chain = mdl->chain[c];
+            if (chain)  {
+              for (r=0;r<chain->nResidues;r++)  {
+                res = chain->residue[r];
+                if (res)  {
+                  switch (propKey)  {
+                    case SELPROP_Solvent    : doSelect = res->isSolvent();
+                                           break;
+                    case SELPROP_Aminoacid  : doSelect = res->isAminoacid();
+                                           break;
+                    case SELPROP_Nucleotide : doSelect = res->isNucleotide();
+                                           break;
+                    case SELPROP_Sugar      : doSelect = res->isSugar();
+                                           break;
+                    case SELPROP_ModRes     : doSelect = res->isModRes();
+                                           break;
+                    default : doSelect = false;
+                  }
+                  if (doSelect)  SelectObject ( res,k,sk,nsel );
+                }
+              }
+            }
+          }
+        }
+      }
+
+    }
+
+
+    MakeSelIndex ( selHnd1,STYPE_RESIDUE,nsel );
+
+    if (sType!=STYPE_RESIDUE)  {
+      Select ( selHnd,sType,selHnd1,SKEY_NEW );
+      DeleteSelection ( selHnd1 );
+    }
+
+  }
+
+
+  void SelManager::SelectUDD (
+               int    selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               int UDDhandle, // UDD handle
+               int    selMin, // lower selection boundary
+               int    selMax, // upper selection boundary
+               SELECTION_KEY sKey  // selection key
+             )  {
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  PAtom    atom;
+  int      i,k,nsel,iudd, n,c,r,a;
+  bool     selAND;
+  SELECTION_KEY sk;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    switch (sType)  {
+      case STYPE_ATOM    : if ((UDDhandle & UDRF_ATOM)==0)    return;
+                        break;
+      case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
+                        break;
+      case STYPE_CHAIN   : if ((UDDhandle & UDRF_CHAIN)==0)   return;
+                        break;
+      case STYPE_MODEL   : if ((UDDhandle & UDRF_MODEL)==0)   return;
+                        break;
+      default            : return;
+    }
+
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+    selAND = (sKey==SKEY_AND);
+
+
+    for (n=0;n<nModels;n++)  {
+
+      mdl = model[n];
+      if (mdl)  {  // check for safety
+
+        if (sType==STYPE_MODEL)  {
+
+          mdl->getUDData ( UDDhandle,iudd );
+          if ((selMin<=iudd) && (iudd<=selMax))
+            SelectObject ( mdl,k,sk,nsel );
+          else if (selAND)
+            mdl->RemoveMask ( mask[k] );
+
+        } else  {
+
+          for (c=0;c<mdl->nChains;c++)  {
+
+            chain = mdl->chain[c];
+            if (chain)  {   // again check for safety
+
+              if (sType==STYPE_CHAIN)  {
+                chain->getUDData ( UDDhandle,iudd );
+                if ((selMin<=iudd) && (iudd<=selMax))
+                  SelectObject ( chain,k,sk,nsel );
+                else if (selAND)
+                  chain->RemoveMask ( mask[k] );
+
+              } else  {
+
+                for (r=0;r<chain->nResidues;r++)  {
+
+                  res = chain->residue[r];
+                  if (res)  {
+
+                    if (sType==STYPE_RESIDUE)  {
+                      res->getUDData ( UDDhandle,iudd );
+                      if ((selMin<=iudd) && (iudd<=selMax))
+                        SelectObject ( res,k,sk,nsel );
+                      else if (selAND)
+                        res->RemoveMask ( mask[k] );
+
+                    } else  {
+
+                      for (a=0;a<res->nAtoms;a++)  {
+                        atom = res->atom[a];
+                        if (atom)  {
+                          if (!atom->Ter)  {
+                            atom->getUDData ( UDDhandle,iudd );
+                            if ((selMin<=iudd) && (iudd<=selMax))
+                              SelectObject ( atom,k,sk,nsel );
+                            else if (selAND)
+                              atom->RemoveMask ( mask[k] );
+                          }
+                        }
+
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectUDD (
+               int      selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               int   UDDhandle, // UDD handle
+               realtype selMin, // lower selection boundary
+               realtype selMax, // upper selection boundary
+               SELECTION_KEY sKey  // selection key
+             )  {
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  PAtom    atom;
+  realtype rudd;
+  int      i,k,nsel, n,c,r,a;
+  bool     selAND;
+  SELECTION_KEY sk;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    switch (sType)  {
+      case STYPE_ATOM    : if ((UDDhandle & UDRF_ATOM)==0)    return;
+                        break;
+      case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
+                        break;
+      case STYPE_CHAIN   : if ((UDDhandle & UDRF_CHAIN)==0)   return;
+                        break;
+      case STYPE_MODEL   : if ((UDDhandle & UDRF_MODEL)==0)   return;
+                        break;
+      default            : return;
+    }
+
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+    selAND = (sKey==SKEY_AND);
+
+
+    for (n=0;n<nModels;n++)  {
+
+      mdl = model[n];
+      if (mdl)  {  // check for safety
+
+        if (sType==STYPE_MODEL)  {
+
+          mdl->getUDData ( UDDhandle,rudd );
+          if ((selMin<=rudd) && (rudd<=selMax))
+            SelectObject ( mdl,k,sk,nsel );
+          else if (selAND)
+            mdl->RemoveMask ( mask[k] );
+
+        } else  {
+
+          for (c=0;c<mdl->nChains;c++)  {
+
+            chain = mdl->chain[c];
+            if (chain)  {   // again check for safety
+
+              if (sType==STYPE_CHAIN)  {
+                chain->getUDData ( UDDhandle,rudd );
+                if ((selMin<=rudd) && (rudd<=selMax))
+                  SelectObject ( chain,k,sk,nsel );
+                else if (selAND)
+                  chain->RemoveMask ( mask[k] );
+
+              } else  {
+
+                for (r=0;r<chain->nResidues;r++)  {
+
+                  res = chain->residue[r];
+                  if (res)  {
+
+                    if (sType==STYPE_RESIDUE)  {
+                      res->getUDData ( UDDhandle,rudd );
+                      if ((selMin<=rudd) && (rudd<=selMax))
+                        SelectObject ( res,k,sk,nsel );
+                      else if (selAND)
+                        res->RemoveMask ( mask[k] );
+
+                    } else  {
+
+                      for (a=0;a<res->nAtoms;a++)  {
+                        atom = res->atom[a];
+                        if (atom)  {
+                          if (!atom->Ter)  {
+                            atom->getUDData ( UDDhandle,rudd );
+                            if ((selMin<=rudd) && (rudd<=selMax))
+                              SelectObject ( atom,k,sk,nsel );
+                            else if (selAND)
+                              atom->RemoveMask ( mask[k] );
+                          }
+                        }
+
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  bool selSUDD ( cpstr sudd, cpstr selStr, int cmpRule, int ssLen )  {
+    if (!sudd)  return false;
+    switch (cmpRule)  {
+      case UDSCR_LT        : return (strcmp(sudd,selStr)<0);
+      case UDSCR_LE        : return (strcmp(sudd,selStr)<=0);
+      case UDSCR_EQ        : return (strcmp(sudd,selStr)==0);
+      case UDSCR_NE        : return (strcmp(sudd,selStr)!=0);
+      case UDSCR_GE        : return (strcmp(sudd,selStr)>=0);
+      case UDSCR_GT        : return (strcmp(sudd,selStr)>=0);
+      case UDSCR_LTcase    : return (strcasecmp(sudd,selStr)<0);
+      case UDSCR_LEcase    : return (strcasecmp(sudd,selStr)<=0);
+      case UDSCR_EQcase    : return (strcasecmp(sudd,selStr)==0);
+      case UDSCR_NEcase    : return (strcasecmp(sudd,selStr)!=0);
+      case UDSCR_GEcase    : return (strcasecmp(sudd,selStr)>=0);
+      case UDSCR_GTcase    : return (strcasecmp(sudd,selStr)>=0);
+      case UDSCR_LTn       : return (strncmp(sudd,selStr,ssLen)<0);
+      case UDSCR_LEn       : return (strncmp(sudd,selStr,ssLen)<=0);
+      case UDSCR_EQn       : return (strncmp(sudd,selStr,ssLen)==0);
+      case UDSCR_NEn       : return (strncmp(sudd,selStr,ssLen)!=0);
+      case UDSCR_GEn       : return (strncmp(sudd,selStr,ssLen)>=0);
+      case UDSCR_GTn       : return (strncmp(sudd,selStr,ssLen)>=0);
+      case UDSCR_LTncase   : return (strncasecmp(sudd,selStr,ssLen)<0);
+      case UDSCR_LEncase   : return (strncasecmp(sudd,selStr,ssLen)<=0);
+      case UDSCR_EQncase   : return (strncasecmp(sudd,selStr,ssLen)==0);
+      case UDSCR_NEncase   : return (strncasecmp(sudd,selStr,ssLen)!=0);
+      case UDSCR_GEncase   : return (strncasecmp(sudd,selStr,ssLen)>=0);
+      case UDSCR_GTncase   : return (strncasecmp(sudd,selStr,ssLen)>=0);
+      case UDSCR_Substr    : return (strstr(sudd,selStr)!=NULL);
+      case UDSCR_NoSubstr  : return (strstr(sudd,selStr)==NULL);
+      case UDSCR_Substr1   : return (strstr(selStr,sudd)!=NULL);
+      case UDSCR_NoSubstr1 : return (strstr(selStr,sudd)==NULL);
+      default              : return false;
+    }
+  }
+
+
+  void SelManager::SelectUDD (
+               int   selHnd,    // must be obtained from NewSelection()
+               SELECTION_TYPE sType,   // selection type STYPE_XXXXX
+               int   UDDhandle, // UDD handle
+               cpstr selStr,    // selection string
+               int   cmpRule,   // comparison rule
+               SELECTION_KEY sKey     // selection key
+             )  {
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  PAtom    atom;
+  int      i,k,nsel,ssLen, n,c,r,a;
+  bool     selAND;
+  SELECTION_KEY sk;
+
+    k  = selHnd-1;
+    sk = sKey;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return;
+
+    switch (sType)  {
+      case STYPE_ATOM    : if ((UDDhandle & UDRF_ATOM)==0)    return;
+                        break;
+      case STYPE_RESIDUE : if ((UDDhandle & UDRF_RESIDUE)==0) return;
+                        break;
+      case STYPE_CHAIN   : if ((UDDhandle & UDRF_CHAIN)==0)   return;
+                        break;
+      case STYPE_MODEL   : if ((UDDhandle & UDRF_MODEL)==0)   return;
+                        break;
+      default            : return;
+    }
+
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : if (nSelItems[k]==0)  return;
+                      nsel = 0;
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];  break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      if (nsel<=0)  return;
+                    break;
+      default       : return;
+    }
+
+    selAND = (sKey==SKEY_AND);
+    ssLen = strlen ( selStr );
+
+    for (n=0;n<nModels;n++)  {
+
+      mdl = model[n];
+      if (mdl)  {  // check for safety
+
+        if (sType==STYPE_MODEL)  {
+
+          if (selSUDD(mdl->getUDData(UDDhandle),selStr,
+                                            cmpRule,ssLen))
+            SelectObject ( mdl,k,sk,nsel );
+          else if (selAND)
+            mdl->RemoveMask ( mask[k] );
+
+        } else  {
+
+          for (c=0;c<mdl->nChains;c++)  {
+
+            chain = mdl->chain[c];
+            if (chain)  {   // again check for safety
+
+              if (sType==STYPE_CHAIN)  {
+                if (selSUDD(chain->getUDData(UDDhandle),selStr,
+                                                  cmpRule,ssLen))
+                  SelectObject ( chain,k,sk,nsel );
+                else if (selAND)
+                  chain->RemoveMask ( mask[k] );
+
+              } else  {
+
+                for (r=0;r<chain->nResidues;r++)  {
+
+                  res = chain->residue[r];
+                  if (res)  {
+
+                    if (sType==STYPE_RESIDUE)  {
+                      if (selSUDD(res->getUDData(UDDhandle),selStr,
+                                                      cmpRule,ssLen))
+                        SelectObject ( res,k,sk,nsel );
+                      else if (selAND)
+                        res->RemoveMask ( mask[k] );
+
+                    } else  {
+
+                      for (a=0;a<res->nAtoms;a++)  {
+                        atom = res->atom[a];
+                        if (atom)  {
+                          if (!atom->Ter)  {
+                            if (selSUDD(atom->getUDData(UDDhandle),selStr,
+                                                             cmpRule,ssLen))
+                              SelectObject ( atom,k,sk,nsel );
+                            else if (selAND)
+                              atom->RemoveMask ( mask[k] );
+                          }
+                        }
+
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectSphere (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               realtype  x, // x-coordinate of the sphere's center
+               realtype  y, // y-coordinate of the sphere's center
+               realtype  z, // z-coordinate of the sphere's center
+               realtype  r, // radius of the sphere
+               SELECTION_KEY sKey  // selection key
+             )  {
+  //  Selecting a sphere
+  PPAtom    A;
+  PAtom     atm;
+  PResidue  res;
+  PChain    chain;
+  PModel    mdl;
+  realtype  dx,dy,dz, r2;
+  int       i,k, nat,nsel, im,ic,ir;
+  bool      ASel, resSel,chainSel,modelSel,selAND;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0))  return;
+
+    k   = selHnd-1;
+    sk  = sKey;
+    A   = atom;
+    nat = nAtoms;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      default       : return;
+    }
+
+    selAND = (sKey==SKEY_AND);
+
+    if ((nat<=0) || (!A))  return;
+
+    r2 = r*r;
+
+    if (sType==STYPE_ATOM)  {
+
+      for (i=0;i<nat;i++)
+        if (A[i])  {
+          ASel = (sk!=SKEY_AND);
+          if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+            dx = fabs(A[i]->x-x);
+            if (dx<=r)  {
+              dy = fabs(A[i]->y-y);
+              if (dy<=r)  {
+                dz = fabs(A[i]->z-z);
+                if (dz<=r)  {
+                  if (dx*dx+dy*dy+dz*dz<=r2)  {
+                    ASel = true;
+                    SelectAtom ( A[i],k,sk,nsel );
+                  }
+                }
+              }
+            }
+          }
+          if (!ASel)  A[i]->RemoveMask ( mask[k] );
+        }
+
+    } else  {
+
+      for (im=0;im<nModels;im++)  {
+        mdl = model[im];
+        if (mdl)  {
+          modelSel = false;
+          for (ic=0;ic<mdl->nChains;ic++)  {
+            chain = mdl->chain[ic];
+            if (chain)  {
+              chainSel = false;
+              for (ir=0;ir<chain->nResidues;ir++)  {
+                res = chain->residue[ir];
+                if (res)  {
+                  resSel = false;
+                  for (i=0;i<res->nAtoms;i++)  {
+                    atm = res->atom[i];
+                    if (atm) {
+                      ASel = false;
+                      if ((!atm->Ter) &&
+                          (atm->WhatIsSet & ASET_Coordinates))  {
+                        dx = fabs(atm->x-x);
+                        if (dx<=r)  {
+                          dy = fabs(atm->y-y);
+                          if (dy<=r)  {
+                            dz = fabs(atm->z-z);
+                            if (dz<=r)  {
+                              if (dx*dx+dy*dy+dz*dz<=r2)  {
+                                SelectObject ( sType,atm,k,sk,nsel );
+                                ASel     = true;
+                                resSel   = true;
+                                chainSel = true;
+                                modelSel = true;
+                              }
+                            }
+                          }
+                        }
+                      }
+                      if (ASel)  break;  // selType>=STYPE_RESIDUE
+                    }
+                  }
+                  if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+                    res->RemoveMask ( mask[k] );
+                  if (chainSel && (sType>STYPE_RESIDUE))  break;
+                }
+              }
+              if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+                chain->RemoveMask ( mask[k] );
+              if (modelSel && (sType>STYPE_CHAIN))  break;
+            }
+          }
+          if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+            mdl->RemoveMask ( mask[k] );
+        }
+      }
+
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectCylinder (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               realtype x1, // x-coordinate of the cylinder axis' 1st end
+               realtype y1, // y-coordinate of the cylinder axis' 1st end
+               realtype z1, // z-coordinate of the cylinder axis' 1st end
+               realtype x2, // x-coordinate of the cylinder axis' 2nd end
+               realtype y2, // y-coordinate of the cylinder axis' 2nd end
+               realtype z2, // z-coordinate of the cylinder axis' 2nd end
+               realtype  r, // radius of the cylinder
+               SELECTION_KEY sKey  // selection key
+             )  {
+  //
+  //  Selecting a cylinder
+  //
+  //  Method : given a line running through (x1,y1,z1) to (x2,y2,z2) on,
+  //  a point (x,y,z) is then projected on it at distance
+  //
+  //              c1 = (c^2-a^2+b^2)/(2c),
+  //
+  //  from (x1,y1,z1), where
+  //      'a' is the distance between (x,y,z) and (x2,y2,z2)
+  //      'b' is the distance between (x,y,z) and (x1,y1,z1)
+  //      'c' is the distance between (x1,y1,z1) and (x2,y2,z2).
+  //  The distance between point (x,y,z) and line is determined as
+  //
+  //              h^2 = b^2 - c1^2
+  //
+  //  If c1>=0 and c1<=c and h^2<=r^2  then point (x,y,z) is inside
+  //  a cylinder of radius 'r' with axis running from point
+  //  (x1,y1,z1) to (x2,y2,z2).
+  //
+  PPAtom   A;
+  PAtom    atm;
+  PResidue res;
+  PChain   chain;
+  PModel   mdl;
+  realtype dx,dy,dz, c,dc,c1,c2, a2,b2, r2;
+  int      i,k, nat,nsel, im,ic,ir;
+  bool     resSel,chainSel,modelSel,selAND;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0))  return;
+
+    dx = x1-x2;
+    dy = y1-y2;
+    dz = z1-z2;
+    c2 = dx*dx + dy*dy + dz*dz;
+    if (c2<=0.0)  return;
+    c  = sqrt(c2);
+    dc = 2.0*c;
+    r2 = r*r;
+
+    k   = selHnd-1;
+    sk  = sKey;
+    A   = atom;
+    nat = nAtoms;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      default       : return;
+    }
+
+    selAND = (sKey==SKEY_AND);
+
+    if ((nat<=0) || (!A))  return;
+
+    if (sType==STYPE_ATOM)  {
+
+      for (i=0;i<nat;i++)
+        if (A[i])  {
+          if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+            dx = fabs(A[i]->x-x1);
+            dy = fabs(A[i]->y-y1);
+            dz = fabs(A[i]->z-z1);
+            a2 = dx*dx + dy*dy + dz*dz;
+            dx = fabs(A[i]->x-x2);
+            dy = fabs(A[i]->y-y2);
+            dz = fabs(A[i]->z-z2);
+            b2 = dx*dx + dy*dy + dz*dz;
+            c1 = (c2-a2+b2)/dc;
+            if ((0.0<=c1) && (c1<=c) && (b2-c1*c1<=r2))
+              SelectAtom ( A[i],k,sk,nsel );
+            else if (sk==SKEY_AND)
+              A[i]->RemoveMask ( mask[k] );
+          }
+        }
+
+    } else  {
+
+      for (im=0;im<nModels;im++)  {
+        mdl = model[im];
+        if (mdl)  {
+          modelSel = false;
+          for (ic=0;ic<mdl->nChains;ic++)  {
+            chain = mdl->chain[ic];
+            if (chain)  {
+              chainSel = false;
+              for (ir=0;ir<chain->nResidues;ir++)  {
+                res = chain->residue[ir];
+                if (res)  {
+                  resSel = false;
+                  for (i=0;i<res->nAtoms;i++)  {
+                    atm = res->atom[i];
+                    if (atm) {
+                      if ((!atm->Ter) &&
+                          (atm->WhatIsSet & ASET_Coordinates))  {
+                        dx = fabs(atm->x-x1);
+                        dy = fabs(atm->y-y1);
+                        dz = fabs(atm->z-z1);
+                        a2 = dx*dx + dy*dy + dz*dz;
+                        dx = fabs(atm->x-x2);
+                        dy = fabs(atm->y-y2);
+                        dz = fabs(atm->z-z2);
+                        b2 = dx*dx + dy*dy + dz*dz;
+                        c1 = (c2-a2+b2)/dc;
+                        if ((0.0<=c1) && (c1<=c) && (b2-c1*c1<=r2))  {
+                          SelectObject ( sType,atm,k,sk,nsel );
+                          resSel   = true;
+                          chainSel = true;
+                          modelSel = true;
+                          break;  // selType>=STYPE_RESIDUE
+                        }
+                      }
+                    }
+                  }
+                  if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+                    res->RemoveMask ( mask[k] );
+                  if (chainSel && (sType>STYPE_RESIDUE))  break;
+                }
+              }
+              if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+                chain->RemoveMask ( mask[k] );
+              if (modelSel && (sType>STYPE_CHAIN))  break;
+            }
+          }
+          if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+            mdl->RemoveMask ( mask[k] );
+        }
+      }
+
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectSlab (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               realtype  a, // a-parameter of the plane  ax+by+cz=d
+               realtype  b, // b-parameter of the plane  ax+by+cz=d
+               realtype  c, // c-parameter of the plane  ax+by+cz=d
+               realtype  d, // d-parameter of the plane  ax+by+cz=d
+               realtype  r, // distance to the plane
+               SELECTION_KEY sKey  // selection key
+             )  {
+  //
+  //  Selecting all atoms on a given distance from a plane
+  //
+  //  Method : the distance between a point (x0,y0,z0) and a plane
+  //  defined by equation
+  //
+  //              a*x + b*y + c*z = d
+  //
+  //  is found as
+  //
+  //              h = (d-a*x0-b*y0-c*z0)/sqrt(a^2+b^2+c^2)
+  //
+  //  If |h|<d then point (x0,y0,z0) belongs to the slab.
+  //
+  PPAtom   A;
+  PAtom    atm;
+  PResidue res;
+  PChain   chain;
+  PModel   mdl;
+  realtype v,h;
+  int      i,k, nat,nsel, im,ic,ir;
+  bool     resSel,chainSel,modelSel,selAND;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) || (r<=0.0))  return;
+
+    v   = sqrt(a*a + b*b + c*c);
+    if (v<=0.0)  return;
+
+    k   = selHnd-1;
+    sk  = sKey;
+    A   = atom;
+    nat = nAtoms;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      default       : return;
+    }
+
+    selAND = (sKey==SKEY_AND);
+
+    if ((nat<=0) || (!A))  return;
+
+    if (sType==STYPE_ATOM)  {
+
+      for (i=0;i<nat;i++)
+        if (A[i])  {
+          if ((!A[i]->Ter) && (A[i]->WhatIsSet & ASET_Coordinates))  {
+            h = fabs(d-a*A[i]->x-b*A[i]->y-c*A[i]->z)/v;
+            if (h<=r)
+              SelectAtom ( A[i],k,sk,nsel );
+            else if (sk==SKEY_AND)
+              A[i]->RemoveMask ( mask[k] );
+          }
+        }
+
+    } else  {
+
+      for (im=0;im<nModels;im++)  {
+        mdl = model[im];
+        if (mdl)  {
+          modelSel = false;
+          for (ic=0;ic<mdl->nChains;ic++)  {
+            chain = mdl->chain[ic];
+            if (chain)  {
+              chainSel = false;
+              for (ir=0;ir<chain->nResidues;ir++)  {
+                res = chain->residue[ir];
+                if (res)  {
+                  resSel = false;
+                  for (i=0;i<res->nAtoms;i++)  {
+                    atm = res->atom[i];
+                    if (atm) {
+                      if ((!atm->Ter) &&
+                          (atm->WhatIsSet & ASET_Coordinates))  {
+                        h = fabs(d-a*A[i]->x-b*A[i]->y-c*A[i]->z)/v;
+                        if (h<=r)  {
+                          SelectObject ( sType,atm,k,sk,nsel );
+                          resSel   = true;
+                          chainSel = true;
+                          modelSel = true;
+                          break;  // selType>=STYPE_RESIDUE
+                        }
+                      }
+                    }
+                  }
+                  if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+                    res->RemoveMask ( mask[k] );
+                  if (chainSel && (sType>STYPE_RESIDUE))  break;
+                }
+              }
+              if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+                chain->RemoveMask ( mask[k] );
+              if (modelSel && (sType>STYPE_CHAIN))  break;
+            }
+          }
+          if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+            mdl->RemoveMask ( mask[k] );
+        }
+      }
+
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+  void SelManager::SelectNeighbours (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               PPAtom  sA, // array of already selected atoms
+               int    alen, // length of A
+               realtype d1, // minimal distance to already selected atoms
+               realtype d2, // maximal distance to already selected atoms
+               SELECTION_KEY sKey  // selection key
+                                         )  {
+  // Selecting all atoms on a given distance from already selected
+  PPAtom   A;
+  PBrick   B;
+  PAtom    atm;
+  PResidue res;
+  PChain   chain;
+  PModel   mdl;
+  realtype x,y,z, dx,dy,dz, dst, d12,d22;
+  int      i,j,k, dn, nx,ny,nz, nat,nsel, im,ic,ir;
+  int      ix1,ix2,ix, iy1,iy2,iy, iz1,iz2,iz;
+  bool     ASel,resSel,chainSel,modelSel,selAND;
+  SELECTION_KEY sk;
+
+    if ((selHnd<=0) || (selHnd>nSelections) ||
+        (d2<=0.0)   || (d2<d1))  return;
+
+    k   = selHnd-1;
+    sk  = sKey;
+    A   = atom;
+    nat = nAtoms;
+    d12 = d1*d1;
+    d22 = d2*d2;
+
+    if ((selType[k]==STYPE_UNDEFINED) || (sKey==SKEY_NEW))
+            selType[k] = sType;
+    else if (selType[k]!=sType)  return;
+
+    if ((alen<1) || (!sA))  {
+      if ((sKey==SKEY_NEW) || (sKey==SKEY_AND))  {
+        for (i=0;i<nSelItems[k];i++)
+          if (selection[k][i])
+            selection[k][i]->RemoveMask ( mask[k] );
+        nSelItems[k] = 0;
+      }
+      return;
+    }
+
+    // if something goes wrong, sk should be assigned SKEY_OR if
+    // selKey is set to SKEY_NEW or SKEY_OR below
+    switch (sKey)  {
+      case SKEY_NEW : for (i=0;i<nSelItems[k];i++)
+                        if (selection[k][i])
+                            selection[k][i]->RemoveMask ( mask[k] );
+                      nSelItems[k] = 0;
+                      nsel = 0;
+                    break;
+      case SKEY_OR  : if (nSelItems[k]==0)  sk = SKEY_NEW;
+                      nsel = nSelItems[k];
+                    break;
+      case SKEY_AND : nsel = 0;
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      case SKEY_XOR : nsel = nSelItems[k];
+                    break;
+      case SKEY_CLR : nsel = nSelItems[k];
+                      nat  = nSelItems[k];
+                      A    = (PPAtom)selection[k];
+                    break;
+      default       : return;
+    }
+
+    selAND = (sk==SKEY_AND);
+
+    if ((nat<=0) || (!A))  return;
+
+    MakeBricks ( sA,alen,d2*1.5 );
+    dn = mround(d2/brick_size)+1;
+
+    if (brick && (sType==STYPE_ATOM))  {
+
+      for (i=0;i<nat;i++)
+        if (A[i])  {
+          if (!A[i]->Ter)  {
+            ASel = false;
+            GetBrickCoor ( A[i],nx,ny,nz );
+            if (nx<0) nx++;
+            ix1 = IMax ( 0,nx-dn );
+            iy1 = IMax ( 0,ny-dn );
+            iz1 = IMax ( 0,nz-dn );
+            ix2 = IMin ( nbrick_x,nx+dn+1 );
+            iy2 = IMin ( nbrick_y,ny+dn+1 );
+            iz2 = IMin ( nbrick_z,nz+dn+1 );
+            x   = A[i]->x;
+            y   = A[i]->y;
+            z   = A[i]->z;
+            for (ix=ix1;(ix<ix2) && (!ASel);ix++)
+              if (brick[ix])
+                for (iy=iy1;(iy<iy2) && (!ASel);iy++)
+                  if (brick[ix][iy])
+                    for (iz=iz1;(iz<iz2) && (!ASel);iz++)  {
+                      B = brick[ix][iy][iz];
+                      if (B)
+                        for (j=0;(j<B->nAtoms) && (!ASel);j++)
+                          if (B->atom[j]!=A[i])  {
+                            dx = fabs(x-B->atom[j]->x);
+                            if (dx<=d2)  {
+                              dy = fabs(y-B->atom[j]->y);
+                              if (dy<=d2)  {
+                                dz = fabs(z-B->atom[j]->z);
+                                if (dz<=d2)  {
+                                  dst = dx*dx+dy*dy+dz*dz;
+                                  if ((dst>=d12) && (dst<=d22))  {
+                                    ASel = true;
+                                    SelectAtom ( A[i],k,sk,nsel );
+                                  }
+                                }
+                              }
+                            }
+                          }
+                    }
+            if ((!ASel) && selAND)  A[i]->RemoveMask ( mask[k] );
+          }
+        }
+
+    } else if (brick)  {
+
+      for (im=0;im<nModels;im++)  {
+        mdl = model[im];
+        if (mdl)  {
+          modelSel = false;
+          for (ic=0;ic<mdl->nChains;ic++)  {
+            chain = mdl->chain[ic];
+            if (chain)  {
+              chainSel = false;
+              for (ir=0;ir<chain->nResidues;ir++)  {
+                res = chain->residue[ir];
+                if (res)  {
+                  resSel = false;
+                  for (i=0;(i<res->nAtoms) && (!resSel);i++)  {
+                    atm = res->atom[i];
+                    if (atm) {
+                      if ((!atm->Ter) &&
+                          (atm->WhatIsSet & ASET_Coordinates))  {
+                        GetBrickCoor ( atm,nx,ny,nz );
+                        if (nx<0) nx++;
+                        ix1 = IMax ( 0,nx-dn );
+                        iy1 = IMax ( 0,ny-dn );
+                        iz1 = IMax ( 0,nz-dn );
+                        ix2 = IMin ( nbrick_x,nx+dn+1 );
+                        iy2 = IMin ( nbrick_y,ny+dn+1 );
+                        iz2 = IMin ( nbrick_z,nz+dn+1 );
+                        x   = atm->x;
+                        y   = atm->y;
+                        z   = atm->z;
+                        for (ix=ix1;(ix<ix2) && (!resSel);ix++)
+                          if (brick[ix])
+                            for (iy=iy1;(iy<iy2) && (!resSel);iy++)
+                              if (brick[ix][iy])
+                                for (iz=iz1;(iz<iz2) && (!resSel);iz++) {
+                                  B = brick[ix][iy][iz];
+                                  if (B)
+                                    for (j=0;(j<B->nAtoms) &&
+                                             (!resSel);j++)
+                                      if (B->atom[j]!=atm)  {
+                                        dx = fabs(x-B->atom[j]->x);
+                                        if (dx<=d2)  {
+                                          dy = fabs(y-B->atom[j]->y);
+                                          if (dy<=d2)  {
+                                            dz = fabs(z-B->atom[j]->z);
+                                            if (dz<=d2)  {
+                                              dst = dx*dx+dy*dy+dz*dz;
+                                              if ((dst>=d12) &&
+                                                  (dst<=d22))  {
+                                                SelectObject ( sType,
+                                                        atm,k,sk,nsel );
+                                                resSel   = true;
+                                                chainSel = true;
+                                                modelSel = true;
+                                              }
+                                            }
+                                          }
+                                        }
+                                      }
+                                }
+
+                      }
+                    }
+                  }
+                  if ((!resSel) && selAND && (sType==STYPE_RESIDUE))
+                    res->RemoveMask ( mask[k] );
+                  if (chainSel && (sType>STYPE_RESIDUE))  break;
+                }
+              }
+              if ((!chainSel) && selAND && (sType==STYPE_CHAIN))
+                chain->RemoveMask ( mask[k] );
+              if (modelSel && (sType>STYPE_CHAIN))  break;
+            }
+          }
+          if ((!modelSel) && selAND && (sType==STYPE_MODEL))
+            mdl->RemoveMask ( mask[k] );
+        }
+      }
+
+    }
+
+    MakeSelIndex ( selHnd,sType,nsel );
+
+  }
+
+
+
+  int TakeChainID ( pstr & p, pstr chainID )  {
+  int RC,k;
+    chainID[0] = char(0);
+    if (*p)  {
+      RC = 0;
+      if (*p==':')  {
+        // starts with colon <=> empty chain ID
+        chainID[0] = char(0);
+        p++;  // advance to residue number
+      } else if (p[1]==':')  {
+        // second symbol is colon <=> regular chain ID
+        chainID[0] = *p;
+        chainID[1] = char(0);
+        p++;
+        p++;  // advance to residue number
+      } else if (*p=='\'')  {
+        // starts with a strip <=> assume empty chain ID
+        chainID[0] = char(0);
+        p++;
+        if (*p=='\'')  {
+          // closing strip must be followed by colon
+          p++;
+          if (*p!=':')  RC = -1;
+        } else  {
+          // no concluding strip <=> could be a strip chain ID,
+          // although this must be captured by 2nd "if"
+          chainID[0] = '\'';
+          chainID[1] = char(0);
+          // assume that residue number is following the strip
+        }
+      } else if ((int(*p)>=int('0')) && (int(*p)<=int('9')))  {
+        // a digit without following semicolon looks very much
+        // like residue number with unspecified empty chain ID
+        chainID[0] = char(0);
+        // assume that p already points on residue number
+      } else  {
+        // assume a long chain ID
+        k = 0;
+        while (*p && (*p!=':') && (k<(int)sizeof(ChainID)-1)) {
+          chainID[k++] = *p;
+          p++;
+        }
+        if (*p==':')  {
+          chainID[k] = char(0);
+        } else  {
+          // a mistake
+          chainID[0] = char(0);
+          RC = -1;
+        }
+      }
+      while (*p==' ')  p++;
+    } else
+      RC = 1;
+    return RC;
+  }
+
+  int TakeResID( pstr & p, int & seqNum, pstr inscode )  {
+  char N[100];
+  int  i,RC;
+  pstr endptr;
+    RC = 1;
+    inscode[0] = '*';
+    inscode[1] = char(0);
+    seqNum     = ANY_RES;
+    if (((*p) &&
+         (int(*p)>=int('0')) && (int(*p)<=int('9'))) || (*p=='-'))  {
+      N[0] = *p;
+      p++;
+      i = 1;
+      while ((*p) && (int(*p)>=int('0')) && (int(*p)<=int('9')))  {
+        N[i++] = *p;
+        p++;
+      }
+      N[i] = char(0);
+      seqNum = mround(strtod(N,&endptr));
+      if ((seqNum==0) && (endptr==N))
+        RC = -1;
+      else  {
+        RC = 0;
+        if ((*p) && (*p!='-') && (*p!=',') && (*p!=' '))  {
+          inscode[0] = *p;
+          inscode[1] = char(0);
+          p++;
+        } else
+          inscode[0] = char(0);
+        if ((*p=='-') || (*p==','))  p++;
+      }
+      while (*p==' ')  p++;
+    }
+    return RC;
+  }
+
+
+  int  SelManager::SelectDomain ( int selHnd , cpstr domainRange,
+                                  SELECTION_TYPE sType,
+                                  SELECTION_KEY  sKey,
+                                  int modelNo )  {
+  // domainRange is of the following format:
+  //    "*", "(all)"            - take all file
+  //    "-"                     - take chain without chain ID
+  //    "a:Ni-Mj,b:Kp-Lq,..."   - take chain a residue number N
+  //                              insertion code i to residue number M
+  //                              insertion code j plus chain b
+  //                              residue number K insertion code p to
+  //                              residue number L insertion code q and
+  //                              so on.
+  //    "a:,b:..."              - take whole chains a and b and so on
+  //    "a:,b:Kp-Lq,..."        - any combination of the above.
+  ChainID       chainID;
+  InsCode       insCode1,insCode2;
+  pstr          S,p;
+  int           seqNum1,seqNum2,rc;
+  SELECTION_KEY selKey1;
+
+    if ((selHnd<=0) || (selHnd>nSelections))  return 1;
+
+    // leave only required residues
+
+    rc = 1;
+    if (!domainRange)  rc = 0;
+    else if ((!domainRange[0]) || (domainRange[0]=='*'))  rc = 0;
+    else if (!strcasecmp(domainRange,"(all)"))  rc = 0;
+    if (!rc)  {
+      // select all
+      Select ( selHnd,sType,modelNo,"*",ANY_RES,"*",ANY_RES,"*",
+                                      "*","*","*","*",sKey );
+      return 0;
+    }
+    if (!strcasecmp(domainRange,"-"))  {
+      // select chain without chain ID
+      Select ( selHnd,sType,modelNo,"",ANY_RES,"*",ANY_RES,"*",
+                                      "*","*","*","*",sKey );
+      return 0;
+    }
+
+    S = new char[strlen(domainRange)+10];
+    strcpy    ( S,domainRange );
+    DelSpaces ( S );
+  //  UpperCase ( S );
+
+    p  = S;
+    rc = 0;
+
+    selKey1 = sKey;
+
+    while ((*p) && (!rc))  {
+
+      if (TakeChainID(p,chainID)<0)             rc = -1;
+      else if (TakeResID(p,seqNum1,insCode1)<0) rc = -2;
+      else if (TakeResID(p,seqNum2,insCode2)<0) rc = -3;
+      else  {
+        Select ( selHnd,sType,modelNo,chainID,
+                 seqNum1,insCode1,seqNum2,insCode2,
+                 "*","*","*","*",selKey1 );
+        if (*p==',')  p++;
+        if (selKey1==SKEY_NEW)  selKey1 = SKEY_OR;
+      }
+
+    }
+
+    delete[] S;
+
+    return rc;
+
+  }
+
+
+  int SelManager::GetSelLength ( int selHnd )  {
+    if ((selHnd>0) && (selHnd<=nSelections))
+          return nSelItems[selHnd-1];
+    else  return 0;
+  }
+
+
+  void SelManager::GetSelIndex ( int       selHnd,
+                                      PPAtom & SelAtom,
+                                      int &     nSelAtoms )  {
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      if (selType[selHnd-1]!=STYPE_ATOM)  {
+        SelAtom   = NULL;
+        nSelAtoms = 0;
+      } else  {
+        SelAtom   = (PPAtom)selection[selHnd-1];
+        nSelAtoms = nSelItems[selHnd-1];
+      }
+    } else  {
+      SelAtom   = NULL;
+      nSelAtoms = 0;
+    }
+  }
+
+  void SelManager::GetSelIndex ( int          selHnd,
+                                      PPResidue & SelResidue,
+                                      int &        nSelResidues )  {
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      if (selType[selHnd-1]!=STYPE_RESIDUE)  {
+        SelResidue   = NULL;
+        nSelResidues = 0;
+      } else  {
+        SelResidue   = (PPResidue)selection[selHnd-1];
+        nSelResidues = nSelItems[selHnd-1];
+      }
+    } else  {
+      SelResidue   = NULL;
+      nSelResidues = 0;
+    }
+  }
+
+  void SelManager::GetSelIndex ( int        selHnd,
+                                      PPChain & SelChain,
+                                      int &      nSelChains )  {
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      if (selType[selHnd-1]!=STYPE_CHAIN)  {
+        SelChain   = NULL;
+        nSelChains = 0;
+      } else  {
+        SelChain   = (PPChain)selection[selHnd-1];
+        nSelChains = nSelItems[selHnd-1];
+      }
+    } else  {
+      SelChain   = NULL;
+      nSelChains = 0;
+    }
+  }
+
+  void SelManager::GetSelIndex ( int        selHnd,
+                                      PPModel & SelModel,
+                                      int &      nSelModels )  {
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      if (selType[selHnd-1]!=STYPE_MODEL)  {
+        SelModel   = NULL;
+        nSelModels = 0;
+      } else  {
+        SelModel   = (PPModel)selection[selHnd-1];
+        nSelModels = nSelItems[selHnd-1];
+      }
+    } else  {
+      SelModel   = NULL;
+      nSelModels = 0;
+    }
+  }
+
+
+  void SelManager::GetAtomStatistics ( int selHnd, RAtomStat AS )  {
+  int  i,k;
+    AS.Init();
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      k = selHnd-1;
+      switch (selType[k])  {
+        case STYPE_MODEL   : if (selection[k])
+                               for (i=0;i<nSelItems[k];i++)
+                                 ((PModel)selection[k][i])->
+                                   CalAtomStatistics ( AS );
+                         break;
+        case STYPE_CHAIN   : if (selection[k])
+                               for (i=0;i<nSelItems[k];i++)
+                                 ((PChain)selection[k][i])->
+                                   CalAtomStatistics ( AS );
+                         break;
+        case STYPE_RESIDUE : if (selection[k])
+                               for (i=0;i<nSelItems[k];i++)
+                                 ((PResidue)selection[k][i])->
+                                   CalAtomStatistics ( AS );
+                         break;
+        case STYPE_ATOM    : if (selection[k])
+                               for (i=0;i<nSelItems[k];i++)
+                                 ((PAtom)selection[k][i])->
+                                   CalAtomStatistics ( AS );
+                         break;
+        default            : break;
+      }
+    }
+    AS.Finish();
+  }
+
+
+  void SelManager::SelectAtom ( PAtom atom, int maskNo,
+                                SELECTION_KEY sKey, int & nsel )  {
+  bool ASel;
+    ASel = atom->CheckMask ( mask[maskNo] );
+    switch (sKey)  {
+      default       :
+      case SKEY_NEW :
+      case SKEY_OR  : if (!ASel)  {
+                        atom->SetMask ( mask[maskNo] );
+                        nsel++;
+                      }
+                    break;
+      case SKEY_AND : if (ASel)  nsel++;
+                    break;
+      case SKEY_XOR : if (ASel)  {
+                        atom->RemoveMask ( mask[maskNo] );
+                        nsel--;
+                      } else  {
+                        atom->SetMask ( mask[maskNo] );
+                        nsel++;
+                      }
+                    break;
+      case SKEY_CLR : if (ASel)  {
+                        atom->RemoveMask ( mask[maskNo] );
+                        nsel--;
+                      }
+    }
+  }
+
+
+  void SelManager::SelectObject ( SELECTION_TYPE sType,
+                                  PAtom          atm,
+                                  int            maskNo,
+                                  SELECTION_KEY  sKey,
+                                  int          & nsel )  {
+  PMask  object;
+    switch (sType)  {
+      default :
+      case STYPE_UNDEFINED : return;
+      case STYPE_ATOM      : object = atm;                break;
+      case STYPE_RESIDUE   : object = atm->GetResidue();  break;
+      case STYPE_CHAIN     : object = atm->GetChain  ();  break;
+      case STYPE_MODEL     : object = atm->GetModel  ();  break;
+    }
+    if (!object)  return;
+    SelectObject ( object,maskNo,sKey,nsel );
+  }
+
+
+  void SelManager::SelectObject ( PMask object, int maskNo,
+                                  SELECTION_KEY sKey, int & nsel )  {
+  bool ASel;
+    ASel = object->CheckMask ( mask[maskNo] );
+    switch (sKey)  {
+      default        :
+      case SKEY_NEW  :
+      case SKEY_OR   : if (!ASel)  {
+                         object->SetMask ( mask[maskNo] );
+                         nsel++;
+                       }
+                    break;
+      case SKEY_AND  : if (ASel)  nsel++;
+                    break;
+      case SKEY_XOR  : if (ASel)  {
+                         object->RemoveMask ( mask[maskNo] );
+                         nsel--;
+                       } else  {
+                         object->SetMask ( mask[maskNo] );
+                         nsel++;
+                       }
+                    break;
+      case SKEY_CLR  : if (ASel)  {
+                         object->RemoveMask ( mask[maskNo] );
+                         nsel--;
+                       }
+                    break;
+      case SKEY_XAND : if (ASel)  {
+                         object->RemoveMask ( mask[maskNo] );
+                         nsel++;
+                       }
+    }
+  }
+
+
+  void  SelManager::DeleteSelObjects ( int selHnd )  {
+  PPModel   model;
+  PPChain   chain;
+  PPResidue res;
+  PPAtom    atom;
+  int        i,k,nSel;
+
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+
+      k    = selHnd-1;
+      nSel = nSelItems[k];
+      switch (selType[k])  {
+
+        case STYPE_MODEL   : model = (PPModel)selection[k];
+                             for (i=0;i<nSel;i++)
+                               delete model[i];
+                          break;
+
+        case STYPE_CHAIN   : chain = (PPChain)selection[k];
+                             for (i=0;i<nSel;i++)
+                               delete chain[i];
+                          break;
+
+        case STYPE_RESIDUE : res   = (PPResidue)selection[k];
+                             for (i=0;i<nSel;i++)
+                               delete res[i];
+                          break;
+
+        case STYPE_ATOM    : atom  = (PPAtom)selection[k];
+                             for (i=0;i<nSel;i++)
+                               delete atom[i];
+                          break;
+
+        default : ;
+
+      }
+
+      if (selection[k])  delete[] selection[k];
+      selection[k] = NULL;
+      nSelItems[k] = 0;
+
+    }
+
+  }
+
+  // ------------------------------------------------------------------------
+
+  void SelManager::MakeSelIndex ( int selHnd,
+                                  SELECTION_TYPE sType, int nsel )  {
+  // if nsel is less than 0, the number of selected atoms will
+  // be calculated.
+  PModel   mdl;
+  PChain   chain;
+  PResidue res;
+  int      k,i,j,n,ns,k1,k2, nns;
+
+    if ((selHnd>0) && (selHnd<=nSelections))  {
+      k1 = selHnd-1;
+      k2 = k1+1;
+    } else  {
+      k1 = 0;
+      k2 = nSelections;
+    }
+
+    for (k=k1;k<k2;k++)  {
+      if (nsel<0)  {
+        ns = 0;
+        switch (sType)  {
+          case STYPE_ATOM    : for (i=0;i<nAtoms;i++)
+                                 if (atom[i])
+                                   if (atom[i]->CheckMask(mask[k]))  ns++;
+                            break;
+          case STYPE_RESIDUE : for (n=0;n<nModels;n++)  {
+                                 mdl = model[n];
+                                 if (mdl)
+                                   for (i=0;i<mdl->nChains;i++) {
+                                     chain = mdl->chain[i];
+                                     if (chain)
+                                       for (j=0;j<chain->nResidues;j++) {
+                                         res = chain->residue[j];
+                                         if (res)
+                                           if (res->CheckMask(mask[k]))  ns++;
+                                       }
+                                   }
+                               }
+                            break;
+          case STYPE_CHAIN   : for (i=0;i<nModels;i++)  {
+                                 mdl = model[i];
+                                 if (mdl)
+                                   for (j=0;j<mdl->nChains;j++) {
+                                     chain = mdl->chain[j];
+                                     if (chain)
+                                       if (chain->CheckMask(mask[k]))  ns++;
+                                   }
+                               }
+                            break;
+          case STYPE_MODEL   : for (i=0;i<nModels;i++)
+                                 if (model[i])
+                                   if (model[i]->CheckMask(mask[k]))  ns++;
+                            break;
+          default : ;
+        }
+      } else
+        ns = nsel;
+      if (selection[k])  delete[] selection[k];
+      if (ns>0)  {
+        selection[k] = new PMask[ns];
+        nns = 0;
+        switch (sType)  {
+          case STYPE_ATOM    : for (i=0;i<nAtoms;i++)
+                                 if (atom[i])  {
+                                   if (atom[i]->CheckMask(mask[k]))  {
+                                     selection[k][nns++] = atom[i];
+                                     if (nns>=ns)  nns = ns-1;
+                                   }
+                                 }
+                            break;
+          case STYPE_RESIDUE : for (n=0;n<nModels;n++)  {
+                                 mdl = model[n];
+                                 if (mdl)
+                                   for (i=0;i<mdl->nChains;i++) {
+                                     chain = mdl->chain[i];
+                                     if (chain)
+                                       for (j=0;j<chain->nResidues;j++)  {
+                                         res = chain->residue[j];
+                                         if (res)
+                                           if (res->CheckMask(mask[k]))  {
+                                             selection[k][nns++] = res;
+                                             if (nns>=ns)  nns = ns-1;
+                                           }
+                                       }
+                                   }
+                               }
+                            break;
+          case STYPE_CHAIN   : for (i=0;i<nModels;i++)  {
+                                 mdl = model[i];
+                                 if (mdl)
+                                   for (j=0;j<mdl->nChains;j++) {
+                                     chain = mdl->chain[j];
+                                     if (chain)
+                                       if (chain->CheckMask(mask[k]))  {
+                                         selection[k][nns++] = chain;
+                                         if (nns>=ns)  nns = ns-1;
+                                       }
+                                   }
+                               }
+                            break;
+          case STYPE_MODEL   : for (i=0;i<nModels;i++)
+                                 if (model[i])
+                                   if (model[i]->CheckMask(mask[k]))  {
+                                     selection[k][nns++] = model[i];
+                                     if (nns>=ns)  nns = ns-1;
+                                   }
+                            break;
+          default : ;
+        }
+
+      } else
+        selection[k] = NULL;
+
+      nSelItems[k] = ns;
+    }
+
+  }
+
+
+  //  -------------------  Stream functions  ----------------------
+
+
+  void  SelManager::write ( io::RFile f )  {
+  int  i,sType;
+  byte Version=1;
+
+    f.WriteByte ( &Version );
+
+    CoorManager::write ( f );
+
+    f.WriteInt ( &nSelections );
+    for (i=0;i<nSelections;i++)  {
+      StreamWrite ( f,mask[i]       );
+      f.WriteInt  ( &(nSelItems[i]) );
+      sType = selType[i];
+      f.WriteInt  ( &(sType) );
+    }
+
+  }
+
+  void  SelManager::read ( io::RFile f )  {
+  int  i,sType;
+  byte Version;
+
+    f.ReadByte ( &Version );
+
+    DeleteAllSelections();
+
+    CoorManager::read ( f );
+
+    f.ReadInt ( &nSelections );
+    if (nSelections>0)  {
+      mask      = new PMask [nSelections];
+      selection = new PPMask[nSelections];
+      nSelItems = new int    [nSelections];
+      selType   = new SELECTION_TYPE[nSelections];
+      for (i=0;i<nSelections;i++)  {
+        mask[i] = NULL;
+        StreamRead ( f,mask[i]       );
+        f.ReadInt  ( &(nSelItems[i]) );
+        f.ReadInt  ( &(sType)        );
+        selType  [i] = (SELECTION_TYPE)sType;
+        selection[i] = NULL;
+        if (mask[i])
+             MakeSelIndex ( i+1,selType[i],-1 );
+        else nSelItems[i] = 0;
+      }
+    }
+
+  }
+
+
+  MakeStreamFunctions(SelManager)
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_selmngr.h b/mmdb2/mmdb_selmngr.h
new file mode 100644
index 0000000..fab8499
--- /dev/null
+++ b/mmdb2/mmdb_selmngr.h
@@ -0,0 +1,634 @@
+//  $Id: mmdb_selmngr.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    15.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  mmdb_selmngr <interface>
+//       ~~~~~~~~~
+//       Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::Manager ( MMDB atom selection manager )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_SelMngr__
+#define __MMDB_SelMngr__
+
+#include "mmdb_coormngr.h"
+#include "mmdb_mask.h"
+
+namespace mmdb  {
+
+  // =======================   SelManager  ==========================
+
+  //   Selection keys. These specify how the requested selection
+  // operation applies to the existing selection for the given mask:
+  //    SKEY_NEW    previous selection is wiped out
+  //    SKEY_OR     new selection is added to the already selected set;
+  //                if no selection preexists, SKEY_NEW and SKEY_OR
+  //                are equivalent. This key is the default one in
+  //                all selection functions.
+  //    SKEY_AND    new selection is made on the already selected set;
+  //                this corresponds to logical 'and' of former and
+  //                current selections. If no selection preexists,
+  //                no selection will be made.
+  //    SKEY_XOR    only those atoms will be left which are found
+  //                in either former or newly selected sets, but not
+  //                in both of them; this corresponds to logical
+  //                'exclusive or' of previous and current selections.
+  //                If no selection preexists, it is equivalent to
+  //                SKEY_OR.
+  enum SELECTION_KEY  {
+    SKEY_NEW  = 0,
+    SKEY_OR   = 1,
+    SKEY_AND  = 2,
+    SKEY_XOR  = 3,
+    SKEY_CLR  = 4,
+    SKEY_XAND = 100  // used internally
+  };
+
+  //  Selection types
+  enum SELECTION_TYPE  {
+    STYPE_INVALID   = -1,
+    STYPE_UNDEFINED =  0,
+    STYPE_ATOM      =  1,
+    STYPE_RESIDUE   =  2,
+    STYPE_CHAIN     =  3,
+    STYPE_MODEL     =  4
+  };
+
+  //  Residue properties for SelectProperties()
+  enum SELECTION_PROPERTY  {
+    SELPROP_Solvent    = 0,
+    SELPROP_Aminoacid  = 1,
+    SELPROP_Nucleotide = 2,
+    SELPROP_Sugar      = 3,
+    SELPROP_ModRes     = 4
+  };
+
+  //  comparison rules for SelectUDD function
+  enum UDD_CMP_RULE  {
+    UDSCR_LT        =  1,
+    UDSCR_LE        =  2,
+    UDSCR_EQ        =  3,
+    UDSCR_NE        =  4,
+    UDSCR_GE        =  5,
+    UDSCR_GT        =  6,
+    UDSCR_LTcase    =  7,
+    UDSCR_LEcase    =  8,
+    UDSCR_EQcase    =  9,
+    UDSCR_NEcase    = 10,
+    UDSCR_GEcase    = 11,
+    UDSCR_GTcase    = 12,
+    UDSCR_LTn       = 13,
+    UDSCR_LEn       = 14,
+    UDSCR_EQn       = 15,
+    UDSCR_NEn       = 16,
+    UDSCR_GEn       = 17,
+    UDSCR_GTn       = 18,
+    UDSCR_LTncase   = 19,
+    UDSCR_LEncase   = 20,
+    UDSCR_EQncase   = 21,
+    UDSCR_NEncase   = 22,
+    UDSCR_GEncase   = 23,
+    UDSCR_GTncase   = 24,
+    UDSCR_Substr    = 25,
+    UDSCR_NoSubstr  = 26,
+    UDSCR_Substr1   = 27,
+    UDSCR_NoSubstr1 = 28
+  };
+
+  DefineClass(SelManager);
+  DefineStreamFunctions(SelManager);
+
+  class  SelManager : public  CoorManager  {
+
+    public :
+
+       SelManager ();
+       SelManager ( io::RPStream Object );
+      ~ SelManager();
+
+
+      // ====================  Selecting atoms  =======================
+
+      //    NewSelection() creates a new selection mask and returns its
+      // handle.  A handle is always a positive (non-zero) integer.
+      // Calling NewSelection() is the only way to create a new
+      // selection mask. Notice however that masks will be automatically
+      // copied from another MMDB (see Copy(..) in CMMDBManager) if
+      // coordinates are copied; if this is the case, the mask handles
+      // will be inherited from the source MMDB as well. The masks will
+      // also be automatically deleted (see Delete(..) in CMMDBManager())
+      // if coordinates are deleted.
+      int   NewSelection ();
+
+      int   GetSelType ( int selHnd );  // returns STYPE_XXXX
+
+      //    DeleteSelection(..) deletes the specified selection mask
+      // and removes the corresponding selection attributes from
+      // all atoms, which were selected with this mask. If an atom
+      // was selected also with other mask(s), the other selection(s)
+      // will remain, provided that the corresponding masks are valid.
+      // After DeleteSelection() returns, the corresponding mask
+      // becomes invalid.
+      void  DeleteSelection ( int selHnd );
+
+      //    DeleteAllSelections() deletes all selection masks and
+      // unselects all atoms in the file. All mask handles become
+      // invalid.
+      void  DeleteAllSelections();
+
+      //   SelectAtoms(..) selects atoms in the serial number range
+      // of iSer1 to iSer2 by adding them to the set of atoms
+      // marked by the given mask. If iSer1=iSer2=0 then all atoms
+      // are selected. Each atom may be selected by a number of masks
+      // simultaneously.
+      void  SelectAtoms ( int selHnd, int iSer1, int iSer2,
+                          SELECTION_KEY selKey=SKEY_OR // selection key
+                        );
+
+      //   SelectAtoms(..) selects atoms with serial numbers given in
+      // vector asn[0..nsn-1].
+      void  SelectAtoms ( int selHnd, ivector asn, int nsn,
+                          SELECTION_KEY selKey=SKEY_OR // selection key
+                        );
+
+      //   UnselectAtoms(..) clears the specified mask for atoms in
+      // the serial number range of iSer1 to iSer2. If iSer1=iSer2=0
+      // then all atoms are cleared of the specified mask. If selHnd
+      // is set to 0, then the atoms are cleared of any mask.
+      void  UnselectAtoms ( int selHnd, int iSer1, int iSer2 );
+
+      //   SelectAtom(..) selects a single atom according to the value
+      // of selection key. If makeIndex is false, then the routine
+      // does not update the selection index. This saves time, but
+      // prevents GetSelIndex(..) from accessing all selected atoms.
+      // In order to update the index after all single-atom selections
+      // are done, use MakeSelIndex(selHnd) found next.
+      void  SelectAtom    ( int selHnd, PAtom A,
+                            SELECTION_KEY selKey=SKEY_OR,
+                            bool makeIndex=true );
+
+      //   SelectResidue(..), SelectChain(..) and SelectModel(..)
+      // select a single residue, chain or model, or all their
+      // hierarchical descendants depending on the value of sType
+      // (i.e. atoms, residues (in chain and model) and chains
+      // (in model only). Ascending hierarchical objects should be
+      // selected explicitely, e.g. atom->GetResidue()->SelectResidue(..)
+      void  SelectResidue ( int selHnd, PResidue Res,
+                            SELECTION_TYPE sType,
+                            SELECTION_KEY  sKey,
+                            bool makeIndex );
+      void  SelectChain   ( int selHnd, PChain chain,
+                            SELECTION_TYPE sType,
+                            SELECTION_KEY  sKey,
+                            bool makeIndex );
+      void  SelectModel   ( int selHnd, PModel mdl,
+                            SELECTION_TYPE sType,
+                            SELECTION_KEY  sKey,
+                            bool makeIndex );
+
+
+      //   MakeSelIndex(.) calculates selection index for selection
+      // adressed by selHnd.  All selection functions except the
+      // SelectAtom(..) above, update selection index automatically.
+      // This function is for use after a series of calls to
+      // SelectAtom(..) with makeIndex parameter set false. This
+      // combination of SelectAtom - MakeSelIndex considerably saves CPU
+      // at extensive selections.
+      //   MakeSelIndex(.) returns the number of selected objects.
+      int   MakeSelIndex  ( int selHnd );
+      void  MakeAllSelIndexes();
+
+      //   Selecting by atom ID, space condition (a sphere) and some
+      // other bits.
+      void  SelectAtoms (
+               int   selHnd,   // must be obtained from NewSelection()
+               int   iModel,   // model number; iModel=0 means
+                               // 'any model'
+               cpstr Chains,   // may be several chains "A,B,W"; "*"
+                               // means 'any chain' (in selected
+                               // model(s))
+               int   ResNo1,   // starting residue sequence number
+               cpstr Ins1,     // starting residue insertion code; "*"
+                               // means 'any code'
+               int   ResNo2,   // ending residue sequence number.
+               cpstr Ins2,     // ending residue insertion code; "*"
+                               // means 'any code'. Combination of
+                               // ResNo1=ResNo2=ANY_RES and
+                               // Ins1=Ins2="*" means 'any residue'
+                               // (in selected chain(s))
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means 'any
+                               // residue name'
+               cpstr ANames,   // may be several names "CA,CB"; "*"
+                               // means 'any atom' (in selected
+                               // residue(s))
+               cpstr Elements, // may be several element types
+                               // 'H,C,O,CU'; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means
+                               // 'any alternative location'
+               cpstr Segments, // may be several segment IDs
+                               // like "S1,S2,A234"; "*" means
+                               // 'any segment'
+               cpstr Charges,  // may be several charges like
+                               // "+1,-2,  "; "*" means 'any charge'
+               realtype occ1,  // lowest occupancy
+               realtype occ2,  // highest occupancy; occ1=occ2<0.0
+                               // means "any occupancy"
+               realtype x0,    // reference x-point
+               realtype y0,    // reference y-point
+               realtype z0,    // reference z-point
+               realtype d0,    // selection distance from the
+                               // reference point; d0<=0.0
+                               // means "any distance" and values
+                               // of x0, y0 and z0 are ignored
+               SELECTION_KEY selKey=SKEY_OR // selection key
+             );
+
+      //  Selecting by just atom ID, no other conditions
+      void  SelectAtoms (
+               int   selHnd,   // must be obtained from NewSelection()
+               int   iModel,   // model number; iModel=0 means
+                               // 'any model'
+               cpstr Chains,   // may be several chains "A,B,W"; "*"
+                               // means 'any chain' (in selected
+                               // model(s))
+               int   ResNo1,   // starting residue sequence number
+               cpstr Ins1,     // starting residue insertion code; "*"
+                               // means 'any code'
+               int   ResNo2,   // ending residue sequence number.
+               cpstr Ins2,     // ending residue insertion code; "*"
+                               // means 'any code'. Combination of
+                               // ResNo1=ResNo2=ANY_RES and
+                               // Ins1=Ins2="*" means 'any residue
+                               // number' (in selected chain(s))
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means 'any
+                               // residue name'
+               cpstr ANames,   // may be several names "CA,CB"; "*"
+                               // means 'any atom' (in selected
+                               // residue(s))
+               cpstr Elements, // may be several element types
+                               // "H,C,O,CU"; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means
+                               // 'any alternative location'
+               SELECTION_KEY selKey=SKEY_OR // selection key
+             );
+
+
+      //  Selecting by integer User-Defined Data
+      void  SelectUDD (
+               int      selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               int   UDDhandle, // UDD handle
+               int      selMin, // lower selection boundary
+               int      selMax, // upper selection boundary
+               SELECTION_KEY  sKey  // selection key
+             );
+      void  SelectUDD (
+               int      selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               int   UDDhandle, // UDD handle
+               realtype selMin, // lower selection boundary
+               realtype selMax, // upper selection boundary
+               SELECTION_KEY  sKey  // selection key
+             );
+      void  SelectUDD (
+               int        selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE  sType, // selection type STYPE_XXXXX
+               int     UDDhandle, // UDD handle
+               cpstr      selStr, // selection string
+               int       cmpRule, // comparison rule
+               SELECTION_KEY   sKey  // selection key
+             );
+
+
+      //  Selecting a sphere
+      void  SelectSphere (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               realtype  x, // x-coordinate of the sphere's center
+               realtype  y, // y-coordinate of the sphere's center
+               realtype  z, // z-coordinate of the sphere's center
+               realtype  r, // radius of the sphere
+               SELECTION_KEY  sKey=SKEY_OR // selection key
+             );
+
+      //  Selecting a cylinder
+      void  SelectCylinder (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               realtype x1, // x-coordinate of the cylinder axis' 1st end
+               realtype y1, // y-coordinate of the cylinder axis' 1st end
+               realtype z1, // z-coordinate of the cylinder axis' 1st end
+               realtype x2, // x-coordinate of the cylinder axis' 2nd end
+               realtype y2, // y-coordinate of the cylinder axis' 2nd end
+               realtype z2, // z-coordinate of the cylinder axis' 2nd end
+               realtype  r, // radius of the cylinder
+               SELECTION_KEY  sKey=SKEY_OR // selection key
+             );
+
+      //  Selecting all atoms on a given distance from a plane
+      void  SelectSlab (
+               int  selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               realtype  a, // a-parameter of the plane  ax+by+cz=d
+               realtype  b, // b-parameter of the plane  ax+by+cz=d
+               realtype  c, // c-parameter of the plane  ax+by+cz=d
+               realtype  d, // d-parameter of the plane  ax+by+cz=d
+               realtype  r, // distance to the plane
+               SELECTION_KEY  sKey=SKEY_OR  // selection key
+             );
+
+      //  Selecting all atoms on a given distance from already selected
+      void  SelectNeighbours (
+               int      selHnd, // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               PPAtom   sA,   // array of already selected atoms
+               int      alen, // length of A
+               realtype d1,   // minimal distance to already selected atoms
+               realtype d2,   // maximal distance to already selected atoms
+               SELECTION_KEY  sKey=SKEY_OR // selection key
+             );
+
+
+      int   GetSelLength ( int selHnd );
+
+      //  Getting an array of atoms selected for a certain mask
+      void  GetSelIndex (
+               int       selHnd,  // selection mask
+               PPAtom & SelAtom,  // continuous index of selected
+                                  // atoms; application must not
+                                  // dispose either index or atoms
+               int &    nSelAtoms // length of index
+                                  // [0..nSelectedAtoms-1]
+             );
+
+      //  Getting an array of residues selected for a certain mask
+      void  GetSelIndex (
+               int          selHnd,     // selection mask
+               PPResidue & SelResidues, // continuous index of selected
+                                        // residues; application must
+                                        // not dispose either index or
+                                        // residues
+               int &       nSelResidues // length of index
+                                        // [0..nSelResidues-1]
+             );
+
+      //  Getting an array of chains selected for a certain mask
+      void  GetSelIndex (
+               int        selHnd,   // selection mask
+               PPChain & SelChains, // continuous index of selected
+                                    // chains; application must not
+                                    // dispose either index or chains
+               int &     nSelChains // length of index
+                                    // [0..nSelChains-1]
+             );
+
+      //  Getting an array of models selected for a certain mask
+      void  GetSelIndex (
+               int        selHnd,   // selection mask
+               PPModel & SelModels, // continuous index of selected
+                                    // models; application must not
+                                    // dispose either index or models
+               int &     nSelModels // length of index
+                                    // [0..nSelModels-1]
+             );
+
+      void  GetAtomStatistics ( int selHnd, RAtomStat AS );
+
+
+      // ===============  General selection functions  ================
+
+      //   Selecting by atom ID, space condition (a sphere) and some
+      // other bits.
+      void  Select (
+               int   selHnd,   // must be obtained from NewSelection()
+               SELECTION_TYPE sType,  // selection type STYPE_XXXXX
+               int   iModel,   // model number; iModel=0 means
+                               // 'any model'
+               cpstr Chains,   // may be several chains "A,B,W"; "*"
+                               // means 'any chain' (in selected
+                               // model(s))
+               int   ResNo1,   // starting residue sequence number
+               cpstr Ins1,     // starting residue insertion code; "*"
+                               // means 'any code'
+               int   ResNo2,   // ending residue sequence number.
+               cpstr Ins2,     // ending residue insertion code; "*"
+                               // means 'any code'. Combination of
+                               // ResNo1=ResNo2=ANY_RES and
+                               // Ins1=Ins2="*" means 'any residue'
+                               // (in selected chain(s))
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means
+                               // 'any residue name'
+               cpstr ANames,   // may be several names "CA,CB"; "*"
+                               // means 'any atom' (in selected
+                               // residue(s))
+               cpstr Elements, // may be several element types
+                               // 'H,C,O,CU'; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means
+                               // 'any alternative location'
+               cpstr Segments, // may be several segment IDs like
+                               // "S1,S2,A234"; "*" means
+                               // 'any segment'
+               cpstr Charges,  // may be several charges like
+                               // "+1,-2,  "; "*" means 'any charge'
+               realtype occ1,  // lowest occupancy
+               realtype occ2,  // highest occupancy; occ1=occ2<0.0
+                               // means "any occupancy"
+               realtype x0,    // reference x-point
+               realtype y0,    // reference y-point
+               realtype z0,    // reference z-point
+               realtype d0,    // selection distance from the
+                               // reference point; d0<=0.0
+                               // means "any distance" and values
+                               // of x0, y0 and z0 are ignored
+               SELECTION_KEY sKey=SKEY_OR // selection key
+             );
+
+
+      //  Selecting by just atom ID, no other conditions
+      void  Select (
+               int   selHnd,   // must be obtained from NewSelection()
+               SELECTION_TYPE sType,  // selection type STYPE_XXXXX
+               int   iModel,   // model number; iModel=0 means
+                               // 'any model'
+               cpstr Chains,   // may be several chains "A,B,W"; "*"
+                               // means 'any chain' (in selected
+                               // model(s))
+               int   ResNo1,   // starting residue sequence number
+               cpstr Ins1,     // starting residue insertion code; "*"
+                               // means 'any code'
+               int   ResNo2,   // ending residue sequence number.
+               cpstr Ins2,     // ending residue insertion code; "*"
+                               // means 'any code'. Combination of
+                               // ResNo1=ResNo2=ANY_RES and
+                               // Ins1=Ins2="*" means 'any residue
+                               // number' (in selected chain(s))
+               cpstr RNames,   // may be several residue names
+                               // "ALA,GLU,CIS"; "*" means
+                               // 'any residue name'
+               cpstr ANames,   // may be several names "CA,CB"; "*"
+                               // means 'any atom' (in selected
+                               // residue(s))
+               cpstr Elements, // may be several element types
+                               // "H,C,O,CU"; "*" means 'any element'
+               cpstr altLocs,  // may be several alternative
+                               // locations 'A,B'; "*" means
+                               // 'any alternative location'
+               SELECTION_KEY sKey=SKEY_OR // selection key
+             );
+
+
+      //  Selecting by coordinate ID.
+      //  Examples:
+      //
+      //  1.  /mdl/chn/s1.i1-s2.i2/at[el]:aloc
+      //  2.  /mdl/chn/*(res).ic  /at[el]:aloc
+      //  3.       chn/*(res).ic  /at[el]:aloc
+      //  4.           s1.i1-s2.i2/at[el]:aloc
+      //  5.           s1.i1      /at[el]:aloc
+      //  6.  /mdl
+      //  7.       chn
+      //  8.           s1.i1-s2.i2
+      //  9.           (res)
+      //  10.                      at[el]:aloc
+      //  11.      chn//[el]
+      //
+      //  mdl   - the model's serial number or 0 or '*' for any model
+      //          (default).
+      //  chn   - the chain ID or list of chains 'A,B,C' or '*' for
+      //          any chain (default).
+      //  s1,s2 - the starting and ending residue sequence numbers
+      //          or '*' for any sequence number (default).
+      //  i1,i2 - the residues insertion codes or '*' for any
+      //          insertion code. If the sequence number other than
+      //          '*' is specified, then insertion code defaults to ""
+      //          (no insertion code), otherwise the default is '*'.
+      //  at    - atom name or list of atom names 'CA,N1,O' or '*'
+      //          for any atom name (default)
+      //  el    - chemical element name or list of chemical element
+      //          names 'C,N,O' or '*' for any chemical element name
+      //          (default)
+      //  aloc  - the alternative location indicator or '*' for any
+      //          alternate location. If the atom name and chemical
+      //          element name is specified (both may be '*'), then
+      //          the alternative location indicator defaults to ""
+      //          (no alternate location), otherwise the default is
+      //           '*'.
+      //
+      //  All spaces are ignored.
+      //
+      //  Returns -1 if numerical format of model is wrong, -2 if
+      //  numerical format for sequence number is wrong, and 0
+      //  otherwise.
+
+      int   Select (
+               int   selHnd,    // must be obtained from NewSelection()
+               SELECTION_TYPE sType, // selection type STYPE_XXXXX
+               cpstr CID,       // coordinate ID
+               SELECTION_KEY  sKey   // selection key
+             );
+
+      //  Propagating the selection up and down coordinate hierarchy
+      void  Select (
+               int  selHnd1,  // must be obtained from NewSelection()
+               SELECTION_TYPE sType,  // selection type STYPE_XXXXX
+               int  selHnd2,  // must be obtained from NewSelection()
+                              // and have been used for selection
+               SELECTION_KEY  sKey=SKEY_OR // selection key
+             );
+
+      void  SelectProperty (
+               int  selHnd,   // must be obtained from NewSelection()
+               SELECTION_PROPERTY propKey, // property key SELPROP_XXXXXXX
+               SELECTION_TYPE     sType, // selection type STYPE_XXXXX
+               SELECTION_KEY      sKey   // selection key
+             );
+
+      // In SelectDomain, domainRange is of the following format:
+      //    "*", "(all)"            - take all file
+      //    "-"                     - take chain without chain ID
+      //    "a:Ni-Mj,b:Kp-Lq,..."   - take chain a residue number N
+      //                             insertion code i to residue numberM
+      //                             insertion code j plus chain b
+      //                             residue number K insertion code p to
+      //                             residue number L insertion code q
+      //                             and so on.
+      //    "a:,b:..."              - take whole chains a and b and so on
+      //    "a:,b:Kp-Lq,..."        - any combination of the above.
+      int  SelectDomain ( int selHnd , cpstr domainRange,
+                          SELECTION_TYPE sType,
+                          SELECTION_KEY  sKey,
+                          int modelNo=1 );
+
+      void  DeleteSelObjects ( int selHnd );
+
+
+    protected :
+
+      // --- SELECTION DATA NOT FOR PUBLIC ACCESS
+      int       nSelections;   // number of selections
+      PPMask    mask;          // vector of selections
+      SELECTION_TYPE *selType; // vector of selection types
+      ivector   nSelItems;     // numbers of selected items
+      PPMask *  selection;     // vector of selected items
+
+      //  ---------------  Stream I/O  -----------------------------
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+      void  InitSelManager();
+      void  SelectAtom    ( PAtom   atm,  int maskNo,
+                            SELECTION_KEY  sKey,  int &  nsel );
+      void  SelectObject  ( SELECTION_TYPE sType, PAtom atm,
+                            int maskNo, SELECTION_KEY sKey,
+                            int &  nsel );
+      void  SelectObject  ( PMask object,  int maskNo,
+                            SELECTION_KEY sKey, int & nsel );
+      void  MakeSelIndex  ( int selHnd,  SELECTION_TYPE sType,
+                            int nsel );
+
+      void  ResetManager();
+
+      PMask GetSelMask ( int selHnd );
+
+  };
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_seqsuperpose.cpp b/mmdb2/mmdb_seqsuperpose.cpp
new file mode 100755
index 0000000..7489850
--- /dev/null
+++ b/mmdb2/mmdb_seqsuperpose.cpp
@@ -0,0 +1,366 @@
+//  $Id: mmdb_seqsuperpose.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    19.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  SeqSuperpose <implementation>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::SeqSuperpose
+//       ~~~~~~~~~
+//
+//  (C) E.Krissinel  2005-2013
+//
+//  =================================================================
+//
+
+#include <math.h>
+#include <string.h>
+
+#include "mmdb_tables.h"
+#include "mmdb_seqsuperpose.h"
+
+namespace mmdb  {
+
+  //  =================================================================
+
+  SeqSuperpose::SeqSuperpose()  {
+    SeqSuperposeInit();
+  }
+
+  SeqSuperpose::~SeqSuperpose()  {
+    FreeMemory();
+  }
+
+  void  SeqSuperpose::SeqSuperposeInit()  {
+    Align  = NULL;
+    Mat4Init ( TMatrix ); // superposes Ca1 over Ca2: |T*Ca1 - Ca2|->min
+    Q      = -0.5;        // Q-score
+    rmsd   = MaxReal;     // rmsd
+    seqId  = MaxReal;     // sequence identity
+    _seqId = 0.0;         // sequence identity in sequence alignment
+    Nalign = 0;           // alignment length
+    c1     = NULL;        // sup-n vector: Ca1[i]->Ca2[c1[i]] if c1[i]>=0
+    c2     = NULL;        // sup-n vector: Ca2[i]->Ca1[c2[i]] if c2[i]>=0
+    cn1    = NULL;        // temporary contact array #1
+    cn2    = NULL;        // temporary contact array #2
+    Rmsd0  = 3.0;         // quality optimization parameter
+    maxContact = 15.0;    // maximal Calpha-pair contact parameter
+    contact    = NULL;
+    ncontacts  = 0;
+  }
+
+  void  SeqSuperpose::FreeMemory()  {
+    if (Align)  {
+      delete Align;
+      Align = NULL;
+    }
+    FreeVectorMemory ( c1 ,0 );
+    FreeVectorMemory ( c2 ,0 );
+    FreeVectorMemory ( cn1,0 );
+    FreeVectorMemory ( cn2,0 );
+    if (contact)  {
+      delete[] contact;
+      contact = NULL;
+    }
+    ncontacts = 0;
+  }
+
+  void  makeAAString ( pstr & S, PPAtom C, int nat )  {
+  pstr    rname;
+  ResName r1;
+  int     i,j;
+    S = new char[nat+1];
+    j = 0;
+    for (i=0;i<nat;i++)
+      if (C[i])  {
+        rname = C[i]->GetResName();
+        if (rname)  {
+          Get1LetterCode ( rname,r1 );
+          S[j++] = r1[0];
+        }
+      }
+    S[j] = char(0);
+  }
+
+
+  realtype  SeqSuperpose::MatchQuality ( int Nalign, realtype Rmsd,
+                                         int nres1,  int nres2 )  {
+    if (Nalign==0)  return 0.0;
+    return MatchQuality2 ( Nalign,Rmsd*Rmsd*Nalign,nres1,nres2 );
+  }
+
+  realtype  SeqSuperpose::MatchQuality2 ( int Nalign, realtype dist2,
+                                          int nres1,  int nres2 ) {
+  realtype  NormN,Na2,NormR;
+    NormN = nres1*nres2;
+    if (NormN<=0.0) return 0.0;
+    Na2   = Nalign*Nalign;
+    NormR = dist2/(Nalign*Rmsd0*Rmsd0);
+    return  Na2/((1.0+NormR)*NormN);
+  }
+
+
+  void  SeqSuperpose::MakeContacts ( mat44 & TM, realtype cont_est ) {
+  //  Find the closest contacts atoms and makes the correspondence
+  //  vectors cn1 and cn2
+  int  i,j,i1,i2;
+
+    //  1. Find all contacts in the range of 0.0 - cont_est
+    if (contact)  {
+      delete[] contact;
+      contact = NULL;
+    }
+    ncontacts = 0;
+    M->SeekContacts ( Ca2,nCa2,Ca1,nCa1,0.0,cont_est,0,
+                      contact,ncontacts,0,&TM,0,
+                      BRICK_ON_1 | BRICK_READY );
+
+    //  2. Leave only unique shortest contacts, that is, if Ca1[i]-Ca2[j]
+    //     is the shortest contact for atom Ca1[i], it has also to be
+    //     the shortest contact for atom Ca2[j].
+
+    if (ncontacts>0)  {
+
+      SortContacts ( contact,ncontacts,CNSORT_DINC );
+
+      for (i=0;i<nCa1;i++)
+        cn1[i] = -1;
+      for (i=0;i<nCa2;i++)
+        cn2[i] = -1;
+
+      j = 0;
+      for (i=0;i<ncontacts;i++)  {
+        i1 = contact[i].id2;
+        i2 = contact[i].id1;
+        if ((cn1[i1]<0) && (cn2[i2]<0))  {
+          // We only check for unmapped atoms in this version, so that
+          // chain misdirection and wide-angle contacts are accepted.
+          // However, the method itself is meant to be used only with
+          // highly similar chains, so we do not expect difficulties
+          // here. Our purpose here is to get maximum performance at
+          // high-quality input. See SSM code for more rigorous contact
+          // building.
+          if (j<i)  contact[j].Copy ( contact[i] );
+          // close contact
+          cn1[i1] = i2;
+          cn2[i2] = i1;
+          j++;
+        }
+      }
+
+      ncontacts = j;
+
+    }
+
+  }
+
+  int  SeqSuperpose::makeStructAlignment ( realtype seqThreshold,
+                                           bool  keepBricks )  {
+  pstr     S,T;
+  mat44    TM;
+  realtype dist2,maxRMSD2,Q1,Q0,dist20;
+  int      i,i1,i2,nal,rc,iter,iter1;
+  char     Space;
+
+    S = Align->GetAlignedS();
+    T = Align->GetAlignedT();
+
+    GetVectorMemory ( cn1,nCa1,0 );
+    GetVectorMemory ( c1 ,nCa1,0 );
+    for (i=0;i<nCa1;i++)  {
+      cn1[i] = -1;
+      c1 [i] = -1;
+    }
+    GetVectorMemory ( cn2,nCa2,0 );
+    GetVectorMemory ( c2 ,nCa2,0 );
+    for (i=0;i<nCa2;i++)  {
+      cn2[i] = -1;
+      c2 [i] = -1;
+    }
+
+    i  = 0;
+    i1 = 0;
+    i2 = 0;
+    Space = Align->GetSpace();
+    while (S[i] && (i1<nCa1) && (i2<nCa2))  {
+      if ((S[i]==Space) && (T[i]!=Space))      i2++;
+      else if ((S[i]!=Space) && (T[i]==Space)) i1++;
+      else  {
+        if (S[i]==T[i])  {
+          cn1[i1] = i2;
+          cn2[i2] = i1;
+          _seqId += 1.0;
+        }
+        i1++;
+        i2++;
+      }
+      i++;
+    }
+
+    _seqId /= IMax(nCa1,nCa2);
+
+    if (_seqId<seqThreshold)  {
+      FreeVectorMemory ( cn1,0 );
+      FreeVectorMemory ( cn2,0 );
+      return SEQSP_SeqThreshold;
+    }
+
+    maxRMSD2 = maxContact*maxContact;
+
+    if ((!keepBricks) || (!M->areBricks()))
+      M->MakeBricks ( Ca2,nCa2,1.25*maxContact );
+
+    Q     = -1.0;
+    Q0    = -1.0;
+    iter  = 0;
+    iter1 = 0;
+
+    do  {
+
+      Q = RMax ( Q,Q0 );
+      iter++;
+
+      rc = SuperposeAtoms ( TM,Ca1,nCa1,Ca2,cn1 );
+
+      if (rc==SPOSEAT_Ok)  {
+
+        MakeContacts ( TM,maxContact );
+
+        dist2 = 0.0;
+        for (i=0;i<ncontacts;i++)  {
+          contact[i].dist *= contact[i].dist;
+          dist2 += contact[i].dist;
+        }
+
+        dist20 = dist2;
+        nal    = ncontacts;
+        Q0     = RMax ( Q0,MatchQuality2(ncontacts,dist2,nCa1,nCa2) );
+        if (ncontacts>0)  {
+          i = ncontacts;
+          while (i>3)  {
+            i--;
+            dist2 -= contact[i].dist;
+            if (dist2<=i*maxRMSD2)  { // rmsd must be within the limits
+              Q1 = MatchQuality2 ( i,dist2,nCa1,nCa2 );
+              if (Q1>Q0)  {
+                Q0     = Q1;
+                nal    = i;
+                dist20 = dist2;
+              }
+            }
+          }
+          for (i=nal+1;i<ncontacts;i++)  {
+            cn1[contact[i].id2] = -1;
+            cn2[contact[i].id1] = -1;
+          }
+          if (Q0>Q)  {
+            for (i=0;i<nCa1;i++)
+              c1[i] = cn1[i];
+            for (i=0;i<nCa2;i++)
+              c2[i] = cn2[i];
+            Mat4Copy ( TM,TMatrix );
+            Nalign = nal;
+            rmsd   = dist20;
+            iter1  = 0;
+          } else
+            iter1++;
+        }
+
+      }
+
+      if ((!rc) && (iter>100))  rc = SEQSP_IterLimit;
+
+    } while ((rc==SPOSEAT_Ok) && ((Q<Q0) || (iter1>=2)));
+
+    if (Nalign>0)  {
+      SuperposeAtoms ( TMatrix,Ca1,nCa1,Ca2,c1 );
+      rmsd  = sqrt(rmsd/Nalign);  // rmsd
+      seqId = 0.0;
+      for (i=0;i<nCa1;i++)
+        if (c1[i]>=0)  {
+          if (!strcasecmp(Ca1[i]->GetResName(),Ca2[c1[i]]->GetResName()))
+            seqId += 1.0;
+        }
+      seqId = seqId/Nalign;
+    } else  {
+      rmsd  = MaxReal;
+      seqId = 0.0;
+    }
+
+    FreeVectorMemory ( cn1,0 );
+    FreeVectorMemory ( cn2,0 );
+
+    if (!keepBricks)  M->RemoveBricks();
+
+    return rc;
+
+  }
+
+
+  int  SeqSuperpose::Superpose ( PManager MMDB,
+                                 PPAtom   Calpha1, int nCalpha1,
+                                 PPAtom   Calpha2, int nCalpha2,
+                                 realtype seqThreshold,
+                                 bool     keepBricks )  {
+  pstr S,T;
+
+    Mat4Init ( TMatrix ); // superposes Ca1 over Ca2: |T*Ca1 - Ca2|->min
+    Q       = 0.0;        // Q-score
+    rmsd    = MaxReal;    // rmsd
+    seqId   = MaxReal;    // sequence identity in structure alignment
+    Nalign  = 0;          // alignment length in structure alignment
+
+    FreeVectorMemory ( c1,0 );
+    FreeVectorMemory ( c2,0 );
+
+    _seqId  = IMin(nCalpha1,nCalpha2);
+    _seqId /= IMax(nCalpha1,nCalpha2);
+
+    if (_seqId<seqThreshold)
+      return SEQSP_SeqThreshold;
+
+    M    = MMDB;
+    Ca1  = Calpha1;
+    nCa1 = nCalpha1;
+    Ca2  = Calpha2;
+    nCa2 = nCalpha2;
+
+    makeAAString ( S,Ca1,nCa1 );
+    makeAAString ( T,Ca2,nCa2 );
+
+    if (!Align)  Align = new math::Alignment();
+
+    Align->Align ( S,T,math::ALIGN_FREEENDS );
+
+    if (S) delete[] S;
+    if (T) delete[] T;
+
+    return makeStructAlignment ( seqThreshold,keepBricks );
+
+  }
+
+}  // namespace mmdb
+
diff --git a/mmdb2/mmdb_seqsuperpose.h b/mmdb2/mmdb_seqsuperpose.h
new file mode 100755
index 0000000..f841dea
--- /dev/null
+++ b/mmdb2/mmdb_seqsuperpose.h
@@ -0,0 +1,134 @@
+//  $Id: mmdb_seqsuperpose.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    19.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  SeqSuperpose <interface>
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::SeqSuperpose
+//       ~~~~~~~~~
+//
+//  (C) E.Krissinel  2005-2013
+//
+//  =================================================================
+//
+
+#ifndef  __Seq_Superpose__
+#define  __Seq_Superpose__
+
+#include "mmdb_manager.h"
+#include "mmdb_math_align.h"
+
+namespace mmdb  {
+
+  //  =================================================================
+
+  enum SEQSP_RC  {
+    SEQSP_Ok           =   0,
+    SEQSP_IterLimit    = 100,
+    SEQSP_SeqThreshold = 101
+  };
+
+  DefineClass(SeqSuperpose);
+
+  class SeqSuperpose  {
+
+    public :
+      mat44    TMatrix;  // superposes Ca1 over Ca2: |T*Ca1 - Ca2|->min
+      realtype Q;        // Q-score
+      realtype rmsd;     // rmsd
+      realtype seqId;    // sequence identity in structure alignment
+      realtype _seqId;   // sequence identity in sequence alignment
+      int      Nalign;   // alignment length in structure alignment
+      ivector  c1;       // sup-n vector: Ca1[i]->Ca2[c1[i]] if c1[i]>=0
+      ivector  c2;       // sup-n vector: Ca2[i]->Ca1[c2[i]] if c2[i]>=0
+
+      SeqSuperpose();
+      ~SeqSuperpose();
+
+      //   Given two sets of atoms, Calpha1 and Calpha2, Superpose(...)
+      // calculates the rotational-translational matrix TMatrix such
+      // that |TMatrix*Calpha1 - Calpha2| is minimal in least-square
+      // terms.
+      //   In difference of a full-scale SSM, this simplified version
+      // uses initial superposition from sequence alignment, hence
+      // it should be applied only to similar chains where calculation
+      // time is crucial. seqThreshold specifies a threshold of
+      // sequence identity (0<=seqThreshold<=1), below which
+      // structural alignment is not performed and Superpose(..)
+      // returns SEQSP_SeqThreshold.
+      //
+      //   If keepBricks is set True, then space bricks are not
+      // removed in MMDB and may be used in the next call if
+      // vector Calpha2 does not change. This saves computation
+      // time.
+      //
+      //   The alignment results return in public fields above:
+      //     TMatrix  - transformation matrix (1 if not aligned)
+      //     Q        - quality Q-score (-1 if not aligned)
+      //     rmsd     - r.m.s.d (MaxReal if not aligned)
+      //     seqId    - sequence identity in structure alignment
+      //                        (0 if not aligned)
+      //     Nalign   - alignment length in structure alignment
+      //                        (0 if not aligned)
+      //     c1,c2    - atom corrspondences:
+      //                Calpha1[i] <=> Calpha2[c1[i]]
+      //                Calpha2[i] <=> Calpha1[c2[i]]
+      //
+      // Upon success, Superpose(...) returns SEQSP_Ok
+      //
+      int Superpose ( PManager MMDB,
+                      PPAtom   Calpha1, int nCalpha1,
+                      PPAtom   Calpha2, int nCalpha2,
+                      realtype seqThreshold,
+                      bool     keepBricks );
+
+    protected :
+      math::PAlignment Align;
+      PManager    M;        // pointers to
+      PPAtom      Ca1,Ca2;    //   the input data
+      int         nCa1,nCa2;  // copy chain lengths
+      ivector     cn1,cn2;    // temporary contact arrays
+      realtype    Rmsd0;      // quality optimization parameter
+      realtype    maxContact; // maximal Calpha-pair contact parameter
+      PContact    contact;
+      int         ncontacts;
+
+      void SeqSuperposeInit();
+      void FreeMemory      ();
+      realtype  MatchQuality   ( int Nalign, realtype Rmsd,
+                                 int nres1,  int nres2  );
+      realtype  MatchQuality2  ( int Nalign, realtype dist2,
+                                 int nres1,  int nres2  );
+      void MakeContacts        ( mat44 & TM, realtype cont_est );
+      int  makeStructAlignment ( realtype seqThreshold,
+                                 bool     keepBricks );
+
+  };
+
+}  // namespace mmdb
+
+#endif
diff --git a/mmdb2/mmdb_symop.cpp b/mmdb2/mmdb_symop.cpp
new file mode 100644
index 0000000..4b8198d
--- /dev/null
+++ b/mmdb2/mmdb_symop.cpp
@@ -0,0 +1,1001 @@
+//  $Id: mmdb_symop.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDB_SymOp <implementation>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::SymOp  ( symmetry operators )
+//       ~~~~~~~~~   mmdb::SymOps ( container of symmetry operators )
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "mmdb_symop.h"
+
+namespace mmdb  {
+
+  //  ====================  SymOp  ========================
+
+  SymOp::SymOp() : io::Stream()  {
+    InitSymOp();
+  }
+
+  SymOp::SymOp ( io::RPStream Object ) : io::Stream(Object)  {
+    InitSymOp();
+  }
+
+  SymOp::~SymOp()  {
+    FreeMemory();
+  }
+
+  void SymOp::InitSymOp()  {
+  int i,j;
+    XYZOp = NULL;
+    for (i=0;i<4;i++)  {
+      for (j=0;j<4;j++)
+        T[i][j] = 0.0;
+      T[i][i] = 1.0;
+    }
+  }
+
+  void SymOp::FreeMemory()  {
+    if (XYZOp)  delete[] XYZOp;
+    XYZOp = NULL;
+  }
+
+  int  SymOp::SetSymOp ( cpstr XYZOperation )  {
+  int  i,j;
+
+    CreateCopy ( XYZOp,XYZOperation );
+    DelSpaces  ( XYZOp );
+
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        T[i][j] = 0.0;
+
+    i = GetOperation ( 0 );
+    if (!i) i = GetOperation ( 1 );
+    if (!i) i = GetOperation ( 2 );
+    T[3][3] = 1.0;
+
+    return i;
+
+  }
+
+  pstr SymOp::GetSymOp()  {
+    if (XYZOp)  return XYZOp;
+          else  return pstr("");
+  }
+
+
+  int  SymOp::GetOperation ( int n )  {
+  char     L[100];
+  pstr     p1,p2;
+  int      len;
+  realtype V;
+
+    p1 = XYZOp;
+    p2 = strchr ( p1,',' );
+    if (!p2)  return SYMOP_WrongSyntax;
+    if (n>0)  {
+      p1 = p2+1;
+      p2 = strchr ( p1,',' );
+      if (!p2)  return SYMOP_WrongSyntax;
+    }
+    if (n>1)  {
+      p1 = p2+1;
+      p2 = NULL;
+    }
+
+    if (p2)  *p2 = char(0);
+    strcpy ( L,p1 );
+    if (p2)  *p2 = ',';
+
+    DelSpaces ( L );
+    if (!L[0])  return SYMOP_WrongSyntax;
+    UpperCase ( L );
+
+    len = strlen ( L );
+    T[n][0] = 0.0;
+    if (L[0]=='X')  {
+      T[n][0] += 1.0;
+      L[0] = ' ';
+    }
+    do  {
+      p1 = strstr ( L,"+X" );
+      if (p1)  {
+        T[n][0] += 1.0;
+        strncpy ( p1,"  ",2 );
+      }
+    } while (p1);
+    do  {
+      p1 = strstr ( L,"-X" );
+      if (p1)  {
+        T[n][0] -= 1.0;
+        strncpy ( p1,"  ",2 );
+      }
+    } while (p1);
+
+    T[n][1] = 0.0;
+    if (L[0]=='Y')  {
+      T[n][1] += 1.0;
+      L[0] = ' ';
+    }
+    do  {
+      p1 = strstr ( L,"+Y" );
+      if (p1)  {
+        T[n][1] += 1.0;
+        strncpy ( p1,"  ",2 );
+      }
+    } while (p1);
+    do  {
+      p1 = strstr ( L,"-Y" );
+      if (p1)  {
+        T[n][1] -= 1.0;
+        strncpy ( p1,"  ",2 );
+      }
+    } while (p1);
+
+    T[n][2] = 0.0;
+    if (L[0]=='Z')  {
+      T[n][2] += 1.0;
+      L[0] = ' ';
+    }
+    do  {
+      p1 = strstr ( L,"+Z" );
+      if (p1)  {
+        T[n][2] += 1.0;
+        strncpy ( p1,"  ",2 );
+      }
+    } while (p1);
+    do  {
+      p1 = strstr ( L,"-Z" );
+      if (p1)  {
+        T[n][2] -= 1.0;
+        strncpy ( p1,"  ",2 );
+      }
+    } while (p1);
+
+    DelSpaces ( L );
+    if ((int)strlen(L)>=len)  return SYMOP_NotAnOperation;
+
+    // translational part
+    p1 = L;
+    T[n][3] = strtod ( p1,&p2 );
+    if (*p2=='/')  {
+      p1 = p2+1;
+      V  = strtod ( p1,&p2 );
+      if (V==0.0)  return SYMOP_ZeroDenominator;
+      T[n][3] /= V;
+    }
+
+    return SYMOP_Ok;
+
+  }
+
+  void  MakeSign ( pstr S, realtype V, realtype & AV )  {
+  int      l;
+    if (V>0.0)  {
+      l = strlen ( S );
+      if (l>0)  {
+        if (S[l-1]!=',')  {
+          strcat ( S,"+" );
+        }
+      }
+      AV = V;
+    } else if (V<0.0)  {
+      strcat ( S,"-" );
+      AV = -V;
+    } else  {
+      AV = V;
+      return;
+    }
+  }
+
+
+  #define  __eps  1.0e-5
+
+  void  GenTranslation ( pstr S, realtype V )  {
+  realtype AV,nAV;
+  char     N[50];
+  int      n,d;
+
+    if (fabs(V)<=__eps)  return;
+    MakeSign ( S,V,AV );
+
+    d = 0;
+    n = -1;
+    while ((d<=20) && (n<0))  {
+      d++;
+      nAV = AV*d;
+      n   = mround(nAV);
+      if (fabs(nAV-n)>__eps)  n = -1;
+    }
+
+    if (d<=1)      sprintf ( N,"%i"    ,n   );
+    else if (n>=0) sprintf ( N,"%i/%i" ,n,d );
+              else sprintf ( N,"%-.10g",AV  );
+    strcat ( S,N );
+
+  }
+
+  void  GenTransformation ( pstr S, realtype V, pstr Axis ) {
+  realtype AV,nAV;
+  char     N[50];
+  int      n,d;
+
+    if (fabs(V)<=__eps)  return;
+    MakeSign ( S,V,AV );
+
+    if (fabs(AV-1.0)>__eps)  {
+
+      d = 0;
+      n = -1;
+      while ((d<=20) && (n<0))  {
+        d++;
+        nAV = AV*d;
+        n   = mround(nAV);
+        if (fabs(nAV-n)>__eps)  n = -1;
+      }
+
+      if (n>=0)  sprintf ( N,"%i/%i*",n,d );
+           else  sprintf ( N,"%-.10g*",AV );
+      strcat ( S,N );
+
+    }
+
+    strcat ( S,Axis );
+
+  }
+
+
+  /*
+  void  GenTranslation ( pstr S, realtype V )  {
+  realtype AV,fAV;
+  int      n,d;
+  char     N[50];
+
+    if (V==0.0)  return;
+    MakeSign ( S,V,AV );
+
+    n = mround(floor(AV+0.00000001));
+    fAV = AV-n;
+
+    if (fabs(fAV-0.5)<=__eps)                 { n += 1;  d = 2; }
+    else if (fabs(fAV-0.25)<=__eps)           { n += 1;  d = 4; }
+    else if (fabs(fAV-0.75)<=__eps)           { n += 3;  d = 4; }
+    else if (fabs(fAV-0.33333333333)<=__eps)  { n += 1;  d = 3; }
+    else if (fabs(fAV-0.66666666666)<=__eps)  { n += 2;  d = 3; }
+    else if (fabs(fAV-0.16666666666)<=__eps)  { n += 1;  d = 6; }
+    else if (fabs(fAV-0.83333333333)<=__eps)  { n += 5;  d = 6; }
+                                        else  d = 1;
+
+    N[0] = char(0);
+    if (d>1)       sprintf  ( N,"%i/%i",n,d );
+    else if (n>0)  sprintf  ( N,"%i",n );
+             else  ParamStr ( N,pstr(""),AV );
+    strcat ( S,N );
+
+  }
+
+  void  GenTransformation ( pstr S, realtype V, pstr Axis ) {
+  realtype AV;
+
+    if (V==0.0)  return;
+    MakeSign ( S,V,AV );
+
+    if (fabs(AV-0.5)<=__eps)                 strcat   ( S,"1/2*" );
+    else if (fabs(AV-0.25)<=__eps)           strcat   ( S,"1/4*" );
+    else if (fabs(AV-0.75)<=__eps)           strcat   ( S,"3/4*" );
+    else if (fabs(AV-0.33333333333)<=__eps)  strcat   ( S,"1/3*" );
+    else if (fabs(AV-0.66666666666)<=__eps)  strcat   ( S,"2/3*" );
+    else if (fabs(AV-0.16666666666)<=__eps)  strcat   ( S,"1/6*" );
+    else if (fabs(AV-0.83333333333)<=__eps)  strcat   ( S,"5/6*" );
+    else if (fabs(AV-1.0)>__eps)             ParamStr ( S,pstr(""),AV,
+                                                        10,pstr("*") );
+
+    strcat ( S,Axis );
+
+  }
+
+  */
+
+  bool  SymOp::CompileOpTitle ( pstr S )  {
+    return CompileOpTitle ( S,T,true );
+  }
+
+  bool  SymOp::CompileOpTitle ( pstr S, mat44 symMat,
+                                    bool compare )  {
+    S[0] = char(0);
+    GenTransformation ( S,symMat[0][0],pstr("X") );
+    GenTransformation ( S,symMat[0][1],pstr("Y") );
+    GenTransformation ( S,symMat[0][2],pstr("Z") );
+    GenTranslation    ( S,symMat[0][3]           );
+    strcat ( S,"," );
+    GenTransformation ( S,symMat[1][0],pstr("X") );
+    GenTransformation ( S,symMat[1][1],pstr("Y") );
+    GenTransformation ( S,symMat[1][2],pstr("Z") );
+    GenTranslation    ( S,symMat[1][3]           );
+    strcat ( S,"," );
+    GenTransformation ( S,symMat[2][0],pstr("X") );
+    GenTransformation ( S,symMat[2][1],pstr("Y") );
+    GenTransformation ( S,symMat[2][2],pstr("Z") );
+    GenTranslation    ( S,symMat[2][3]           );
+    DelSpaces ( S );
+    if ((!compare) || (!strcmp(S,XYZOp)))  return true;
+    else  {
+      S[0] = char(0);
+      GenTranslation    ( S,symMat[0][3]           );
+      GenTransformation ( S,symMat[0][0],pstr("X") );
+      GenTransformation ( S,symMat[0][1],pstr("Y") );
+      GenTransformation ( S,symMat[0][2],pstr("Z") );
+      strcat ( S,"," );
+      GenTranslation    ( S,symMat[1][3]           );
+      GenTransformation ( S,symMat[1][0],pstr("X") );
+      GenTransformation ( S,symMat[1][1],pstr("Y") );
+      GenTransformation ( S,symMat[1][2],pstr("Z") );
+      strcat ( S,"," );
+      GenTranslation    ( S,symMat[2][3]           );
+      GenTransformation ( S,symMat[2][0],pstr("X") );
+      GenTransformation ( S,symMat[2][1],pstr("Y") );
+      GenTransformation ( S,symMat[2][2],pstr("Z") );
+      DelSpaces ( S );
+      if (!strcmp(S,XYZOp))  return true;
+    }
+    return false;
+  }
+
+  void  SymOp::Transform ( realtype & x, realtype & y, realtype & z )  {
+  realtype x1,y1,z1;
+    x1 = T[0][0]*x + T[0][1]*y + T[0][2]*z + T[0][3];
+    y1 = T[1][0]*x + T[1][1]*y + T[1][2]*z + T[1][3];
+    z1 = T[2][0]*x + T[2][1]*y + T[2][2]*z + T[2][3];
+    x = x1;
+    y = y1;
+    z = z1;
+  }
+
+  void  SymOp::GetTMatrix ( mat44 & TMatrix )  {
+  // copies T to TMatrix
+  int i,j;
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        TMatrix[i][j] = T[i][j];
+  }
+
+  void  SymOp::SetTMatrix ( mat44 & TMatrix )  {
+  // copies TMatrix to T
+  int i,j;
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        T[i][j] = TMatrix[i][j];
+  }
+
+
+  void  SymOp::Print()  {
+  int i;
+    printf ( "  operation '%s'\n",XYZOp );
+    for (i=0;i<4;i++)
+      printf ( "               %10.3g %10.3g %10.3g  %10.3g\n",
+               T[i][0],T[i][1],T[i][2],T[i][3] );
+  }
+
+  void  SymOp::Copy ( PSymOp SymOp )  {
+  int i,j;
+    CreateCopy ( XYZOp,SymOp->XYZOp );
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        T[i][j] = SymOp->T[i][j];
+  }
+
+  void  SymOp::write ( io::RFile f )  {
+  int  i,j;
+  byte Version=1;
+    f.WriteByte   ( &Version );
+    f.CreateWrite ( XYZOp    );
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        f.WriteReal ( &(T[i][j]) );
+  }
+
+  void  SymOp::read ( io::RFile f )  {
+  int  i,j;
+  byte Version;
+    f.ReadByte   ( &Version );
+    f.CreateRead ( XYZOp    );
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        f.ReadReal ( &(T[i][j]) );
+  }
+
+  MakeStreamFunctions(SymOp)
+
+
+
+  //  ====================  SymOps  ========================
+
+  SymOps::SymOps() : io::Stream()  {
+    InitSymOps();
+  }
+
+  SymOps::SymOps ( io::RPStream Object ) : io::Stream(Object)  {
+    InitSymOps();
+  }
+
+  SymOps::~SymOps()  {
+    FreeMemory();
+  }
+
+  void SymOps::InitSymOps()  {
+    SpGroup = NULL;
+    Nops    = 0;
+    symOp   = NULL;
+  }
+
+  void SymOps::FreeMemory()  {
+  int i;
+    if (SpGroup)  delete[] SpGroup;
+    SpGroup = NULL;
+    if (symOp)  {
+      for (i=0;i<Nops;i++)
+        if (symOp[i])  delete symOp[i];
+      delete[] symOp;
+      symOp = NULL;
+    }
+    Nops = 0;
+  }
+
+  #define  symop_file  cpstr("symop.lib")
+
+  int  SymOps::SetGroupSymopLib ( cpstr SpaceGroup,
+                                  cpstr symop_lib )  {
+  char     S[500];
+  char     G[100];
+  pstr     p;
+  io::File f;
+  int      i,RC;
+
+    FreeMemory();
+
+    CreateCopy ( SpGroup,SpaceGroup );
+
+    if (!symop_lib)          p = pstr(symop_file);
+    else if (!symop_lib[0])  p = pstr(symop_file);
+                       else  p = pstr(symop_lib);
+    f.assign ( p,true );
+    if (!f.reset(true))  {
+      p = getenv ( "SYMOP" );
+      if (p)
+        strcpy ( S,p );
+      else  {
+        p = getenv ( "CLIBD" );
+        if (p)  {
+          strcpy ( S,p );
+          if (S[strlen(S)-1]!='/')  strcat ( S,"/" );
+          strcat ( S,"symop.lib" );
+        } else
+          strcpy ( S,"symop.lib" );
+      }
+      f.assign ( S,true );
+      if (!f.reset(true))  return SYMOP_NoLibFile;
+    }
+
+    strcpy ( G," '"    );
+    strcat ( G,SpGroup );
+    strcat ( G,"'"     );
+    S[0] = char(0);
+    while (!f.FileEnd() && (!strstr(S,G)))
+      f.ReadLine ( S,sizeof(S) );
+    if (f.FileEnd())  {
+      f.shut();
+      return SYMOP_UnknownSpaceGroup;
+    }
+
+    p = S;
+    while (*p==' ')  p++;
+    p = strchr ( p,' ' );
+    if (p)  Nops = mround(strtod(p,NULL));
+    if (Nops<=0)  return SYMOP_NoSymOps;
+
+    symOp = new PSymOp[Nops];
+    RC    = SYMOP_Ok;
+    for (i=0;(i<Nops) && (!RC);i++)  {
+      f.ReadLine ( S,sizeof(S) );
+      symOp[i] = new SymOp();
+      RC = symOp[i]->SetSymOp ( S );
+    }
+
+    f.shut();
+
+    return RC;
+
+  }
+
+
+  #define  syminfo_file  cpstr("syminfo.lib")
+
+  int  SymOps::SetGroup ( cpstr SpaceGroup,
+                           cpstr syminfo_lib )  {
+  io::File f;
+  pstr     p;
+  psvector lines,lines1;
+  char     S[500];
+  char     G[100];
+  char     O[100];
+  mat44    T1,T2,T3;
+  int      i,j,k,l,m,n,RC;
+  int      nlines,npops,ncops;
+
+    FreeMemory();
+
+    npops = 0;
+    ncops = 0;
+
+    CreateCopy ( SpGroup,SpaceGroup );
+
+    if (!syminfo_lib)          p = pstr(syminfo_file);
+    else if (!syminfo_lib[0])  p = pstr(syminfo_file);
+                         else  p = pstr(syminfo_lib);
+    f.assign ( p,true );
+    if (!f.reset(true))  {
+      p = getenv ( "SYMINFO" );
+      if (p)
+        strcpy ( S,p );
+      else  {
+        p = getenv ( "CLIBD" );
+        if (p)  {
+          strcpy ( S,p );
+          if (S[strlen(S)-1]!='/')  strcat ( S,"/" );
+          strcat ( S,"syminfo.lib" );
+        } else
+          strcpy ( S,"syminfo.lib" );
+      }
+      f.assign ( S,true );
+      if (!f.reset(true))  return SYMOP_NoLibFile;
+    }
+
+
+    if (strncasecmp(SpGroup,"Hall:",5))  {
+      // normal space group symbol on input
+      strcpy ( G," '"    );
+      strcat ( G,SpGroup );
+      strcat ( G,"'"     );
+      S[0] = char(0);
+      while (!f.FileEnd() && !(strstr(S,G) && (strstr(S,"symbol xHM") ||
+              strstr(S,"symbol old"))))
+        f.ReadLine ( S,sizeof(S) );
+    } else  {
+      // hall descriptor on input
+      strcpy ( G," ' " );
+      p = &(SpGroup[5]);
+      while (*p==' ')  p++;
+      strcat ( G,p     );
+      strcat ( G,"'"   );
+      S[0] = char(0);
+      while (!f.FileEnd() && !(strstr(S,G) && strstr(S,"symbol Hall")))
+        f.ReadLine ( S,sizeof(S) );
+    }
+    if (f.FileEnd())  {
+      f.shut();
+      return SYMOP_UnknownSpaceGroup;
+    }
+
+    // found spacegroup, move to symop lines
+    while (!f.FileEnd() && (!strstr(S,"symop")))
+      f.ReadLine ( S,sizeof(S) );
+
+    nlines = 256;
+    GetVectorMemory ( lines,nlines,0 );
+    for (i=0;i<nlines;i++)
+      lines[i] = NULL;
+    n = 0;
+    CreateCopy ( lines[n++],S );
+
+    // count primitive operators
+    while (!f.FileEnd() && (strstr(S,"symop"))) {
+      npops++;
+      f.ReadLine ( S,sizeof(S) );
+      if (n>=nlines)  {
+        nlines += + 256;
+        GetVectorMemory ( lines1,nlines,0 );
+        for (i=0;i<n;i++)
+          lines1[i] = lines[i];
+        for (i=n;i<nlines;i++)
+          lines1[i] = NULL;
+        FreeVectorMemory ( lines,0 );
+        lines = lines1;
+      }
+      CreateCopy ( lines[n++],S );
+    }
+
+    // count centering operators
+    while (!f.FileEnd() && (strstr(S,"cenop"))) {
+      ncops++;
+      f.ReadLine ( S,sizeof(S) );
+      if (n>=nlines)  {
+        nlines += + 256;
+        GetVectorMemory ( lines1,nlines,0 );
+        for (i=0;i<n;i++)
+          lines1[i] = lines[i];
+        for (i=n;i<nlines;i++)
+          lines1[i] = NULL;
+        FreeVectorMemory ( lines,0 );
+        lines = lines1;
+      }
+      CreateCopy ( lines[n++],S );
+    }
+
+    Nops = npops*ncops;
+    symOp = new PSymOp[Nops];
+    RC    = SYMOP_Ok;
+
+    n = 0;  // start second pass here
+
+    // read primitive operators
+    for (i=0;(i<npops) && (!RC);i++)  {
+      symOp[i] = new SymOp();
+      RC = symOp[i]->SetSymOp ( lines[n++]+6 );
+    }
+
+    // loop over non-trivial centering operators, and for each loop
+    // over primtive operators
+    for (i=1;(i<ncops) && (!RC);i++)  {
+      n++;  // this also skips the identity operator
+      for (j=0;(j<npops) && (!RC);j++)  {
+        symOp[i*npops+j] = new SymOp();
+        RC = symOp[i*npops+j]->SetSymOp ( lines[n]+6 );
+        symOp[i*npops+j]->GetTMatrix(T1);
+        symOp[j]->GetTMatrix(T2);
+        for (k=0;k<4;k++)
+          for (l=0;l<4;l++) {
+            T3[k][l] = 0.0;
+            for (m=0;m<4;m++)
+              T3[k][l] += T1[k][m]*T2[m][l];
+          }
+        for (k=0;k<3;k++)                  // kdc fix
+          T3[k][3] -= floor ( T3[k][3] );  // kdc fix
+        symOp[i*npops+j]->CompileOpTitle ( O,T3,false );
+        symOp[i*npops+j]->SetSymOp ( O );
+      }
+    }
+
+    f.shut();
+
+    for (i=0;i<nlines;i++)
+      if (lines[i])  delete[] lines[i];
+    FreeVectorMemory ( lines,0 );
+
+    return RC;
+
+  }
+
+  /*
+  int  SymOps::SetGroup ( cpstr SpaceGroup,
+                           cpstr syminfo_lib )  {
+  CFile  f;
+  pstr   p;
+  char   S[500];
+  char   G[100];
+  char   O[100];
+  mat44  T1,T2,T3;
+  int    i,j,k,l,m,RC;
+  int    npops,ncops;
+  long   symop_start;
+  //fpos_t symop_start;
+
+    FreeMemory();
+
+    npops = 0;
+    ncops = 0;
+
+    CreateCopy ( SpGroup,SpaceGroup );
+
+    if (!syminfo_lib)          p = pstr(syminfo_file);
+    else if (!syminfo_lib[0])  p = pstr(syminfo_file);
+                         else  p = pstr(syminfo_lib);
+    f.assign ( p,true );
+    if (!f.reset(true))  {
+      p = getenv ( "SYMINFO" );
+      if (p)
+        strcpy ( S,p );
+      else  {
+        p = getenv ( "CLIBD" );
+        if (p)  {
+          strcpy ( S,p );
+          if (S[strlen(S)-1]!='/')  strcat ( S,"/" );
+          strcat ( S,"syminfo.lib" );
+        } else
+          strcpy ( S,"syminfo.lib" );
+      }
+      f.assign ( S,true );
+      if (!f.reset(true))  return SYMOP_NoLibFile;
+    }
+
+    if (strncasecmp(SpGroup,"Hall:",5))  {
+      // normal space group symbol on input
+      strcpy ( G," '"    );
+      strcat ( G,SpGroup );
+      strcat ( G,"'"     );
+      S[0] = char(0);
+      while (!f.FileEnd() && !(strstr(S,G) && (strstr(S,"symbol xHM") ||
+              strstr(S,"symbol old"))))
+        f.ReadLine ( S,sizeof(S) );
+    } else  {
+      // hall descriptor on input
+      strcpy ( G," ' " );
+      p = &(SpGroup[5]);
+      while (*p==' ')  p++;
+      strcat ( G,p     );
+      strcat ( G,"'"   );
+      S[0] = char(0);
+      while (!f.FileEnd() && !(strstr(S,G) && strstr(S,"symbol Hall")))
+        f.ReadLine ( S,sizeof(S) );
+    }
+    if (f.FileEnd())  {
+      f.shut();
+      return SYMOP_UnknownSpaceGroup;
+    }
+
+    // found spacegroup, move to symop lines
+    while (!f.FileEnd() && (!strstr(S,"symop"))) {
+      symop_start = f.Position();
+  //#    fgetpos ( f.GetHandle(),&symop_start );
+      f.ReadLine ( S,sizeof(S) );
+    }
+    // count primitive operators
+    while (!f.FileEnd() && (strstr(S,"symop"))) {
+      npops++;
+      f.ReadLine ( S,sizeof(S) );
+    }
+    // count centering operators
+    while (!f.FileEnd() && (strstr(S,"cenop"))) {
+      ncops++;
+      f.ReadLine ( S,sizeof(S) );
+    }
+    Nops = npops*ncops;
+    f.seek(symop_start);
+  //#  fsetpos ( f.GetHandle(),&symop_start );
+    SymOp = new PSymOp[Nops];
+    RC    = SYMOP_Ok;
+
+    // read primitive operators
+    for (i=0;(i<npops) && (!RC);i++)  {
+      f.ReadLine ( S,sizeof(S) );
+      SymOp[i] = new SymOp();
+      RC = SymOp[i]->SetSymOp ( S+6 );
+    }
+
+    // skip identity centering operator
+    f.ReadLine ( S,sizeof(S) );
+    // loop over non-trivial centering operators, and for each loop
+    // over primtive operators
+    for (i=1;(i<ncops) && (!RC);i++)  {
+      f.ReadLine ( S,sizeof(S) );
+      for (j=0;(j<npops) && (!RC);j++)  {
+        SymOp[i*npops+j] = new SymOp();
+        RC = SymOp[i*npops+j]->SetSymOp ( S+6 );
+
+        SymOp[i*npops+j]->GetTMatrix(T1);
+        SymOp[j]->GetTMatrix(T2);
+        for (k=0;k<4;k++)
+          for (l=0;l<4;l++) {
+            T3[k][l] = 0.0;
+            for (m=0;m<4;m++)
+              T3[k][l] += T1[k][m]*T2[m][l];
+          }
+        for (k=0;k<3;k++)                  // kdc fix
+          T3[k][3] -= floor ( T3[k][3] );  // kdc fix
+        SymOp[i*npops+j]->CompileOpTitle(O,T3,false);
+        SymOp[i*npops+j]->SetSymOp (O);
+      }
+    }
+
+    f.shut();
+
+    return RC;
+
+  }
+  */
+
+  void SymOps::Reset()  {
+  // removes all symmetry operations
+    FreeMemory();
+  }
+
+  int  SymOps::AddSymOp ( cpstr XYZOperation )  {
+  // adds a symmetry operation
+  PPSymOp symOp1;
+  int      i;
+    symOp1 = new PSymOp[Nops+1];
+    for (i=0;i<Nops;i++)
+      symOp1[i] = symOp[i];
+    if (symOp) delete[] symOp;
+    symOp = symOp1;
+    i = Nops;
+    symOp[i] = new SymOp();
+    Nops++;
+    return symOp[i]->SetSymOp ( XYZOperation );
+  }
+
+  void SymOps::PutGroupName ( cpstr SpGroupName )  {
+    CreateCopy ( SpGroup,SpGroupName );
+  }
+
+
+  int  SymOps::GetNofSymOps()  {
+  //  GetNofSymOps()  returns Nops -- the number of symmetry operations
+    return Nops;
+  }
+
+  pstr SymOps::GetSymOp ( int Nop )  {
+    if ((0<=Nop) && (Nop<Nops))  return symOp[Nop]->GetSymOp();
+                           else  return pstr("");
+  }
+
+  int  SymOps::Transform ( realtype & x, realtype & y, realtype & z,
+                            int Nop )  {
+  //  Transform(..) transforms the coordinates according to the
+  // symmetry operation Nop. The return code is non-zero if
+  // Nop is a wrong operation number (must range from 0 to Nops-1).
+    if ((Nop<0) || (Nop>=Nops))  return 1;
+    if (symOp[Nop])  {
+      symOp[Nop]->Transform ( x,y,z );
+      return 0;
+    } else
+      return 2;
+  }
+
+  int  SymOps::GetTMatrix ( mat44 & TMatrix, int Nop )  {
+  //  GetTMatrix(..) returns the coordinate transformation matrix
+  // for the symmetry operation Nop. The return code is non-zero if
+  // Nop is a wrong operation number (must range from 0 to Nops-1).
+    if ((Nop<0) || (Nop>=Nops))  return 1;
+    if (symOp[Nop])  {
+      symOp[Nop]->GetTMatrix ( TMatrix );
+      return 0;
+    } else
+      return 2;
+  }
+
+  void  SymOps::Print()  {
+  int  i;
+  char S[200];
+    printf ( "  SPACE GROUP  '%s'\n",SpGroup );
+    for (i=0;i<Nops;i++)  {
+      symOp[i]->Print();
+      if (symOp[i]->CompileOpTitle(S))
+            printf ( " CHECK STATUS: Ok\n" );
+      else  printf ( " CHECK STATUS: Generated '%s'\n",S );
+    }
+  }
+
+
+  void  SymOps::Copy ( PSymOps SymOps )  {
+  int i;
+    FreeMemory();
+    CreateCopy ( SpGroup,SymOps->SpGroup );
+    Nops = SymOps->Nops;
+    if (Nops>0)  {
+      symOp = new PSymOp[Nops];
+      for (i=0;i<Nops;i++) {
+        symOp[i] = new SymOp();
+        symOp[i]->Copy ( SymOps->symOp[i] );
+      }
+    }
+  }
+
+
+  void  SymOps::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte   ( &Version );
+    f.CreateWrite ( SpGroup  );
+    f.WriteInt    ( &Nops    );
+    for (i=0;i<Nops;i++)
+      StreamWrite ( f,symOp[i] );
+  }
+
+  void  SymOps::read ( io::RFile f )  {
+  int  i;
+  byte Version;
+    FreeMemory();
+    f.ReadByte   ( &Version );
+    f.CreateRead ( SpGroup  );
+    f.ReadInt    ( &Nops    );
+    if (Nops>0)  {
+      symOp = new PSymOp[Nops];
+      for (i=0;i<Nops;i++) {
+        symOp[i] = NULL;
+        StreamRead ( f,symOp[i] );
+      }
+    }
+  }
+
+
+  MakeStreamFunctions(SymOps)
+
+}  // namespace mmdb
+
+
+/*
+
+void TestSymOps()  {
+pstr     p,p1;
+int      RC;
+char     S[500];
+SymOps  SymOps;
+CFile    f;
+
+  p = getenv ( "PDB_ROOT" );
+  if (p)  {
+    strcpy ( S,p );
+    strcat ( S,"/lib/" );
+  } else
+    S[0] = char(0);
+  strcat   ( S,"symop.lib" );
+  f.assign ( S,true );
+  if (!f.reset())  {
+    printf ( " +++++ No symop.lib file found.\n" );
+    return;
+  }
+
+  while (!f.FileEnd())  {
+    f.ReadLine ( S,sizeof(S) );
+    if (S[0] && (S[0]!=' '))  {
+      p = strchr ( S,'\'' );
+      if (p)  {
+        p++;
+        p1 = strchr ( p,'\'' );
+        if (!p1)  p = NULL;
+      }
+      if (!p)  {
+        printf ( " +++++ Strange line in symop.lib:\n"
+                 "%s\n",S );
+        return;
+      }
+      *p1 = char(0);
+      RC = SymOps.SetGroup ( p );
+      printf ( " =========================================================\n"
+               "  RC=%i\n",RC );
+      SymOps.Print();
+    }
+  }
+
+  return;
+
+}
+
+*/
diff --git a/mmdb2/mmdb_symop.h b/mmdb2/mmdb_symop.h
new file mode 100644
index 0000000..f5e7af0
--- /dev/null
+++ b/mmdb2/mmdb_symop.h
@@ -0,0 +1,168 @@
+//  $Id: mmdb_symop.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDB_SymOp <interface>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::SymOp  ( symmetry operators )
+//       ~~~~~~~~~   mmdb::SymOps ( container of symmetry operators )
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_SymOp__
+#define __MMDB_SymOp__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_defs.h"
+
+namespace mmdb  {
+
+  //  ====================  SymOp  ========================
+
+  DefineClass(SymOp);
+  DefineStreamFunctions(SymOp);
+
+  class SymOp : public io::Stream  {
+
+    public :
+
+      SymOp ();
+      SymOp ( io::RPStream Object );
+      ~SymOp();
+
+      int  SetSymOp  ( cpstr XYZOperation );
+      pstr GetSymOp  ();
+
+      void Transform ( realtype & x, realtype & y, realtype & z );
+
+      void GetTMatrix ( mat44 & TMatrix );  // copies T to TMatrix
+      void SetTMatrix ( mat44 & TMatrix );  // copies TMatrix to T
+
+      bool CompileOpTitle ( pstr S );  // makes XYZOp from matrix T
+      bool CompileOpTitle ( pstr S, mat44 symMat, bool compare );
+      void Print          ();          // prints operation and matrix
+
+      void Copy  ( PSymOp symOp );
+
+      void write ( io::RFile f );
+      void read  ( io::RFile f );
+
+    protected :
+      pstr  XYZOp;
+      mat44 T;
+
+      void InitSymOp    ();
+      void FreeMemory   ();
+      int  GetOperation ( int n );
+
+  };
+
+
+  //  ====================  SymOps  ========================
+
+  enum SYMOP_RC  {
+    SYMOP_Ok                =  0,
+    SYMOP_NoLibFile         = -1,
+    SYMOP_UnknownSpaceGroup = -2,
+    SYMOP_NoSymOps          = -3,
+    SYMOP_WrongSyntax       = -4,
+    SYMOP_NotAnOperation    = -5,
+    SYMOP_ZeroDenominator   = -6
+  };
+
+  DefineClass(SymOps);
+  DefineStreamFunctions(SymOps);
+
+  class SymOps : public io::Stream  {
+
+    public :
+
+      SymOps ();
+      SymOps ( io::RPStream Object );
+      ~SymOps();
+
+      virtual void FreeMemory();
+
+      int  SetGroupSymopLib ( cpstr SpaceGroup,
+                              cpstr symop_lib=NULL );
+        // Space Group is taken from symop.lib. Return Code:
+        // SYMOP_Ok <=> success
+
+      int  SetGroup ( cpstr SpaceGroup,
+                      cpstr syminfo_lib=NULL );
+        // Space Group is taken from syminfo.lib. Return Code:
+        // SYMOP_Ok <=> success
+
+      void Reset           ();        // removes all symmetry operations
+      virtual int AddSymOp ( cpstr XYZOperation ); // adds symmetry
+                                                   // operation
+      void PutGroupName    ( cpstr SpGroupName  );
+
+      //  GetNofSymOps()  returns Nops -- the number of sym. operations
+      int  GetNofSymOps ();
+      pstr GetSymOp     ( int Nop );
+
+      //  Transform(..) transforms the coordinates according to the
+      // symmetry operation Nop. The return code is non-zero if
+      // Nop is a wrong operation number (must range from 0 to Nops-1).
+      int  Transform ( realtype & x, realtype & y, realtype & z,
+                       int Nop );
+
+      //  GetTMatrix(..) returns the coordinate transformation matrix
+      // for the symmetry operation Nop. The return code is non-zero if
+      // Nop is a wrong operation number (must range from 0 to Nops-1).
+      int  GetTMatrix ( mat44 & TMatrix, int Nop );
+
+      void Print ();
+
+      virtual void Copy ( PSymOps symOps );
+
+      void write ( io::RFile f );
+      void read  ( io::RFile f );
+
+    protected :
+
+      pstr    SpGroup;
+      int     Nops;
+      PPSymOp symOp;
+
+      void InitSymOps();
+
+  };
+
+}  // namespace mmdb
+
+// extern void TestSymOps();
+
+#endif
+
diff --git a/mmdb2/mmdb_tables.cpp b/mmdb2/mmdb_tables.cpp
new file mode 100644
index 0000000..d1e7c61
--- /dev/null
+++ b/mmdb2/mmdb_tables.cpp
@@ -0,0 +1,748 @@
+//  $Id: mmdb_tables.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDB_Tables <implementation>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Namespace :  mmdb::
+//
+//  **** Functions :
+//       ~~~~~~~~~~~
+//
+//  **** Constants :  AName  ( array of 2-character atom names       )
+//       ~~~~~~~~~~~  HAName ( array of 2=character heteroatom names )
+//                    RName  ( 3-characters amino acid names         )
+//                    RName1 ( 1-characters amino acid names         )
+//
+//
+//  (C) E. Krissinel  2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+
+#include "mmdb_tables.h"
+#include "mmdb_defs.h"
+
+namespace mmdb  {
+
+  //  ===============================================================
+
+  cpstr const ElementName[nElementNames] = {
+    " H", "HE",
+    "LI", "BE", " B", " C", " N", " O", " F", "NE",
+    "NA", "MG", "AL", "SI", " P", " S", "CL", "AR",
+    " K", "CA",
+          "SC", "TI", " V", "CR", "MN", "FE",
+          "CO", "NI", "CU", "ZN",
+                "GA", "GE", "AS", "SE", "BR", "KR",
+    "RB", "SR",
+          " Y", "ZR", "NB", "MO", "TC", "RU",
+          "RH", "PD", "AG", "CD",
+                "IN", "SN", "SB", "TE", " I", "XE",
+    "CS", "BA",
+          "LA", "CE", "PR", "ND", "PM", "SM", "EU",
+          "GD", "TB", "DY", "HO", "ER", "TM", "YB",
+                "LU", "HF", "TA", " W", "RE", "OS",
+                "IR", "PT", "AU", "HG",
+                      "TL", "PB", "BI", "PO", "AT", "RN",
+    "FR", "RA",
+          "AC", "TH", "PA", " U", "NP", "PU", "AM",
+          "CM", "BK", "CF", "ES", "FM", "MD", "NO",
+                "LR", "RF", "DB", "SG", "BH", "HS",
+                "MT", "UN", "UU", "UB",
+                            "UQ",       "UH",       "UO",
+    " D", "AN"
+  };
+
+  realtype const MolecWeight[nElementNames] = {
+    1.0079, 4.0026,
+    6.9410, 9.0122, 10.811, 12.011, 14.007, 15.999, 18.998, 20.180,
+    22.990, 24.305, 26.982, 28.086, 30.974, 32.066, 35.453, 39.948,
+    39.098, 40.078,
+            44.956, 47.867, 50.942, 51.996, 54.938, 55.845,
+            58.993, 58.693, 63.546, 65.390,
+                    69.723, 72.610, 74.922, 78.960, 79.904, 83.800,
+    85.468, 87.620,
+            88.906, 91.224, 92.906, 95.940, 97.907, 101.07,
+            102.91, 106.42, 107.87, 112.41,
+                    114.82, 118.71, 121.76, 127.60, 126.90, 131.29,
+    132.91, 137.33,
+            138.91, 140.12, 140.91, 144.24, 144.91, 150.36, 151.96,
+            157.25, 158.93, 162.50, 164.93, 167.26, 168.93, 173.04,
+                    174.97, 178.49, 180.95, 183.84, 186.21, 190.23,
+                    192.22, 195.08, 196.97, 200.59,
+                            204.38, 207.20, 208.98, 208.98, 209.99, 222.02,
+    232.02, 226.03,
+            227.03, 232.04, 231.04, 238.03, 237.05, 244.06, 243.06,
+            247.07, 247.07, 251.08, 252.08, 257.10, 258.10, 259.10,
+                    262.11, 263.11, 262.11, 266.12, 264.12, 269.13,
+                    268.14, 272.15, 272.15, 277.00,
+                            289.00, 289.00, 293.00,
+    2.0200, 3.0300
+  };
+
+
+  realtype const CovalentRadius[nElementNames] = {
+    0.32, 0.93,
+    1.23, 0.90, 0.82, 0.77, 0.75, 0.73, 0.72, 0.71,
+    1.54, 1.36, 1.18, 1.11, 1.06, 1.02, 0.99, 0.98,
+    2.03, 1.91,
+          1.62, 1.45, 1.34, 1.18, 1.17, 1.17,
+          1.16, 1.15, 1.17, 1.25,
+                1.26, 1.22, 1.20, 1.16, 1.14, 1.12,
+    2.16, 1.91,
+          1.62, 1.45, 1.34, 1.30, 1.27, 1.25,
+          1.25, 1.28, 1.34, 1.48,
+                1.44, 1.41, 1.40, 1.36, 1.33, 1.31,
+    2.35, 1.98,
+          1.69, 1.44, 1.34, 1.30, 1.28, 1.26, 1.27,
+          1.30, 1.34, 1.49, 1.48, 1.47, 1.46, 1.46,
+                1.45, 1.43, 2.50, 2.40, 2.20, 1.65,
+                1.65, 1.64, 1.63, 1.62,
+                      1.85, 1.61, 1.59, 1.59, 1.58, 1.57,
+    1.56, 1.74,
+          1.56, 1.65, 1.65, 1.42, 1.65, 1.65, 1.65,
+          1.65, 1.65, 1.65, 1.65, 1.65, 1.65, 1.65,
+                1.65, 0.32, 0.10, /**/
+                                  0.20, 0.20, 0.20,
+                0.20, 0.20, 0.20, 0.20,
+                      0.20, 0.20, 0.20,
+    0.32, 0.32
+  };
+
+
+  realtype const VdWaalsRadius[nElementNames] = {
+    1.20, 1.40,
+    1.82, 1.78, 1.74, 1.70, 1.55, 1.52, 1.47, 1.54,
+  //      ^^^^  ^^^^   <- only a guess
+    2.27, 1.73, 1.80, 2.10, 1.80, 1.80, 1.75, 1.88,
+  //            ^^^^
+    2.75, 2.65,
+  //      ^^^^
+          2.55, 2.45, 2.35, 2.20, 1.73, 1.90,
+  //      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+          1.75, 1.63, 1.40, 1.39,
+  //      ^^^^
+                1.87, 1.86, 1.85, 1.90, 1.85, 2.02,
+  //                  ^^^^
+    2.75, 2.65,
+  //^^^^  ^^^^
+          2.55, 2.45, 2.35, 2.20, 2.05, 1.90,
+  //      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+          1.75, 1.63, 1.72, 1.58,
+  //      ^^^^
+                1.93, 2.17, 2.10, 2.06, 1.98, 2.16,
+  //                        ^^^^
+    2.75, 2.75,
+  //^^^^  ^^^^
+          2.75, 2.75, 2.75, 2.75, 2.75, 2.75, 2.75,
+  //      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+          2.75, 2.75, 2.75, 2.75, 2.75, 2.65, 2.55,
+  //      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+                2.45, 2.35, 2.25, 2.15, 2.05, 1.95,
+  //            ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+                1.85, 1.75, 1.66, 1.55,
+  //            ^^^^
+                      1.96, 2.02, 2.00, 2.00, 2.00, 2.00,
+  //                              ^^^^  ^^^^  ^^^^  ^^^^
+    2.75, 2.75,
+  //^^^^  ^^^^
+          2.50, 2.25, 1.95, 1.86, 1.80, 1.80, 1.80,
+  //      ^^^^  ^^^^  ^^^^        ^^^^  ^^^^  ^^^^
+          1.80, 1.80, 1.80, 1.80, 1.80, 1.80, 1.80,
+  //      ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+                1.80, 1.80, 1.80, 1.80, 1.80, 1.80,
+  //            ^^^^  ^^^^  ^^^^  ^^^^  ^^^^  ^^^^
+                1.80, 1.80, 1.80, 1.80,
+  //            ^^^^  ^^^^  ^^^^  ^^^^
+                            1.80,       1.80,       1.80,
+  //                        ^^^^        ^^^^        ^^^^
+    1.30, 1.50
+  //^^^^  ^^^^
+  };
+
+  realtype const IonicRadius[nElementNames] = {
+       0.79, 0.49, 2.05, 1.40, 1.17, 0.91, 0.75, 0.65, 0.57, 0.51,
+       2.23, 1.72, 1.82, 1.46, 1.23, 1.09, 0.97, 0.88, 2.77, 2.23,
+       2.09, 2.00, 1.92, 1.85, 1.79, 1.72, 1.67, 1.62, 1.57, 1.53,
+       1.81, 1.52, 1.33, 1.22, 1.12, 1.03, 2.98, 2.45, 2.27, 2.16,
+       2.09, 2.01, 1.95, 1.89, 1.83, 1.79, 1.75, 1.71, 2.00, 1.72,
+       1.53, 1.42, 1.32, 1.24, 3.34, 2.78, 2.74, 2.16, 2.09, 2.02,
+       1.97, 1.92, 1.87, 1.83, 1.79, 1.76, 2.08, 1.81, 1.63, 1.53,
+       1.43, 1.34, 3.50, 3.00, 3.20, 2.70, 2.67, 2.64, 2.62, 2.59,
+       2.56, 2.54, 2.51, 2.49, 2.47, 2.45, 2.42, 2.40, 2.25, 3.16,
+       3.14, 3.11, 3.08, 3.05, 3.02, 2.99, 2.97, 2.95, 2.92, 2.90,
+       2.87, 2.85
+  };
+
+  cpstr const ElementMetal[nElementMetals] = {
+    "LI", "BE", "NA", "MG", "AL", " K", "CA", "SC", "TI", " V",
+    "MN", "FE", "CO", "NI", "CU", "ZN", "GA", "RB", "SR", " Y",
+    "ZR", "NB", "MO", "TC", "RU", "RH", "PD", "AG", "CD", "IN",
+    "SN", "SB", "CS", "BA", "LA", "CE", "PR", "ND", "PM", "SM",
+    "EU", "GD", "TB", "DY", "HO", "ER", "TM", "YB", "LU", "HF",
+    "TA", " W", "RE", "OS", "IR", "PT", "AU", "HG", "TL", "PB",
+    "BI", "PO", "FR", "RA", "AC", "TH", "PA", " U", "NP", "PU",
+    "AM", "CM", "BK", "CF", "ES", "FM", "MD", "NO", "LR", "RF",
+    "DB", "SG", "BH", "HS", "MT", "UN", "UU", "UB", "UQ", "UH",
+    "UO"
+  };
+
+
+  cpstr const HydAtomName[nHydAtomNames] = {
+    "0H", "1H", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H",
+    "HH", "*H", "'H", """H"
+  };
+
+
+
+  bool isMetal ( cpstr element )  {
+  char name[3];
+  bool isThere;
+  int  i;
+    if (!element[1])  {
+      name[0] = ' ';
+      name[1] = element[0];
+    } else
+      strncpy ( name,element,2 );
+    name[2] = char(0);
+    isThere = false;
+    for (i=0;(i<nElementMetals) && (!isThere);i++)
+      isThere = (!strcmp(ElementMetal[i],name));
+    return isThere;
+  }
+
+  int  getElementNo ( cpstr element )  {
+  int  type=0;
+  char El[3];
+    if ((!element[1]) || (element[1]==' '))  {
+      El[0] = ' ';
+      El[1] = element[0];
+    } else  {
+      El[0] = element[0];
+      El[1] = element[1];
+    }
+    El[2] = char(0);
+    UpperCase ( El );
+    while (type<nElementNames)
+      if (!strcmp(El,ElementName[type]))  break;
+                                    else  type++;
+    if (type>=nElementNames)  return ELEMENT_UNKNOWN;
+    return type+1;  // so that hydrogen is 1
+  }
+
+  realtype  getMolecWeight ( cpstr element )  {
+  int  type=0;
+  char El[3];
+    if ((!element[1]) || (element[1]==' '))  {
+      El[0] = ' ';
+      El[1] = element[0];
+    } else  {
+      El[0] = element[0];
+      El[1] = element[1];
+    }
+    El[2] = char(0);
+    UpperCase ( El );
+    while (type<nElementNames)
+      if (!strcmp(El,ElementName[type]))  break;
+                                    else  type++;
+    if (type>=nElementNames)  return 1.0;
+    return MolecWeight[type];
+  }
+
+  realtype  getCovalentRadius ( cpstr element )  {
+  int  type=0;
+  char El[3];
+    if ((!element[1]) || (element[1]==' '))  {
+      El[0] = ' ';
+      El[1] = element[0];
+    } else  {
+      El[0] = element[0];
+      El[1] = element[1];
+    }
+    El[2] = char(0);
+    UpperCase ( El );
+    while (type<nElementNames)
+      if (!strcmp(El,ElementName[type]))  break;
+                                    else  type++;
+    if (type>=nElementNames)  return 2.2*CovalentRadius[0];
+    return CovalentRadius[type];
+  }
+
+  realtype  getVdWaalsRadius ( cpstr element )  {
+  int  type=0;
+  char El[3];
+    if ((!element[1]) || (element[1]==' '))  {
+      El[0] = ' ';
+      El[1] = element[0];
+    } else  {
+      El[0] = element[0];
+      El[1] = element[1];
+    }
+    El[2] = char(0);
+    UpperCase ( El );
+    while (type<nElementNames)
+      if (!strcmp(El,ElementName[type]))  break;
+                                    else  type++;
+    if (type>=nElementNames)  return 1.8;
+    return VdWaalsRadius[type];
+  }
+
+  cpstr const ResidueName[nResNames] = {
+    "ALA", "ARG", "ASN", "ASP", "CYS", "CYH", "GLN",
+    "GLU", "GLY", "HIS", "ILE", "LEU", "LYS", "MET",
+    "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL",
+    "HEM", "WAT", "SUL", "END", "DUM"
+  };
+
+  int getResidueNo ( cpstr resName )  {
+  int i,m;
+    m = -1;
+    for (i=0;(i<nResNames) && (m<0);i++)
+      if (!strcmp(resName,ResidueName[i]))
+        m = i;
+    return m;
+  }
+
+  char const ResidueName1[nResNames] = {
+    'A', 'R', 'N', 'D', 'C', 'C', 'Q',
+    'E', 'G', 'H', 'I', 'L', 'K', 'M',
+    'F', 'P', 'S', 'T', 'W', 'Y', 'V',
+    'X', 'O', 'U', 'Z', 'Z'
+  };
+
+
+  cpstr const StdSolventName[nSolventNames] = {
+    "ADE", "CYT", "GUA", "INO", "THY", "URA",
+    "WAT", "HOH", "TIP", "H2O", "DOD", "MOH"
+  };
+
+
+  AAProperty const AAProperties[nAminoacidNames] = {
+    { "ALA",  1.8,  0.0,  0.42 },
+    { "ARG", -4.5,  1.0, -1.37 },
+    { "ASN", -3.5,  0.0, -0.82 },
+    { "ASP", -3.5, -1.0, -1.05 },
+    { "ASX", -3.5, -0.5, -1.05 },  // by analogy
+    { "CYS",  2.5,  0.0,  1.34 },
+    { "CYH",  2.5,  0.0,  1.34 },  // by analogy
+    { "GLN", -3.5,  0.0, -0.30 },
+    { "GLU", -3.5, -1.0, -0.87 },
+    { "GLX", -3.5, -0.5,  0.0  },  // by analogy
+    { "GLY", -0.4,  0.0,  0.0  },
+    { "HIS", -3.2,  0.0,  0.18 },
+    { "ILE",  4.5,  0.0,  2.46 },
+    { "LEU",  3.8,  0.0,  2.32 },
+    { "LYS", -3.9,  1.0, -1.35 },
+    { "MET",  1.9,  0.0,  1.68 },
+    { "PHE",  2.8,  0.0,  2.44 },
+    { "PRO", -1.6,  0.0,  0.98 },
+    { "SER", -0.8,  0.0, -0.05 },
+    { "THR", -0.7,  0.0,  0.35 },
+    { "TRP", -0.9,  0.0,  3.07 },
+    { "TYR", -1.3,  0.0,  1.31 },
+    { "VAL",  4.2,  0.0,  1.66 }
+  };
+
+  realtype GetAAHydropathy ( cpstr resName )  {
+  int  i1,j;
+    i1 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName,AAProperties[j].name))  {
+        i1 = j;
+        break;
+      } else
+        j++;
+    if (i1<0)  return -MaxReal;
+    return AAProperties[i1].hydropathy;
+  }
+
+  realtype GetAACharge ( cpstr resName )  {
+  int  i1,j;
+    i1 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName,AAProperties[j].name))  {
+        i1 = j;
+        break;
+      } else
+        j++;
+    if (i1<0)  return 0.0;
+    return AAProperties[i1].charge;
+  }
+
+  realtype GetAASolvationEnergy ( cpstr resName )  {
+  int  i1,j;
+    i1 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName,AAProperties[j].name))  {
+        i1 = j;
+        break;
+      } else
+        j++;
+    if (i1<0)  return 0.0;
+    return AAProperties[i1].relSolvEnergy;
+  }
+
+
+  int const AASimilarity[nAminoacidNames][nAminoacidNames] = {
+  /*  A A A A A C C G G G G H I L L M P P S T T T V            */
+  /*  L R S S S Y Y L L L L I L E Y E H R E H R Y A            */
+  /*  A G N P X S H N U X Y S E U S T E O R R P R L            */
+    { 5,0,0,0,0,0,0,0,0,2,2,0,2,2,0,2,2,2,1,1,2,2,2 },  /* ALA */
+    { 0,5,2,2,2,0,0,2,2,0,0,2,0,0,4,0,0,0,0,0,0,0,0 },  /* ARG */
+    { 0,2,5,3,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* ASN */
+    { 0,2,3,5,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* ASP */
+    { 0,2,5,5,5,0,0,3,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* ASX */
+    { 0,0,0,0,0,5,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },  /* CYS */
+    { 0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },  /* CYH */
+    { 0,2,3,3,3,0,0,5,3,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* GLN */
+    { 0,2,3,3,3,0,0,3,5,0,0,0,0,0,2,0,0,0,0,0,0,0,0 },  /* GLU */
+    { 2,0,0,0,0,0,0,0,0,5,5,0,1,1,0,1,1,2,0,0,1,1,1 },  /* GLX */
+    { 2,0,0,0,0,0,0,0,0,5,5,0,1,1,0,1,1,2,0,0,1,1,1 },  /* GLY */
+    { 0,2,0,0,0,0,0,0,0,0,0,5,1,1,2,2,2,0,1,1,2,2,1 },  /* HIS */
+    { 2,0,0,0,0,0,0,0,0,1,1,1,5,4,0,4,4,0,0,0,4,4,4 },  /* ILE */
+    { 2,0,0,0,0,0,0,0,0,1,1,1,4,5,0,4,4,0,0,0,4,4,4 },  /* LEU */
+    { 0,4,2,2,2,0,0,2,2,0,0,2,0,0,5,0,0,0,0,0,0,0,0 },  /* LYS */
+    { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,5,4,0,0,0,4,4,4 },  /* MET */
+    { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 },  /* PHE */
+    { 2,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,5,0,0,0,0,0 },  /* PRO */
+    { 1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,5,3,0,0,0 },  /* SER */
+    { 1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,3,5,0,0,0 },  /* THR */
+    { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 },  /* TRP */
+    { 2,0,0,0,0,0,0,0,0,1,1,2,4,4,0,4,5,0,0,0,5,5,4 },  /* TYR */
+    { 2,0,0,0,0,0,0,0,0,1,1,1,4,4,0,4,4,0,0,0,4,4,5 },  /* VAL */
+  };
+
+  int  GetAAPIndex ( cpstr resName )  {
+  // 0..nAminoacidNames-1
+  int i,k;
+    k = -1;
+    for (i=0;(i<nAminoacidNames) && (k<0);i++)
+      if (!strcasecmp(resName,AAProperties[i].name))
+        k = i;
+    return k;
+  }
+
+
+  int  GetAASimilarity ( cpstr resName1, cpstr resName2 )  {
+  int  i1,i2,j;
+
+    i1 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName1,AAProperties[j].name))  {
+        i1 = j;
+        break;
+      } else
+        j++;
+    if (i1<0)  return -1;
+
+    i2 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName2,AAProperties[j].name))  {
+        i2 = j;
+        break;
+      } else
+        j++;
+    if (i2<0)  return -2;
+
+    return AASimilarity[i1][i2];
+
+  }
+
+
+
+
+
+  /*
+
+
+  pstr const AminoacidName[nAminoacidNames] = {
+    "ALA", "ARG", "ASN", "ASP", "ASX", "CYS", "CYH", "GLN",
+    "GLU", "GLX", "GLY", "HIS", "ILE", "LEU", "LYS", "MET",
+    "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL"
+  };
+
+
+  //    The higher is the hydropathy scale value, the more
+  //  hydrophobic the residue is.
+  //    Some sources suggest that sure hydrophilic residues
+  //  are those with hydropathy scale value less than -1.5,
+  //  while sure hydropoobic residues have hydropathy scale
+  //  value greater than 0.0.
+  //    The scale is after J. Kyte and R. F. Doolittle,
+  //  A simple method for displaying the hydropathic character
+  //  of a protein, J. Mol. Biol. (1982) 157, 105-132
+  realtype const AAHydropathyScale[nAminoacidNames] = {
+      1.8,  -4.5,  -3.5,  -3.5,  -3.5,   2.5,   2.5,  -3.5,
+     -3.5,  -3.5,  -0.4,  -3.2,   4.5,   3.8,  -3.9,   1.9,
+      2.8,  -1.6,  -0.8,  -0.7,  -0.9,  -1.3,   4.2
+  };
+
+  realtype GetAAHydropathy ( cpstr resName )  {
+  int  i1,j;
+    i1 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName,AminoacidName[j]))  {
+        i1 = j;
+        break;
+      } else
+        j++;
+    if (i1<0)  return -MaxReal;
+    return AAHydropathyScale[i1];
+  }
+
+  //  Acid residues are those with negative charge
+  //  Base residues are those with positive charge
+  realtype const AACharge[nAminoacidNames] = {
+      0.0,   1.0,   0.0,  -1.0,  -0.5,   0.0,   0.0,   0.0,
+     -1.0,  -0.5,   0.0,   0.0,   0.0,   0.0,   1.0,   0.0,
+      0.0,   0.0,   0.0,   0.0,   0.0,   0.0,   0.0
+  };
+
+  int  GetAASimilarity ( cpstr resName1, cpstr resName2 )  {
+  int  i1,i2,j;
+
+    i1 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName1,AminoacidName[j]))  {
+        i1 = j;
+        break;
+      } else
+        j++;
+    if (i1<0)  return -1;
+
+    i2 = -1;
+    j  = 0;
+    while (j<nAminoacidNames)
+      if (!strcasecmp(resName2,AminoacidName[j]))  {
+        i2 = j;
+        break;
+      } else
+        j++;
+    if (i2<0)  return -2;
+
+    return AASimilarity[i1][i2];
+
+  }
+
+  bool isAminoacid ( cpstr resName )  {
+  bool isThere;
+  int     i;
+    isThere = false;
+    for (i=0;(i<nAminoacidNames) && (!isThere);i++)
+      isThere = (!strcmp(AminoacidName[i],resName));
+    return isThere;
+  }
+
+  */
+
+
+  cpstr const NucleotideName[nNucleotideNames] = {
+     "A",  "C",  "G",  "I",   "T",   "U",
+    "+A", "+C", "+G", "+I",  "+T",  "+U",
+    "DA", "DC", "DG", "DI",  "DT",  "DU",
+    "RA", "RC", "RG", "RU", "5NC", "TYD"
+  };
+
+
+  bool isSolvent ( cpstr resName )  {
+  bool isThere;
+  int     i;
+    isThere = false;
+    for (i=0;(i<nSolventNames) && (!isThere);i++)
+      isThere = (!strcmp(StdSolventName[i],resName));
+    return isThere;
+  }
+
+  bool isAminoacid ( cpstr resName )  {
+  bool isThere;
+  int     i;
+    isThere = false;
+    for (i=0;(i<nAminoacidNames) && (!isThere);i++)
+      isThere = (!strcmp(AAProperties[i].name,resName));
+    return isThere;
+  }
+
+  bool isNucleotide ( cpstr resName )  {
+  bool isThere;
+  int     i;
+    isThere = false;
+    for (i=0;(i<nNucleotideNames) && (!isThere);i++)
+      isThere = (!strcmp(NucleotideName[i],resName));
+    return isThere;
+  }
+
+  int isDNARNA ( cpstr resName )  {
+  bool isThere;
+  int     i;
+    isThere = false;
+    for (i=0;(i<nNucleotideNames) && (!isThere);i++)
+      isThere = (!strcmp(NucleotideName[i],resName));
+    if (!isThere)         return 0;  // neither
+    if (resName[0]=='D')  return 1;  // DNA
+    return 2;                        // RNA
+  }
+
+  bool isSugar ( cpstr resName )  {
+  UNUSED_ARGUMENT(resName);
+    return false;
+  }
+
+
+  cpstr const Res1Code[] = {
+
+    // standard aminoacids
+
+    "ALA A",  // Alanine
+    "ARG R",  // Arginine
+    "ASN N",  // Asparagine
+    "ASP D",  // Aspartic acid (Aspartate)
+    "CYS C",  // Cysteine
+    "GLN Q",  // Glutamine
+    "GLU E",  // Glutamic acid (Glutamate)
+    "GLY G",  // Glycine
+    "HIS H",  // Histidine
+    "ILE I",  // Isoleucine
+    "LEU L",  // Leucine
+    "LYS K",  // Lysine
+    "MET M",  // Methionine
+    "PHE F",  // Phenylalanine
+    "PRO P",  // Proline
+    "SER S",  // Serine
+    "THR T",  // Threonine
+    "TRP W",  // Tryptophan
+    "TYR Y",  // Tyrosine
+    "VAL V",  // Valine
+    "ASX B",  // Aspartic acid or Asparagine
+    "GLX Z",  // Glutamine or Glutamic acid.
+    //  ???     X       Any amino acid.
+
+    // other
+
+    "1PA A",   "1PI A",   "2AS D",   "2ML L",   "2MR R",   "3GA A",
+    "5HP E",   "ACB D",   "ACL R",   "AGM R",   "AHB D",   "ALM A",
+    "ALN A",   "ALO T",   "ALT A",   "ALY K",   "APH A",   "APM A",
+    "AR2 R",   "ARM R",   "ARO R",   "ASA D",   "ASB D",   "ASI D",
+    "ASK D",   "ASL D",   "ASQ D",   "AYA A",   "B1F A",   "B2A A",
+    "B2F A",   "B2I I",   "B2V V",   "BAL A",   "BCS C",   "BFD D",
+    "BHD D",   "BLE L",   "BLY K",   "BNN F",   "BNO L",   "BTA L",
+    "BTC C",   "BTR W",   "BUC C",   "BUG L",   "C5C C",   "C6C C",
+    "CAF C",   "CAS C",   "CAY C",   "CCS C",   "CEA C",   "CGU E",
+    "CHG G",   "CHP G",   "CLB A",   "CLD A",   "CLE L",   "CME C",
+    "CMT C",   "CSB C",   "CSD A",   "CSE C",   "CSO C",   "CSP C",
+    "CSR C",   "CSS C",   "CSW C",   "CSX C",   "CSY C",   "CSZ C",
+    "CTH T",   "CXM M",   "CY1 C",   "CYM C",   "CZZ C",   "DAH F",
+    "DAL A",   "DAM A",   "DAR R",   "DAS D",   "DBY Y",   "DCY C",
+    "DGL E",   "DGN Q",   "DHI H",   "DHN V",   "DIL I",   "DIV V",
+    "DLE L",   "DLY K",   "DNP A",   "DOH D",   "DPH F",   "DPN F",
+    "DPR P",   "DSE S",   "DSN S",   "DSP D",   "DTH T",   "DTR W",
+    "DTY Y",   "DVA V",   "EFC C",   "EHP F",   "EYS C",   "FLA A",
+    "FLE L",   "FME M",   "FTY Y",   "GGL E",   "GHP G",   "GSC G",
+    "GT9 C",   "H5M P",   "HAC A",   "HAR R",   "HIC H",   "HIP H",
+    "HMR R",   "HPH F",   "HPQ F",   "HTR W",   "HV5 A",   "HYP P",
+    "IAS N",   "IIL I",   "ILG Q",   "IML I",   "IN2 K",   "ISO A",
+    "IVA V",   "IYR Y",   "KCX K",   "KPH K",   "LLY K",   "LOL L",
+    "LPL L",   "LTR W",   "LYM K",   "LYZ K",   "M3L K",   "MAA A",
+    "MAI R",   "MEN N",   "MGN Q",   "MGY G",   "MHL L",   "MHO M",
+    "MHS H",   "MIS S",   "MLE L",   "MLY K",   "MLZ K",   "MME M",
+    "MNL L",   "MNV V",   "MPQ G",   "MSE M",   "MSO M",   "MTY Y",
+    "MVA V",   "NAL A",   "NAM A",   "NCY C",   "NEM H",   "NEP H",
+    "NFA F",   "NIT A",   "NLE L",   "NLN L",   "NNH R",   "NPH C",
+    "NVA V",   "OAS S",   "OCS C",   "OCY C",   "OMT M",   "OPR R",
+    "PAQ F",   "PBB C",   "PCA E",   "PEC C",   "PGY G",   "PHA F",
+    "PHD N",   "PHI F",   "PHL F",   "PHM F",   "PLE L",   "POM P",
+    "PPH F",   "PPN F",   "PR3 C",   "PRR A",   "PRS P",   "PTH Y",
+    "PTR Y",   "PYA A",   "RON V",   "S1H S",   "SAC S",   "SAH C",
+    "SAM M",   "SBD A",   "SBL A",   "SCH C",   "SCS C",   "SCY C",
+    "SEB S",   "SEG A",   "SEP S",   "SET S",   "SHC C",   "SHP G",
+    "SLZ K",   "SMC C",   "SME M",   "SNC C",   "SOC C",   "STY Y",
+    "SVA S",   "TBG G",   "TCR W",   "THC T",   "THO T",   "TIH A",
+    "TNB C",   "TPL W",   "TPO T",   "TPQ F",   "TRF W",   "TRG K",
+    "TRN W",   "TRO W",   "TYB Y",   "TYI Y",   "TYN Y",   "TYQ Y",
+    "TYS Y",   "TYY A",   "VAD V",   "VAF V",   "YOF Y",   ""
+
+  };
+
+
+  void Get1LetterCode ( cpstr res3name, pstr res1code )  {
+  char r[4];
+  int  i;
+
+    strncpy ( r,res3name,3 );
+    r[3] = char(0);
+    UpperCase ( r );
+    i = 0;
+    res1code[0] = char(1);
+    while (Res1Code[i][0])  {
+      if (Res1Code[i][0]==r[0])  {
+        if (Res1Code[i][1]==r[1])  {
+          if (Res1Code[i][2]==r[2])  {
+            res1code[0] = Res1Code[i][4];
+            break;
+          }
+        }
+      }
+      i++;
+    }
+
+    if (res1code[0]!=char(1))  res1code[1] = char(0);
+    else if (isNucleotide(r))  strcpy ( res1code,r   );
+                         else  strcpy ( res1code,"X" );
+
+  }
+
+
+  void Get3LetterCode ( cpstr res1name, pstr res3code )  {
+  int  i;
+
+    strcpy ( res3code,"XXX" );
+    i = 0;
+    while (Res1Code[i][0])  {
+      if (Res1Code[i][4]==res1name[0])  {
+        res3code[0] = Res1Code[i][0];
+        res3code[1] = Res1Code[i][1];
+        res3code[2] = Res1Code[i][2];
+        break;
+      }
+      i++;
+    }
+
+  }
+
+} // namespace mmdb
diff --git a/mmdb2/mmdb_tables.h b/mmdb2/mmdb_tables.h
new file mode 100644
index 0000000..f2d4d9d
--- /dev/null
+++ b/mmdb2/mmdb_tables.h
@@ -0,0 +1,127 @@
+//  $Id: mmdb_tables.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDB_Tables <interface>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Namespace :  mmdb::
+//
+//  **** Functions :
+//       ~~~~~~~~~~~
+//
+//  **** Constants :  AName  ( array of 2-character atom names       )
+//       ~~~~~~~~~~~  HAName ( array of 2=character heteroatom names )
+//                    RName  ( 3-characters amino acid names         )
+//                    RName1 ( 1-characters amino acid names         )
+//
+//
+//  (C) E. Krissinel  2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Tables__
+#define __MMDB_Tables__
+
+#include "mmdb_mattype.h"
+
+namespace mmdb  {
+
+  //  =================================================================
+
+  const int nElementNames  = 117;
+  const int nElementMetals = 91;
+  const int nHydAtomNames  = 14;
+
+  extern cpstr    const ElementName   [nElementNames];
+  extern cpstr    const ElementMetal  [nElementMetals];
+  extern cpstr    const HydAtomName   [nHydAtomNames];
+  extern realtype const MolecWeight   [nElementNames];
+  extern realtype const CovalentRadius[nElementNames];
+  extern realtype const VdWaalsRadius [nElementNames];
+  extern realtype const IonicRadius   [nElementNames];
+
+  extern bool isMetal ( cpstr element );
+
+  const int ELEMENT_UNKNOWN = -1;
+
+  extern int      getElementNo      ( cpstr element );
+  extern realtype getMolecWeight    ( cpstr element );
+  extern realtype getCovalentRadius ( cpstr element );
+  extern realtype getVdWaalsRadius  ( cpstr element );
+
+  const int nResNames = 26;
+
+  extern cpstr const ResidueName [nResNames];
+  extern char  const ResidueName1[nResNames];
+
+  extern int getResidueNo ( cpstr resName );
+
+  const realtype NAvogadro = 6.02214129e23;
+
+  const int nSolventNames    = 12;
+  const int nAminoacidNames  = 23;
+  const int nNucleotideNames = 24;
+
+  DefineStructure(AAProperty);
+
+  struct AAProperty  {
+    char     name[4];
+    realtype hydropathy;
+    realtype charge;
+    realtype relSolvEnergy;
+  };
+
+  extern AAProperty const AAProperties[nAminoacidNames];
+  extern int const AASimilarity[nAminoacidNames][nAminoacidNames];
+
+  extern int      GetAAPIndex     ( cpstr resName );  // 0..nAminoacidNames-1
+  extern realtype GetAAHydropathy ( cpstr resName );  // -4.5...+4.5
+  extern realtype GetAACharge     ( cpstr resName );
+  extern realtype GetAASolvationEnergy ( cpstr resName );
+  extern int      GetAASimilarity ( cpstr resName1,
+                                    cpstr resName2 );  // 0..5
+
+  extern cpstr const StdSolventName[nSolventNames];
+  extern cpstr const NucleotideName[nNucleotideNames];
+
+  extern bool isSolvent    ( cpstr resName );
+  extern bool isAminoacid  ( cpstr resName );
+  extern bool isNucleotide ( cpstr resName );
+  extern int  isDNARNA     ( cpstr resName ); // 0,1(DNA),2(RNA)
+  extern bool isSugar      ( cpstr resName );
+
+  extern void  Get1LetterCode ( cpstr res3name, pstr res1code );
+  extern void  Get3LetterCode ( cpstr res1name, pstr res3code );
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_title.cpp b/mmdb2/mmdb_title.cpp
new file mode 100644
index 0000000..b16f6e1
--- /dev/null
+++ b/mmdb2/mmdb_title.cpp
@@ -0,0 +1,2662 @@
+//  $Id: mmdb_title.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    21.11.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Title <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::TitleContainer  (container of title classes)
+//       ~~~~~~~~~  mmdb::ObsLine
+//                  mmdb::TitleLine
+//                  mmdb::Caveat
+//                  mmdb::Compound
+//                  mmdb::Source
+//                  mmdb::KeyWords
+//                  mmdb::ExpData
+//                  mmdb::MdlType
+//                  mmdb::Author
+//                  mmdb::RevData
+//                  mmdb::Supersede
+//                  mmdb::Journal
+//                  mmdb::Remark
+//                  mmdb::Biomolecule
+//                  mmdb::Title       ( MMDB title section )
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mmdb_title.h"
+#include "mmdb_cifdefs.h"
+
+namespace mmdb  {
+
+  //  ==============  TitleContainer  ====================
+
+  PContainerClass TitleContainer::MakeContainerClass ( int ClassID )  {
+    switch (ClassID)  {
+      default :
+      case ClassID_Template  : return
+                           ClassContainer::MakeContainerClass(ClassID);
+      case ClassID_ObsLine   : return new ObsLine  ();
+      case ClassID_CAVEAT    : return new Caveat   ();
+      case ClassID_TitleLine : return new TitleLine();
+      case ClassID_Compound  : return new Compound ();
+      case ClassID_Source    : return new Source   ();
+      case ClassID_ExpData   : return new ExpData  ();
+      case ClassID_Author    : return new Author   ();
+      case ClassID_RevData   : return new RevData  ();
+      case ClassID_Supersede : return new Supersede();
+      case ClassID_Journal   : return new Journal  ();
+      case ClassID_Remark    : return new Remark   ();
+    }
+  }
+
+  MakeStreamFunctions(TitleContainer)
+
+
+  //  ================  ObsLine  ===================
+
+  ObsLine::ObsLine() : ContainerClass()  {
+    InitObsLine();
+  }
+
+  ObsLine::ObsLine ( cpstr S ) : ContainerClass()  {
+    InitObsLine();
+    ConvertPDBASCII ( S );
+  }
+
+  ObsLine::ObsLine ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitObsLine();
+  }
+
+  ObsLine::~ObsLine() {}
+
+  void  ObsLine::InitObsLine()  {
+  int i;
+    strcpy ( repDate,"DD-MMM-YYYY" );
+    strcpy ( idCode, "----" );
+    for (i=0;i<8;i++)
+      strcpy ( rIdCode[i],"    " );
+  }
+
+  void  ObsLine::PDBASCIIDump ( pstr S, int N )  {
+  //  makes the ASCII PDB OBSLTE line number N
+  //  from the class' data
+  int i;
+    if (N==0)  strcpy  ( S,"OBSLTE    " );
+         else  sprintf ( S,"OBSLTE  %2i",N+1 );
+    PadSpaces ( S,80 );
+    Date11to9 ( repDate,&(S[11]) );
+    strncpy   ( &(S[21]),idCode,4 );
+    for (i=0;i<8;i++)
+      strncpy ( &(S[31+5*i]),rIdCode[i],4 );
+  }
+
+  void  ObsLine::MakeCIF ( mmcif::PData CIF, int )  {
+  mmcif::PLoop Loop;
+  int          RC,i,j;
+  char         DateCIF[20];
+    RC = CIF->AddLoop ( CIFCAT_OBSLTE,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, provide tags
+      Loop->AddLoopTag ( CIFTAG_ID             );
+      Loop->AddLoopTag ( CIFTAG_DATE           );
+      Loop->AddLoopTag ( CIFTAG_REPLACE_PDB_ID );
+      Loop->AddLoopTag ( CIFTAG_PDB_ID         );
+    }
+    Date11toCIF ( repDate,DateCIF );
+    for (i=0;i<8;i++)  {
+      j = 0;
+      while (rIdCode[i][j] && (rIdCode[i][j]==' '))  j++;
+      if (rIdCode[i][j])  {
+        Loop->AddString ( pstr("OBSLTE") );
+        Loop->AddString ( DateCIF    );
+        Loop->AddString ( idCode     );
+        Loop->AddString ( rIdCode[i] );
+      }
+    }
+  }
+
+  ERROR_CODE ObsLine::ConvertPDBASCII ( cpstr S )  {
+  int i;
+    Date9to11 ( &(S[11]),repDate );
+    strncpy   ( idCode,&(S[21]),4 );
+    idCode[4] = char(0);
+    for (i=0;i<8;i++)  {
+      strncpy ( rIdCode[i],&(S[31+i*5]),4 );
+      rIdCode[i][4] = char(0);
+    }
+    return Error_NoError;
+  }
+
+  ERROR_CODE  ObsLine::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  int         i,RC;
+  pstr        F,FDate,FID;
+  char        DateCIF [20];
+  char        DateCIF0[20];
+  IDCode      idCode1;
+
+    Loop = CIF->GetLoop ( CIFCAT_OBSLTE );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+    i = 0;
+    do  {
+      F = Loop->GetString ( CIFTAG_ID,n,RC );
+      if (RC)  {
+        if (i==0)  n = -1;
+        return Error_MissingCIFField;
+      }
+      if (F)  {
+        if (!strcmp(F,"OBSLTE"))  {
+          FDate = Loop->GetString ( CIFTAG_DATE,n,RC );
+          if ((!RC) && FDate)
+                strncpy ( DateCIF,FDate,15 );
+          else  strcpy  ( DateCIF,"YYYY-MMM-DD" );
+          FID = Loop->GetString ( CIFTAG_REPLACE_PDB_ID,n,RC );
+          if ((!RC) && FID)
+                strncpy ( idCode1,FID,sizeof(IDCode)-1 );
+          else  idCode1[0] = char(0);
+          if (i==0)  {
+            DateCIFto11 ( DateCIF,repDate );
+            DateCIF[11] = char(0);
+            strcpy ( idCode  ,idCode1 );
+            strcpy ( DateCIF0,DateCIF );
+          } else if ((strcmp(DateCIF0,DateCIF)) ||
+                     (strcmp(idCode,idCode1)))
+            return Error_MissingCIFField;
+          FID = Loop->GetString ( CIFTAG_PDB_ID,n,RC );
+          if ((!RC) && FID)
+               strncpy ( rIdCode[i],FID,sizeof(IDCode)-1 );
+          else rIdCode[i][0] = char(0);
+          Loop->DeleteField ( CIFTAG_ID            ,n );
+          Loop->DeleteField ( CIFTAG_DATE          ,n );
+          Loop->DeleteField ( CIFTAG_REPLACE_PDB_ID,n );
+          Loop->DeleteField ( CIFTAG_PDB_ID        ,n );
+          i++;
+        }
+      }
+      n++;
+    } while (i<8);
+
+    return Error_NoError;
+
+  }
+
+  void  ObsLine::Copy ( PContainerClass ObsLine )  {
+  int i;
+    strcpy ( repDate,PObsLine(ObsLine)->repDate );
+    strcpy ( idCode ,PObsLine(ObsLine)->idCode  );
+    for (i=0;i<8;i++)
+      strcpy ( rIdCode[i],PObsLine(ObsLine)->rIdCode[i] );
+  }
+
+  void  ObsLine::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+   f.WriteByte    ( &Version      );
+   f.WriteTerLine ( repDate,false );
+   f.WriteTerLine ( idCode ,false );
+   for (i=0;i<8;i++)
+     f.WriteTerLine ( rIdCode[i],false );
+  }
+
+  void  ObsLine::read  ( io::RFile f ) {
+  int  i;
+  byte Version;
+   f.ReadByte    ( &Version      );
+   f.ReadTerLine ( repDate,false );
+   f.ReadTerLine ( idCode ,false );
+   for (i=0;i<8;i++)
+     f.ReadTerLine ( rIdCode[i],false );
+  }
+
+  MakeStreamFunctions(ObsLine)
+
+
+  //  ===================  TitleLine  ======================
+
+  TitleLine::TitleLine() : ContString()  {
+    InitTitleLine();
+  }
+
+  TitleLine::TitleLine ( cpstr S ) : ContString()  {
+    InitTitleLine();
+    ConvertPDBASCII ( S );
+  }
+
+  TitleLine::TitleLine ( io::RPStream Object ) : ContString(Object)  {
+    InitTitleLine();
+  }
+
+  TitleLine::~TitleLine() {
+  }
+
+  void  TitleLine::InitTitleLine()  {
+    CreateCopy ( CIFCategory,CIFCAT_STRUCT );
+    CreateCopy ( CIFTag,     CIFTAG_TITLE  );
+  }
+
+  ERROR_CODE TitleLine::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10]) );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  TitleLine::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"TITLE     " );
+         else  sprintf ( S,"TITLE   %2i",N+1 );
+    strcat ( S,Line );
+  }
+
+  void  TitleLine::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  TitleLine::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(TitleLine)
+
+
+
+  //  ===================  Caveat  ======================
+
+  Caveat::Caveat() : ContString()  {
+    InitCaveat();
+  }
+
+  Caveat::Caveat ( cpstr S ) : ContString()  {
+    InitCaveat();
+    ConvertPDBASCII ( S );
+  }
+
+  Caveat::Caveat ( io::RPStream Object ) : ContString(Object)  {
+    InitCaveat();
+  }
+
+  Caveat::~Caveat() {}
+
+  void  Caveat::InitCaveat()  {
+    strcpy ( idCode,"----" );
+    CreateCopy ( CIFCategory,CIFCAT_DATABASE_PDB_CAVEAT );
+    CreateCopy ( CIFTag     ,CIFTAG_TEXT                );
+  }
+
+  ERROR_CODE Caveat::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>12)  {
+      strncpy ( idCode,&(S[11]),4 );
+      idCode[4] = char(0);
+      if (strlen(S)>19)
+            CreateCopy ( Line,&(S[19])  );
+      else  CreateCopy ( Line,pstr(" ") );
+    } else
+      CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  Caveat::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"CAVEAT     " );
+         else  sprintf ( S,"CAVEAT  %2i ",N+1 );
+    strcat ( S,idCode );
+    strcat ( S,"    " );
+    strcat ( S,Line   );
+  }
+
+  void  Caveat::MakeCIF ( mmcif::PData CIF, int N )  {
+  char S[500];
+    CIF->PutString ( idCode,CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID,false );
+    strcpy  ( S,"\n" );
+    strncat ( S,Line,sizeof(S)-2 );
+    S[sizeof(S)-1] = char(0);
+    CIF->PutString ( S,CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_TEXT,(N!=0) );
+  }
+
+/*
+  void  Caveat::GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
+                          int & pos )  {
+  pstr F;
+  int  RC;
+    F = CIF->GetString ( CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID,RC );
+    if ((!RC) && F)  {
+      strncpy ( idCode,F,sizeof(IDCode) );
+      idCode[sizeof(IDCode)-1] = char(0);
+    }
+    ContString::GetCIF1 ( CIF,Signal,pos );
+    if (Signal<0)
+      CIF->DeleteField ( CIFCAT_DATABASE_PDB_CAVEAT,CIFTAG_ID );
+  }
+*/
+
+  void  Caveat::Copy ( PContainerClass Caveat )  {
+    strcpy ( idCode,PCaveat(Caveat)->idCode );
+    ContString::Copy ( Caveat );
+  }
+
+  void  Caveat::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte    ( &Version     );
+    f.WriteTerLine ( idCode,false );
+    ContString::write ( f );
+  }
+
+  void  Caveat::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte    ( &Version     );
+    f.ReadTerLine ( idCode,false );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(Caveat)
+
+
+
+  //  ===================  Compound  ======================
+
+  Compound::Compound() : ContString()  {
+    InitCompound();
+  }
+
+  Compound::Compound ( cpstr S ) : ContString()  {
+    InitCompound();
+    ConvertPDBASCII ( S );
+  }
+
+  Compound::Compound ( io::RPStream Object ) : ContString(Object)  {
+    InitCompound();
+  }
+
+  Compound::~Compound() {}
+
+  void  Compound::InitCompound()  {
+    CreateCopy ( CIFCategory,CIFCAT_STRUCT         );
+    CreateCopy ( CIFTag     ,CIFTAG_NDB_DESCRIPTOR );
+  }
+
+  ERROR_CODE Compound::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10])  );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  Compound::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"COMPND    " );
+         else  sprintf ( S,"COMPND  %2i",N+1 );
+    strcat ( S,Line );
+  }
+
+  void  Compound::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  Compound::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(Compound)
+
+
+
+  //  ===================  Source  ======================
+
+  Source::Source() : ContString()  {
+    InitSource();
+  }
+
+  Source::Source ( cpstr S ) : ContString()  {
+    InitSource();
+    ConvertPDBASCII ( S );
+  }
+
+  Source::Source ( io::RPStream Object ) : ContString(Object)  {
+    InitSource();
+  }
+
+  Source::~Source() {}
+
+  void  Source::InitSource()  {
+    CreateCopy ( CIFCategory,CIFCAT_STRUCT );
+    CreateCopy ( CIFTag     ,CIFTAG_SOURCE );
+  }
+
+  ERROR_CODE Source::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10])  );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  Source::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"SOURCE    " );
+         else  sprintf ( S,"SOURCE  %2i",N+1 );
+    strcat ( S,Line );
+  }
+
+  void  Source::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  Source::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(Source)
+
+
+  //  ===================  KeyWords  ======================
+
+  KeyWords::KeyWords() : io::Stream()  {
+    Init();
+  }
+
+  KeyWords::KeyWords ( cpstr S ) : io::Stream()  {
+    Init();
+    ConvertPDBASCII ( S );
+  }
+
+  KeyWords::KeyWords ( io::RPStream Object ) : io::Stream(Object)  {
+    Init();
+  }
+
+  KeyWords::~KeyWords()  {
+    Delete();
+  }
+
+  void  KeyWords::Init()  {
+    nKeyWords = 0;
+    KeyWord   = NULL;
+    Cont      = false;
+  }
+
+  void  KeyWords::Delete()  {
+  int i;
+    if (KeyWord)  {
+      for (i=0;i<nKeyWords;i++)
+        if (KeyWord[i])
+          delete[] KeyWord[i];
+      delete[] KeyWord;
+    }
+    nKeyWords = 0;
+    KeyWord   = NULL;
+    Cont      = false;
+  }
+
+  int  KeyWords::ConvertPDBASCII ( cpstr S )  {
+  //  we anticipate that length of S is 80 characters
+  //  -- pad with spaces if necessary
+  char   L[85];
+  int    i,k,m;
+  pstr * KW;
+
+    i = 10;  // scan PDB line from ith character
+
+    k = nKeyWords;
+    if (!Cont)  k++;  // 1st keyword does not continue from previous line
+    m = 0;
+    while (S[i] && (i<70))  {
+      if (S[i]==',')  k++;  // count keywords
+      if (S[i]!=' ')  m++;  // count non-spaces to see if the line is empty
+      i++;
+    }
+
+    if (m==0)  return 0;    //  empty line
+
+    KW = new pstr[k];
+    if (KeyWord)  {
+      for (i=0;i<nKeyWords;i++)
+        KW[i] = KeyWord[i];
+      delete[] KeyWord;
+    }
+    for (i=nKeyWords;i<k;i++)
+      KW[i] = NULL;       // null new pointers
+    KeyWord = KW;
+
+    i = 10;
+    if (Cont)  nKeyWords--;
+    while (S[i] && (i<70))  {
+      while ((S[i]==' ') && (i<70))  i++;  // skip leading spaces
+      if (Cont)  {
+        strcpy ( L," " );
+        m = 1;
+      } else
+        m = 0;
+      while (S[i] && (S[i]!=',') && (i<70))
+        L[m++] = S[i++];
+      m--;
+      while ((m>0) && (L[m]==' '))  m--;  // remove padding spaces
+      m++;
+      L[m] = char(0);
+      if (Cont)  CreateConcat ( KeyWord[nKeyWords],L );
+           else  CreateCopy   ( KeyWord[nKeyWords],L );
+      if (S[i]==',')  {
+        i++;
+        Cont = false;
+      } else
+        Cont = true;
+      nKeyWords++;
+    }
+
+    return 0;
+
+  }
+
+  void  KeyWords::PDBASCIIDump ( io::RFile f )  {
+  int  N,i,k,m1,m2,ms;
+  char S[85];
+  char c;
+    if (KeyWord)  {
+      N = 0;
+      i = 0;
+      while (i<nKeyWords)  {
+        if (N==0)  strcpy  ( S,"KEYWDS    " );
+             else  sprintf ( S,"KEYWDS  %2i ",N+1 );
+        do  {
+          while ((i<nKeyWords) && (!KeyWord[i]))  i++;
+          if (i<nKeyWords) {
+            m1 = 0;
+            while (KeyWord[i][m1])  {
+              while (KeyWord[i][m1]==' ')  m1++;
+              m2 = m1;
+              ms = -1;
+              while ((KeyWord[i][m2]) && ((m2-m1)<58))  {
+                if (KeyWord[i][m2]==' ')  ms = m2;
+                m2++;
+              }
+              if ((ms<0) || ((m2-m1)<58))  ms = m2;
+              c = KeyWord[i][ms];
+              KeyWord[i][ms] = char(0);
+              strcat ( S,&(KeyWord[i][m1]) );
+              KeyWord[i][ms] = c;
+              m1 = ms;
+              if (c)  {
+                PadSpaces   ( S,80 );
+                f.WriteLine ( S );
+                N++;
+                sprintf ( S,"KEYWDS  %2i ",N+1 );
+              }
+            }
+            i++;
+            if (i<nKeyWords)  {
+              k = strlen(S) + strlen(KeyWord[i]) + 2;
+              if (i<nKeyWords)
+                strcat ( S,", " );
+            } else
+              k = 80;
+          } else
+            k = 80;
+        } while (k<70);
+        PadSpaces   ( S,80 );
+        f.WriteLine ( S );
+        N++;
+      }
+    }
+  }
+
+  void  KeyWords::MakeCIF ( mmcif::PData CIF )  {
+  int  i,k;
+  char S[500];
+    strcpy ( S,"\n" );
+    for (i=0;i<nKeyWords;i++)
+      if (KeyWord[i])  {
+        k = strlen(KeyWord[i]);
+        if (strlen(S)+k>70)  {
+          CIF->PutString ( S,CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,true );
+          if (k>(int)sizeof(S))  {
+            CIF->PutString ( KeyWord[i],CIFCAT_STRUCT_KEYWORDS,
+                             CIFTAG_TEXT,true );
+            k = 0;
+          }
+          strcpy ( S,"\n" );
+        }
+        if (k>0) {
+          strcat ( S,KeyWord[i] );
+          if (i<nKeyWords-1)  strcat ( S,", " );
+        }
+      }
+    if (strlen(S)>1)
+      CIF->PutString ( S,CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,true );
+  }
+
+  void  KeyWords::GetCIF ( mmcif::PData CIF )  {
+  pstr  F;
+  int   i,j,k;
+  bool  NB;
+  char  c;
+    Delete();
+    F = CIF->GetString ( CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT,i );
+    k = 0;
+    if ((!i) && F)  {
+      i  = 0;
+      NB = false;
+      while (F[i])  {
+        if (F[i]==',')  {
+          nKeyWords++;
+          NB = false;
+        } else if (F[i]!=' ')
+          NB = true;
+        i++;
+      }
+      if (NB)  nKeyWords++;
+      KeyWord = new pstr[nKeyWords];
+      i = 0;
+      while (F[i] && (k<nKeyWords))  {
+        while ((F[i]==' ') || (F[i]=='\n') || (F[i]=='\r'))  i++;
+        j = i;
+        while (F[i] && (F[i]!=','))  i++;
+        c    = F[i];
+        F[i] = char(0);
+        KeyWord[k] = NULL;
+        CreateCopy ( KeyWord[k],&(F[j]) );
+        j = 0;
+        while (KeyWord[k][j])  {
+          if ((KeyWord[k][j]=='\n') || (KeyWord[k][j]=='\r'))
+            KeyWord[k][j] = ' ';
+          j++;
+        }
+        F[i] = c;
+        k++;
+        if (F[i])  i++;
+      }
+    }
+    while (k<nKeyWords)  KeyWord[k++] = NULL;
+    CIF->DeleteField ( CIFCAT_STRUCT_KEYWORDS,CIFTAG_TEXT );
+  }
+
+
+  void  KeyWords::Copy ( PKeyWords KeyWords )  {
+  int i;
+    Delete();
+    nKeyWords = KeyWords->nKeyWords;
+    if (nKeyWords>0)  {
+      KeyWord = new pstr[nKeyWords];
+      for (i=0;i<nKeyWords;i++)  {
+        KeyWord[i] = NULL;
+        CreateCopy ( KeyWord[i],KeyWords->KeyWord[i] );
+      }
+    }
+  }
+
+  void  KeyWords::write ( io::RFile f )  {
+  int i;
+  byte Version=1;
+    f.WriteByte ( &Version   );
+    f.WriteInt  ( &nKeyWords );
+    for (i=0;i<nKeyWords;i++)
+      f.CreateWrite ( KeyWord[i] );
+  }
+
+  void  KeyWords::read ( io::RFile f )  {
+  int  i;
+  byte Version;
+    Delete();
+    f.ReadByte ( &Version   );
+    f.ReadInt  ( &nKeyWords );
+    if (nKeyWords>0)  {
+      KeyWord = new pstr[nKeyWords];
+      for (i=0;i<nKeyWords;i++)  {
+        KeyWord[i] = NULL;
+        f.CreateRead ( KeyWord[i] );
+      }
+    }
+  }
+
+  MakeStreamFunctions(KeyWords)
+
+
+  //  ===================  ExpData  ======================
+
+  ExpData::ExpData() : ContString()  {
+    InitExpData();
+  }
+
+  ExpData::ExpData ( cpstr S ) : ContString()  {
+    InitExpData();
+    ConvertPDBASCII ( S );
+  }
+
+  ExpData::ExpData ( io::RPStream Object ) : ContString(Object)  {
+    InitExpData();
+  }
+
+  ExpData::~ExpData() {}
+
+  void  ExpData::InitExpData()  {
+    CreateCopy ( CIFCategory,CIFCAT_EXPTL  );
+    CreateCopy ( CIFTag     ,CIFTAG_METHOD );
+  }
+
+  ERROR_CODE ExpData::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10])  );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  ExpData::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"EXPDTA    " );
+         else  sprintf ( S,"EXPDTA  %2i",N+1 );
+    strcat ( S,Line );
+  }
+
+  void  ExpData::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  ExpData::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(ExpData)
+
+
+
+
+  //  ===================  MdlType  ======================
+
+  MdlType::MdlType() : ContString()  {
+    InitMdlType();
+  }
+
+  MdlType::MdlType ( cpstr S ) : ContString()  {
+    InitMdlType();
+    ConvertPDBASCII ( S );
+  }
+
+  MdlType::MdlType ( io::RPStream Object ) : ContString(Object)  {
+    InitMdlType();
+  }
+
+  MdlType::~MdlType() {}
+
+  void  MdlType::InitMdlType()  {
+    CreateCopy ( CIFCategory,CIFCAT_EXPTL  );
+    CreateCopy ( CIFTag     ,CIFTAG_METHOD );
+  }
+
+  ERROR_CODE MdlType::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10])  );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  MdlType::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"MDLTYP    " );
+         else  sprintf ( S,"MDLTYP  %2i",N+1 );
+    strcat ( S,Line );
+  }
+
+  void  MdlType::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  MdlType::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(MdlType)
+
+
+  //  ===================  Author  ======================
+
+  Author::Author() : ContString()  {
+    InitAuthor();
+  }
+
+  Author::Author ( cpstr S ) : ContString()  {
+    InitAuthor();
+    ConvertPDBASCII ( S );
+  }
+
+  Author::Author ( io::RPStream Object ) : ContString(Object)  {
+    InitAuthor();
+  }
+
+  Author::~Author() {}
+
+  void  Author::InitAuthor()  {
+    CreateCopy ( CIFCategory,CIFCAT_AUDIT_AUTHOR );
+    CreateCopy ( CIFTag     ,CIFTAG_NAME         );
+  }
+
+  ERROR_CODE Author::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10])  );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  Author::PDBASCIIDump ( pstr S, int N )  {
+    if (N==0)  strcpy  ( S,"AUTHOR    " );
+         else  sprintf ( S,"AUTHOR  %2i",N+1 );
+    strcat ( S,Line );
+  }
+
+  void  Author::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  Author::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(Author)
+
+
+
+  //  ================  RevData  ===================
+
+  RevData::RevData() : ContainerClass()  {
+    InitRevData();
+  }
+
+  RevData::RevData ( cpstr S ) : ContainerClass()  {
+    InitRevData();
+    ConvertPDBASCII ( S );
+  }
+
+  RevData::RevData ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitRevData();
+  }
+
+  RevData::~RevData() {}
+
+  void  RevData::InitRevData()  {
+  int i;
+    modNum  = 0;
+    strcpy ( modDate,"DD-MMM-YYYY" );
+    strcpy ( modId  , "----" );
+    modType = -1;
+    for (i=0;i<4;i++)
+      strcpy ( record[i],"      " );
+    Warning = 0;
+  }
+
+  void  RevData::PDBASCIIDump ( pstr S, int N )  {
+  //  makes the ASCII PDB REVDATA line number N
+  //  from the class' data
+  int i;
+    if (N==0)  sprintf ( S,"REVDAT %3i  " ,modNum     );
+         else  sprintf ( S,"REVDAT %3i%2i",modNum,N+1 );
+    i = strlen(S);
+    while (i<80)
+      S[i++] = ' ';
+    S[i] = char(0);
+    Date11to9 ( modDate,&(S[13]) );
+    strncpy   ( &(S[23]),modId,5 );
+    S[31] = char(modType+int('0'));
+    for (i=0;i<4;i++)
+      strncpy ( &(S[39+i*7]),record[i],6 );
+  }
+
+  void RevData::MakeCIF ( mmcif::PData CIF, int N )  {
+  mmcif::PLoop Loop;
+  int         RC,i,j;
+  char        DateCIF[20];
+    RC = CIF->AddLoop ( CIFCAT_DATABASE_PDB_REV,Loop );
+    if ((RC!=mmcif::CIFRC_Ok) || (N==0))  {
+      // the category was (re)created, privide tags
+      Loop->AddLoopTag ( CIFTAG_NUM                   );
+      Loop->AddLoopTag ( CIFTAG_DATE                  );
+      Loop->AddLoopTag ( CIFTAG_REPLACES              );
+      Loop->AddLoopTag ( CIFTAG_MOD_TYPE              );
+      Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_1 );
+      Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_2 );
+      Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_3 );
+      Loop->AddLoopTag ( CIFTAG_RCSB_RECORD_REVISED_4 );
+    }
+    Date11toCIF ( modDate,DateCIF );
+    Loop->AddInteger ( modNum  );
+    Loop->AddString  ( DateCIF );
+    Loop->AddString  ( modId   );
+    Loop->AddInteger ( modType );
+    for (i=0;i<4;i++)  {
+      j = 0;
+      while (record[i][j] && (record[i][j]==' '))  j++;
+      if (record[i][j])  Loop->AddString ( record[i] );
+                   else  Loop->AddString ( NULL      );
+    }
+
+  }
+
+  ERROR_CODE RevData::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  int          RC;
+  pstr         F;
+
+    Loop = CIF->GetLoop ( CIFCAT_DATABASE_PDB_REV );
+    if (!Loop)  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    RC = Loop->GetInteger ( modNum,CIFTAG_NUM,n,true );
+    if (RC==mmcif::CIFRC_WrongIndex)  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      sprintf ( CIFErrorLocation,"loop %s.%s row %i",
+                CIFCAT_DATABASE_PDB_REV,CIFTAG_NUM,n );
+      n = -Error_UnrecognizedInteger-1;
+      return Error_UnrecognizedInteger;
+    }
+
+    F = Loop->GetString ( CIFTAG_DATE,n,RC );
+    if ((!RC) && F)  DateCIFto11 ( F,modDate );
+    F = Loop->GetString ( CIFTAG_REPLACES,n,RC );
+    if ((!RC) && F)  strcpy ( modId,F );
+    RC = Loop->GetInteger ( modType,CIFTAG_MOD_TYPE,n,true );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      sprintf ( CIFErrorLocation,"loop %s.%s row %i",
+                CIFCAT_DATABASE_PDB_REV,CIFTAG_MOD_TYPE,n );
+      n = -Error_UnrecognizedInteger-1;
+      return Error_UnrecognizedInteger;
+    }
+
+    F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_1,n,RC );
+    if ((!RC) && F)  strcpy ( record[0],F );
+    F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_2,n,RC );
+    if ((!RC) && F)  strcpy ( record[1],F );
+    F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_3,n,RC );
+    if ((!RC) && F)  strcpy ( record[2],F );
+    F = Loop->GetString ( CIFTAG_RCSB_RECORD_REVISED_4,n,RC );
+    if ((!RC) && F)  strcpy ( record[3],F );
+
+    Loop->DeleteField ( CIFTAG_DATE                 ,n );
+    Loop->DeleteField ( CIFTAG_REPLACES             ,n );
+    Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_1,n );
+    Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_2,n );
+    Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_3,n );
+    Loop->DeleteField ( CIFTAG_RCSB_RECORD_REVISED_4,n );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  ERROR_CODE RevData::ConvertPDBASCII ( cpstr S )  {
+  int  i;
+  pstr endptr;
+  char N[20];
+    Warning = 0;
+    strncpy   ( N,&(S[7]),3 );
+    N[3]    = char(0);
+    modNum  = mround(strtod(N,&endptr));
+    if (endptr==N)  Warning |= REVDAT_WARN_MODNUM;
+    Date9to11 ( &(S[13]),modDate );
+    strncpy   ( modId,&(S[23]),5 );
+    modId[5] = char(0);
+    modType  = int(S[31]) - int('0');
+    if (modType>9)  Warning |= REVDAT_WARN_MODTYPE;
+    for (i=0;i<4;i++)  {
+      strncpy ( record[i],&(S[39+i*7]),6 );
+      record[i][6] = char(0);
+    }
+    return Error_NoError;
+  }
+
+  void  RevData::Copy ( PContainerClass RevData )  {
+  int i;
+    modNum  = PRevData(RevData)->modNum;
+    modType = PRevData(RevData)->modType;
+    strcpy ( modDate,PRevData(RevData)->modDate );
+    strcpy ( modId  ,PRevData(RevData)->modId   );
+    for (i=0;i<4;i++)
+      strcpy ( record[i],PRevData(RevData)->record[i] );
+  }
+
+  void  RevData::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte  ( &Version );
+    f.WriteInt   ( &modNum  );
+    f.WriteInt   ( &modType );
+    f.WriteWord  ( &Warning );
+    f.WriteTerLine ( modDate,false );
+    f.WriteTerLine ( modId  ,false );
+    for (i=0;i<4;i++)
+      f.WriteTerLine ( record[i],false );
+  }
+
+  void  RevData::read  ( io::RFile f ) {
+  int  i;
+  byte Version;
+    f.ReadByte  ( &Version );
+    f.ReadInt   ( &modNum  );
+    f.ReadInt   ( &modType );
+    f.ReadWord  ( &Warning );
+    f.ReadTerLine ( modDate,false );
+    f.ReadTerLine ( modId  ,false );
+    for (i=0;i<4;i++)
+      f.ReadTerLine ( record[i],false );
+  }
+
+  MakeStreamFunctions(RevData)
+
+
+
+  //  ================  Supersede  ===================
+
+  Supersede::Supersede() : ContainerClass()  {
+    InitSupersede();
+  }
+
+  Supersede::Supersede ( cpstr S ) : ContainerClass()  {
+    InitSupersede();
+    ConvertPDBASCII ( S );
+  }
+
+  Supersede::Supersede ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitSupersede();
+  }
+
+  Supersede::~Supersede() {}
+
+  void  Supersede::InitSupersede()  {
+  int i;
+    strcpy ( sprsdeDate,"DD-MMM-YYYY" );
+    strcpy ( idCode, "----" );
+    for (i=0;i<8;i++)
+      strcpy ( sIdCode[i],"    " );
+  }
+
+  void  Supersede::PDBASCIIDump ( pstr S, int N )  {
+  //  makes the ASCII PDB OBSLTE line number N
+  //  from the class' data
+  int i;
+    if (N==0)  strcpy  ( S,"SPRSDE    " );
+         else  sprintf ( S,"SPRSDE  %2i",N+1 );
+    i = strlen(S);
+    while (i<80)
+      S[i++] = ' ';
+    S[i] = char(0);
+    if (N==0)  {
+      Date11to9 ( sprsdeDate,&(S[11]) );
+      strncpy   ( &(S[21]),idCode,4 );
+    }
+    for (i=0;i<8;i++)
+      strncpy ( &(S[31+5*i]),sIdCode[i],4 );
+  }
+
+  void  Supersede::MakeCIF ( mmcif::PData CIF, int )  {
+  mmcif::PLoop Loop;
+  int         RC,i,j;
+  char        DateCIF[20];
+    RC = CIF->AddLoop ( CIFCAT_SPRSDE,Loop );
+    if (RC!=mmcif::CIFRC_Ok)  {
+      // the category was (re)created, privide tags
+      Loop->AddLoopTag ( CIFTAG_ID             );
+      Loop->AddLoopTag ( CIFTAG_DATE           );
+      Loop->AddLoopTag ( CIFTAG_REPLACE_PDB_ID );
+      Loop->AddLoopTag ( CIFTAG_PDB_ID         );
+    }
+    Date11toCIF ( sprsdeDate,DateCIF );
+    for (i=0;i<8;i++)  {
+      j = 0;
+      while (sIdCode[i][j] && (sIdCode[i][j]==' '))  j++;
+      if (sIdCode[i][j])  {
+        Loop->AddString ( pstr("SPRSDE") );
+        Loop->AddString ( DateCIF    );
+        Loop->AddString ( idCode     );
+        Loop->AddString ( sIdCode[i] );
+      }
+    }
+  }
+
+  ERROR_CODE Supersede::ConvertPDBASCII ( cpstr S )  {
+  int i;
+    if (S[9]==' ')  {
+      Date9to11 ( &(S[11]),sprsdeDate );
+      strncpy   ( idCode,&(S[21]),4 );
+      idCode[4] = char(0);
+    }
+    for (i=0;i<8;i++)  {
+      strncpy ( sIdCode[i],&(S[31+i*5]),4 );
+      sIdCode[i][4] = char(0);
+    }
+    return Error_NoError;
+  }
+
+  ERROR_CODE Supersede::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  int         i,RC;
+  pstr        F,FDate,FID;
+  char        DateCIF [20];
+  char        DateCIF0[20];
+  IDCode      idCode1;
+
+    Loop = CIF->GetLoop ( CIFCAT_SPRSDE );
+    if (!Loop)  {
+      n = -1;  // signal to finish processing of this structure
+      return Error_EmptyCIF;
+    }
+    i = 0;
+    do  {
+      F = Loop->GetString ( CIFTAG_ID,n,RC );
+      if (RC)  {
+        if (i==0)  {
+          n = -1;
+          return Error_EmptyCIF;
+        } else
+          return Error_NoError;
+      }
+      if (F)  {
+        if (!strcmp(F,"SPRSDE"))  {
+          FDate = Loop->GetString ( CIFTAG_DATE,n,RC );
+          if ((!RC) && FDate)
+                strncpy ( DateCIF,FDate,15 );
+          else  strcpy  ( DateCIF,"YYYY-MMM-DD" );
+          FID = Loop->GetString ( CIFTAG_REPLACE_PDB_ID,n,RC );
+          if ((!RC) && FID)
+                strncpy ( idCode1,FID,sizeof(IDCode)-1 );
+          else  idCode1[0] = char(0);
+          if (i==0)  {
+            DateCIFto11 ( DateCIF,sprsdeDate );
+            DateCIF[11] = char(0);
+            strcpy ( idCode  ,idCode1 );
+            strcpy ( DateCIF0,DateCIF );
+          } else if ((strcmp(DateCIF0,DateCIF)) ||
+                     (strcmp(idCode,idCode1)))
+            return Error_NoError;
+          FID = Loop->GetString ( CIFTAG_PDB_ID,n,RC );
+          if ((!RC) && FID)
+               strncpy ( sIdCode[i],FID,sizeof(IDCode)-1 );
+          else sIdCode[i][0] = char(0);
+          Loop->DeleteField ( CIFTAG_ID            ,n );
+          Loop->DeleteField ( CIFTAG_DATE          ,n );
+          Loop->DeleteField ( CIFTAG_REPLACE_PDB_ID,n );
+          Loop->DeleteField ( CIFTAG_PDB_ID        ,n );
+          i++;
+        }
+      }
+      n++;
+    } while (i<8);
+
+    return Error_NoError;
+
+  }
+
+  void  Supersede::Copy ( PContainerClass Supersede )  {
+  int i;
+    strcpy ( sprsdeDate,PSupersede(Supersede)->sprsdeDate );
+    strcpy ( idCode    ,PSupersede(Supersede)->idCode     );
+    for (i=0;i<8;i++)
+      strcpy ( sIdCode[i],PSupersede(Supersede)->sIdCode[i] );
+  }
+
+  void  Supersede::write ( io::RFile f )  {
+  int  i;
+  byte Version=1;
+    f.WriteByte  ( &Version );
+    f.WriteTerLine ( sprsdeDate,false );
+    f.WriteTerLine ( idCode    ,false );
+    for (i=0;i<8;i++)
+      f.WriteTerLine ( sIdCode[i],false );
+  }
+
+  void  Supersede::read  ( io::RFile f ) {
+  int  i;
+  byte Version;
+    f.ReadByte  ( &Version );
+    f.ReadTerLine ( sprsdeDate,false );
+    f.ReadTerLine ( idCode    ,false );
+    for (i=0;i<8;i++)
+      f.ReadTerLine ( sIdCode[i],false );
+  }
+
+  MakeStreamFunctions(Supersede)
+
+
+  //  ===================  Journal  ======================
+
+  Journal::Journal() : ContString()  {
+    InitJournal();
+  }
+
+  Journal::Journal ( cpstr S ) : ContString()  {
+    InitJournal();
+    ConvertPDBASCII ( S );
+  }
+
+  Journal::Journal ( io::RPStream Object ) : ContString(Object)  {
+    InitJournal();
+  }
+
+  Journal::~Journal() {}
+
+  void  Journal::InitJournal()  {
+    CreateCopy ( CIFCategory,CIFCAT_CITATION );
+    CreateCopy ( CIFTag     ,CIFTAG_TEXT     );
+  }
+
+  ERROR_CODE Journal::ConvertPDBASCII ( cpstr S )  {
+    if (strlen(S)>10)
+         CreateCopy ( Line,&(S[10]) );
+    else CreateCopy ( Line,pstr(" ") );
+    return Error_NoError;
+  }
+
+  void  Journal::PDBASCIIDump ( pstr S, int )  {
+    strcpy ( S,"JRNL      " );
+    strcat ( S,Line         );
+  }
+
+  void  Journal::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    ContString::write ( f );
+  }
+
+  void  Journal::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    ContString::read ( f );
+  }
+
+  MakeStreamFunctions(Journal)
+
+
+
+  //  ===================  Remark  ======================
+
+  Remark::Remark() : ContainerClass()  {
+    InitRemark();
+  }
+
+  Remark::Remark ( cpstr S ) : ContainerClass()  {
+    InitRemark();
+    ConvertPDBASCII ( S );
+  }
+
+  Remark::Remark ( io::RPStream Object ) : ContainerClass(Object)  {
+    InitRemark();
+  }
+
+  Remark::~Remark() {
+    if (remark)  delete[] remark;
+  }
+
+  void  Remark::InitRemark()  {
+    remarkNum = 0;
+    remark    = NULL;
+  }
+
+  ERROR_CODE Remark::ConvertPDBASCII ( cpstr S )  {
+  int i;
+    GetInteger ( remarkNum,&(S[7]),3 );
+    if (remarkNum==MinInt4)  CreateCopy ( remark,S );
+    else if (strlen(S)>11)   CreateCopy ( remark,&(S[11])  );
+                       else  CreateCopy ( remark,pstr(" ") );
+    i = strlen(remark)-1;
+    while ((i>0) && (remark[i]==' '))  i--;
+    remark[i+1] = char(0);
+    return Error_NoError;
+  }
+
+  void  Remark::PDBASCIIDump ( pstr S, int )  {
+    if (remarkNum==MinInt4)
+      strcpy ( S,remark );
+    else  {
+      strcpy     ( S,"REMARK" );
+      PadSpaces  ( S,80 );
+      PutInteger ( &(S[7]) ,remarkNum,3 );
+      strncpy    ( &(S[11]),remark,IMin(68,strlen(remark)) );
+    }
+  }
+
+  void  Remark::MakeCIF ( mmcif::PData CIF, int N )  {
+  mmcif::PLoop Loop;
+  int         RC;
+    RC = CIF->AddLoop ( CIFCAT_NDB_DATABASE_REMARK,Loop );
+    if ((RC!=mmcif::CIFRC_Ok) || (N==0))  {
+      // the category was (re)created, privide tags
+      Loop->AddLoopTag ( CIFTAG_ID   );
+      Loop->AddLoopTag ( CIFTAG_TEXT );
+    }
+    if (remarkNum==MinInt4)  Loop->AddString  ( NULL      );
+                       else  Loop->AddInteger ( remarkNum );
+    Loop->AddString ( remark );
+  }
+
+  ERROR_CODE  Remark::GetCIF ( mmcif::PData CIF, int & n )  {
+  mmcif::PLoop Loop;
+  int          RC;
+
+    Loop = CIF->GetLoop ( CIFCAT_NDB_DATABASE_REMARK );
+    if (!Loop)  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+    if (n>=Loop->GetLoopLength() )  {
+      n = -1;
+      return Error_EmptyCIF;
+    }
+
+    RC = Loop->GetInteger ( remarkNum,CIFTAG_ID,n,true );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      sprintf ( CIFErrorLocation,"loop %s.%s row %i",
+                CIFCAT_NDB_DATABASE_REMARK,CIFTAG_ID,n );
+      n = -Error_UnrecognizedInteger-1;
+      return Error_UnrecognizedInteger;
+    } else if (RC)
+      remarkNum = MinInt4;
+    Loop->GetString ( remark,CIFTAG_TEXT,n,true );
+
+    n++;
+
+    return Error_NoError;
+
+  }
+
+  void  Remark::Copy ( PContainerClass RemarkClass )  {
+    remarkNum = PRemark(RemarkClass)->remarkNum;
+    CreateCopy ( remark,PRemark(RemarkClass)->remark );
+  }
+
+  void  Remark::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte   ( &Version   );
+    f.WriteInt    ( &remarkNum );
+    f.CreateWrite ( remark     );
+  }
+
+  void  Remark::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte   ( &Version   );
+    f.ReadInt    ( &remarkNum );
+    f.CreateRead ( remark     );
+  }
+
+  MakeStreamFunctions(Remark)
+
+
+  //  =================  Biomolecule  =====================
+
+  #define  R350_ERRBIOMT     (-3)
+  #define  R350_ERROR        (-2)
+  #define  R350_END          (-1)
+  #define  R350_NONE           0
+  #define  R350_BIOMOLECULE    1
+  #define  R350_CHAINS         2
+  #define  R350_BIOMT          3
+
+  void getRemarkKey ( RPRemark rem, int & lkey )  {
+    if (rem)  {
+      if (rem->remarkNum!=350)  lkey = R350_END;
+      else if (rem->remark)  {
+        if (strcasestr(rem->remark,"BIOMOLECULE:"))
+          lkey = R350_BIOMOLECULE;
+        else if (strcasestr(rem->remark,"CHAINS:"))
+          lkey = R350_CHAINS;
+        else if (strcasestr(rem->remark,"BIOMT1") ||
+                 strcasestr(rem->remark,"BIOMT2") ||
+                 strcasestr(rem->remark,"BIOMT3"))
+          lkey = R350_BIOMT;
+        else
+          lkey = R350_NONE;
+      }
+    }
+  }
+
+  int lookupRemarks ( int & i, RPRemark rem,
+                      RTitleContainer Remark )  {
+  int l,lkey;
+
+    l    = Remark.Length();
+    lkey = R350_NONE;
+    while ((i<l) && (lkey==R350_NONE))  {
+      getRemarkKey ( rem,lkey );
+      if (lkey==R350_NONE)  {
+        i++;
+        rem = (PRemark)Remark.GetContainerClass ( i );
+      }
+    }
+
+    return lkey;
+
+  }
+
+
+
+  BMApply::BMApply() : io::Stream()  {
+    InitBMApply();
+  }
+
+  BMApply::BMApply ( io::RPStream Object ) : io::Stream ( Object )  {
+    InitBMApply();
+  }
+
+  BMApply::~BMApply()  {
+    FreeMemory();
+  }
+
+  void  BMApply::InitBMApply()  {
+    chain     = NULL;
+    nChains   = 0;
+    tm        = NULL;
+    nMatrices = 0;
+  }
+
+  void  BMApply::FreeMemory()  {
+    if (chain)  delete[] chain;
+    if (tm)     delete[] tm;
+    chain     = NULL;
+    nChains   = 0;
+    tm        = NULL;
+    nMatrices = 0;
+  }
+
+  int  BMApply::addChains ( int & i, RPRemark rem,
+                             RTitleContainer Remark )  {
+  PChainID ch1;
+  pstr     p;
+  int      l,lkey,nAdd,j;
+
+    l    = Remark.Length();
+    lkey = R350_NONE;
+
+    while ((i<l) && (lkey==R350_NONE))  {
+
+      p = strcasestr ( rem->remark,"CHAINS:" );
+      if (p)  p += 7;
+      else  {
+        p = rem->remark;
+        while (*p==' ')  p++;
+        if ((p[1]!=',') && (p[1]!=' '))  p = NULL;
+      }
+
+      if (p)  {
+        nAdd  = strlen(p)/2 + 3;
+        ch1   = chain;
+        chain = new ChainID[nChains+nAdd];
+        for (j=0;j<nChains;j++)
+          strcpy ( chain[j],ch1[j] );
+        if (ch1)  delete[] ch1;
+
+        while (*p)  {
+          while ((*p==' ') || (*p==','))  p++;
+          if (*p)  {
+            if ((p[1]==',') || (p[1]==' ') || (p[1]==char(0)))  {
+              chain[nChains][0] = *p;
+              chain[nChains][1] = char(0);
+              nChains++;
+              p++;
+            } else
+              break;
+          }
+        }
+      }
+
+      do  {
+        i++;
+        if (i<l)  {
+          rem = (PRemark)Remark.GetContainerClass ( i );
+          if (rem)  {
+            if (rem->remarkNum!=350)  lkey = R350_END;
+            else getRemarkKey ( rem,lkey );
+          }
+        } else
+          lkey = R350_END;
+      } while ((!rem) && (lkey==R350_NONE));
+
+    }
+
+    return lkey;
+
+  }
+
+  int getBIOMT ( RPRemark rem, int biomtNo, mat44 & t,
+                 RTitleContainer Remark, int & i )  {
+  char PN[20];
+  pstr p1,p2;
+  int  l,j,lkey;
+
+    sprintf ( PN,"BIOMT%1i",biomtNo );
+    p1 = strcasestr ( rem->remark,PN );
+    if (!p1)  return R350_ERRBIOMT;
+
+    p1 += 6;
+    while (*p1==' ')  p1++;
+    while (*p1 && (*p1!=' '))  p1++;
+
+    l = biomtNo - 1;
+    t[l][0] = strtod ( p1,&p2 );
+    if (p1==p2)  return R350_ERRBIOMT;
+    t[l][1] = strtod ( p2,&p1 );
+    if (p1==p2)  return R350_ERRBIOMT;
+    t[l][2] = strtod ( p1,&p2 );
+    if (p1==p2)  return R350_ERRBIOMT;
+    t[l][3] = strtod ( p2,&p1 );
+    if (p1==p2)  return R350_ERRBIOMT;
+
+    if (biomtNo==3)  {
+      for (j=0;j<3;j++)
+        t[3][j] = 0.0;
+      t[3][3] = 1.0;
+    }
+
+    l    = Remark.Length();
+    lkey = R350_BIOMT;
+    do  {
+      i++;
+      if (i<l)  {
+        rem = (PRemark)Remark.GetContainerClass ( i );
+        if (rem)  {
+          if (rem->remarkNum!=350)  lkey = R350_END;
+                              else  getRemarkKey ( rem,lkey );
+        }
+      } else
+        lkey = R350_END;
+    } while ((lkey==R350_NONE) || ((!rem) && (lkey==R350_BIOMT)));
+
+    return lkey;
+
+  }
+
+  int  BMApply::addMatrices ( int & i, RPRemark rem,
+                               RTitleContainer Remark )  {
+  pmat44 tm1;
+  int    l,lkey,j,k1,k2,nAlloc;
+
+    l      = Remark.Length();
+    lkey   = R350_BIOMT;
+    nAlloc = nMatrices;
+
+    while ((i<l) && (lkey==R350_BIOMT))  {
+
+      if (nMatrices>=nAlloc)  {
+        nAlloc = nMatrices + 10;
+        tm1    = tm;
+        tm     = new mat44[nAlloc];
+        for (j=0;j<nMatrices;j++)
+          for (k1=0;k1<4;k1++)
+            for (k2=0;k2<4;k2++)
+              tm[j][k1][k2] = tm1[j][k1][k2];
+        if (tm1)  delete[] tm1;
+      }
+
+      lkey = getBIOMT ( rem,1,tm[nMatrices],Remark,i );
+      if (lkey==R350_BIOMT)
+        lkey = getBIOMT ( rem,2,tm[nMatrices],Remark,i );
+      if (lkey==R350_BIOMT)
+        lkey = getBIOMT ( rem,3,tm[nMatrices],Remark,i );
+      nMatrices++;
+
+    }
+
+    return lkey;
+
+  }
+
+  void  BMApply::Copy ( PBMApply BMA )  {
+  // if BMA is NULL, then empties the class
+  int  i,j,k;
+
+    FreeMemory();
+
+    if (BMA)  {
+
+      nChains = BMA->nChains;
+      if (nChains>0)  {
+        chain = new ChainID[nChains];
+        for (i=0;i<nChains;i++)
+          strcpy ( chain[i],BMA->chain[i] );
+      }
+
+      nMatrices = BMA->nMatrices;
+      if (nMatrices>0)  {
+        tm = new mat44[nMatrices];
+        for (i=0;i<nMatrices;i++)
+          for (j=0;j<4;j++)
+            for (k=0;k<4;k++)
+              tm[i][j][k] = BMA->tm[i][j][k];
+       }
+    }
+
+  }
+
+  void  BMApply::write ( io::RFile f )  {
+  int i,j,k;
+    f.WriteInt ( &nChains );
+    for (i=0;i<nChains;i++)
+      f.WriteTerLine ( chain[i],false );
+    f.WriteInt ( &nMatrices );
+    for (i=0;i<nMatrices;i++)
+      for (j=0;j<3;j++)
+        for (k=0;k<4;k++)
+          f.WriteReal ( &(tm[i][j][k]) );
+  }
+
+  void  BMApply::read ( io::RFile f )  {
+  int i,j,k;
+    FreeMemory();
+    f.ReadInt ( &nChains );
+    if (nChains>0)  {
+      chain = new ChainID[nChains];
+      for (i=0;i<nChains;i++)
+        f.ReadTerLine ( chain[i],false );
+    }
+    f.ReadInt ( &nMatrices );
+    if (nMatrices>0)  {
+      tm = new mat44[nMatrices];
+      for (i=0;i<nMatrices;i++)  {
+        for (j=0;j<3;j++)  {
+          for (k=0;k<4;k++)
+            f.ReadReal ( &(tm[i][j][k]) );
+          tm[i][3][j] = 0.0;
+        }
+        tm[i][3][3] = 1.0;
+      }
+    }
+  }
+
+  MakeStreamFunctions(BMApply)
+
+
+  Biomolecule::Biomolecule() : io::Stream()  {
+    InitBiomolecule();
+  }
+
+  Biomolecule::Biomolecule ( io::RPStream Object )
+              : io::Stream ( Object )  {
+    InitBiomolecule();
+  }
+
+  Biomolecule::~Biomolecule()  {
+    FreeMemory();
+  }
+
+  void  Biomolecule::InitBiomolecule()  {
+    bmApply = NULL;
+    nBMAs   = 0;
+  }
+
+  void  Biomolecule::FreeMemory()  {
+  int i;
+    if (bmApply)  {
+      for (i=0;i<nBMAs;i++)
+        if (bmApply[i])  delete bmApply[i];
+      delete[] bmApply;
+      bmApply = NULL;
+    }
+    nBMAs = 0;
+  }
+
+
+  PBMApply Biomolecule::addBMApply()  {
+  PPBMApply bmA1;
+  int       i;
+    bmA1 = bmApply;
+    bmApply = new PBMApply[nBMAs+1];
+    for (i=0;i<nBMAs;i++)
+      bmApply[i] = bmA1[i];
+    if (bmA1)  delete[] bmA1;
+    bmApply[nBMAs] = new BMApply();
+    nBMAs++;
+    return bmApply[nBMAs-1];
+  }
+
+  int Biomolecule::Size()  {
+  int i,k;
+    k = 0;
+    for (i=0;i<nBMAs;i++)
+      k += bmApply[i]->nChains*bmApply[i]->nMatrices;
+    return k;
+  }
+
+  bool Biomolecule::checkComposition ( PChainID chID, ivector occ,
+                                           ivector  wocc, int n )  {
+  // chID[n] is list of chain IDs
+  // occ[n]  is list of chain occurencies
+  // wocc[n] is working array
+  int     i,j,k,k1;
+  bool cmp;
+
+    for (i=0;i<n;i++)
+      wocc[i] = 0;
+
+    cmp = true;
+
+    for (i=0;(i<nBMAs) && cmp;i++)
+      for (j=0;(j<bmApply[i]->nChains) && cmp;j++)  {
+        k1 = -1;
+        for (k=0;(k<n) && (k1<0);k++)
+          if (!strcmp(chID[k],bmApply[i]->chain[j]))
+            k1 = k;
+        if (k1<0)  cmp = false;  // chain not found in the list
+             else  wocc[k1] += bmApply[i]->nMatrices;
+      }
+
+    for (i=0;(i<n) && cmp;i++)
+      if (occ[i]!=wocc[i])  cmp = false;
+
+    return cmp;
+
+  }
+
+  void  Biomolecule::Copy ( PBiomolecule B )  {
+  // if B is NULL, then empties the class
+  int  i;
+
+    FreeMemory();
+
+    if (B)  {
+
+      nBMAs = B->nBMAs;
+      if (nBMAs>0)  {
+        bmApply = new PBMApply[nBMAs];
+        for (i=0;i<nBMAs;i++)
+          if (B->bmApply[i])  {
+            bmApply[i] = new BMApply();
+            bmApply[i]->Copy ( B->bmApply[i] );
+          } else
+            bmApply[i] = NULL;
+      }
+
+    }
+
+  }
+
+  void  Biomolecule::write ( io::RFile f )  {
+  int i;
+    f.WriteInt ( &nBMAs );
+    for (i=0;i<nBMAs;i++)
+      StreamWrite ( f,bmApply[i] );
+  }
+
+  void  Biomolecule::read ( io::RFile f )  {
+  int i;
+    FreeMemory();
+    f.ReadInt ( &nBMAs );
+    if (nBMAs>0)  {
+      bmApply = new PBMApply[nBMAs];
+      for (i=0;i<nBMAs;i++)  {
+        bmApply[i] = NULL;
+        StreamRead ( f,bmApply[i] );
+      }
+    }
+  }
+
+  MakeStreamFunctions(Biomolecule)
+
+
+  //  =====================   Title   =======================
+
+  Title::Title() : io::Stream() {
+    Init();
+  }
+
+  Title::Title ( io::RPStream Object )  : io::Stream(Object)  {
+    Init();
+  }
+
+  void  Title::Init()  {
+
+    //  Header data
+    classification = NULL;
+    depDate[0]     = char(0);
+    idCode [0]     = char(0);
+    resolution     = -2.0;
+    col73          = false;
+
+    biomolecule    = NULL;
+    nBiomolecules  = 0;
+
+  }
+
+  Title::~Title() {
+    FreeMemory ( false );
+  }
+
+  void  Title::FreeMemory ( bool keepBiomolecules )  {
+
+    if (classification)  delete[] classification;
+    classification = NULL;
+    resolution     = -2.0;
+
+    obsData  .FreeContainer();
+    title    .FreeContainer();
+    caveat   .FreeContainer();
+    compound .FreeContainer();
+    source   .FreeContainer();
+    keyWords .Delete       ();
+    expData  .FreeContainer();
+    mdlType  .FreeContainer();
+    author   .FreeContainer();
+    revData  .FreeContainer();
+    supersede.FreeContainer();
+    journal  .FreeContainer();
+    remark   .FreeContainer();
+
+    col73 = false;
+
+    if (!keepBiomolecules)
+      FreeBiomolecules();
+
+  }
+
+  void  Title::FreeBiomolecules()  {
+  int  i;
+    if (biomolecule)  {
+      for (i=0;i<nBiomolecules;i++)
+        if (biomolecule[i])  delete biomolecule[i];
+      delete[] biomolecule;
+      biomolecule = NULL;
+    }
+    nBiomolecules = 0;
+  }
+
+
+  void  Title::SetHeader ( cpstr Classification,
+                                cpstr DepDate,
+                                cpstr IDCode )  {
+  // fills the PDB file header
+    CreateCopy ( classification ,Classification  );
+    strncpy    ( depDate,DepDate,sizeof(depDate) );
+    strncpy    ( idCode ,IDCode ,sizeof(idCode)  );
+    depDate[sizeof(depDate)-1] = char(0);
+    idCode [sizeof(idCode) -1] = char(0);
+  }
+
+  ERROR_CODE Title::ConvertPDBString ( pstr PDBString ) {
+  // Interprets the ASCII PDB line belonging to the title section
+  // and fills the corresponding fields.
+  //   Returns zero if the line was converted, otherwise returns a
+  // non-negative value of Error_XXXX.
+  //   PDBString must be not shorter than 81 characters.
+  int             i;
+  char            c;
+  PContainerClass ContainerClass;
+
+    //  pad input line with spaces, if necessary
+    PadSpaces ( PDBString,80 );
+
+    if (!strncmp(PDBString,"HEADER",6))  {
+
+      i = 49;
+      while ((i>=10) && (PDBString[i]==' '))  i--;
+      i++;
+      c = PDBString[i];
+      PDBString[i] = char(0);
+      CreateCopy ( classification,&(PDBString[10]) );
+      PDBString[i] = c;
+
+      Date9to11 ( &(PDBString[50]),depDate );
+
+      strncpy ( idCode,&(PDBString[62]),4 );
+      idCode[4] = char(0);
+
+    } else if (!strncmp(PDBString,"OBSLTE",6))  {
+
+      ContainerClass = new ObsLine(PDBString);
+      obsData.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"TITLE ",6))  {
+
+      ContainerClass = new TitleLine(PDBString);
+      title.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"CAVEAT",6))  {
+
+      ContainerClass = new Caveat(PDBString);
+      caveat.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"COMPND",6))  {
+
+      ContainerClass = new Compound(PDBString);
+      compound.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"SOURCE",6))  {
+
+      ContainerClass = new Source(PDBString);
+      source.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"KEYWDS",6))  {
+
+      keyWords.ConvertPDBASCII ( PDBString );
+
+    } else if (!strncmp(PDBString,"EXPDTA",6))  {
+
+      ContainerClass = new ExpData(PDBString);
+      expData.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"MDLTYPE",6))  {
+
+      ContainerClass = new MdlType(PDBString);
+      mdlType.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"AUTHOR",6))  {
+
+      ContainerClass = new Author(PDBString);
+      author.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"REVDAT",6))  {
+
+      ContainerClass = new RevData(PDBString);
+      revData.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"SPRSDE",6))  {
+
+      ContainerClass = new Supersede(PDBString);
+      supersede.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"JRNL  ",6))  {
+
+      ContainerClass = new Journal(PDBString);
+      journal.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"REMARK",6))  {
+
+      ContainerClass = new Remark(PDBString);
+      remark.AddData ( ContainerClass );
+
+    } else if (!strncmp(PDBString,"SPLIT ",6))  {
+      // do nothing at the moment
+    } else
+      return Error_WrongSection;
+
+    //  check for ID code in columns 73-80
+
+    if (!col73)  {
+      if (('0'<=idCode[0]) && (idCode[0]<='9'))  {
+        if (!strncasecmp(idCode,&(PDBString[72]),4))
+          col73 = true;
+      }
+    }
+
+    return  Error_NoError;
+
+  }
+
+  realtype Title::GetResolution()  {
+  //  returns -1.0 if there is no resolution record in the file
+  PRemark rem;
+  pstr     p,eptr;
+  int      i,l;
+    if (resolution>-1.5)  return resolution;
+    l = remark.Length();
+    for (i=0;(i<l) && (resolution<-1.5);i++)  {
+      rem = (PRemark)remark.GetContainerClass ( i );
+      if (rem)  {
+        if (rem->remarkNum==2)  {
+          if (rem->remark)  {
+            p = strcasestr ( rem->remark,"RESOLUTION" );
+            if (p)  {
+              while ((*p) && (*p!=' '))  p++;
+              if (*p)  {
+                resolution = strtod ( p,&eptr );
+                if ((resolution<0.0) || (eptr==p))
+                  resolution = -1.0;
+              }
+            }
+          }
+        } else if (rem->remarkNum>2)
+          resolution = -1.0;
+      }
+    }
+    return resolution;
+  }
+
+  PBiomolecule Title::addBiomolecule()  {
+  PPBiomolecule  BM1;
+  int             i;
+    BM1 = biomolecule;
+    biomolecule = new PBiomolecule[nBiomolecules+1];
+    for (i=0;i<nBiomolecules;i++)
+      biomolecule[i] = BM1[i];
+    if (BM1)  delete[] BM1;
+    biomolecule[nBiomolecules] = new Biomolecule();
+    nBiomolecules++;
+    return biomolecule[nBiomolecules-1];
+  }
+
+  int Title::ParseBiomolecules()  {
+  PRemark       rem;
+  PBiomolecule  BMol;
+  PBMApply      BMA;
+  int            i,l, lkey;
+
+    FreeBiomolecules();
+
+    l    = remark.Length();
+    i    = 0;
+    lkey = 0;
+    while ((i<l) && (!lkey))  {
+      rem = (PRemark)remark.GetContainerClass ( i );
+      if (rem)  {
+        if (rem->remarkNum==350)      lkey = 1;
+        else if (rem->remarkNum>350)  lkey = -1;
+      }
+      if (!lkey) i++;
+    }
+
+    BMol = NULL;
+    BMA  = NULL;
+
+    while (lkey>0)  {
+
+      rem = (PRemark)remark.GetContainerClass ( i );
+      lkey = lookupRemarks ( i,rem,remark );
+
+      switch (lkey)  {
+        case R350_BIOMOLECULE : BMol = addBiomolecule();
+                                i++;
+                              break;
+        case R350_CHAINS      : if (BMol)  {
+                                  BMA = BMol->addBMApply();
+                                  while (lkey==R350_CHAINS)
+                                    lkey = BMA->addChains(i,rem,remark);
+                                } else
+                                  lkey = R350_ERROR;
+                              break;
+        case R350_BIOMT       : if (BMA)
+                                  lkey = BMA->addMatrices(i,rem,remark);
+                                else
+                                  lkey = R350_ERROR;
+                              break;
+        default : i++;
+      }
+
+    }
+
+    if (lkey<=R350_ERROR)  {
+      FreeBiomolecules();
+      return lkey;
+    }
+
+    return nBiomolecules;
+
+  }
+
+  int Title::GetNofBiomolecules()  {
+    return nBiomolecules;
+  }
+
+  void Title::GetBiomolecules ( PPBiomolecule & BM, int & nBMs ) {
+    BM   = biomolecule;
+    nBMs = nBiomolecules;
+  }
+
+  PBiomolecule Title::GetBiomolecule ( int bmNo )  { // bmno=0,1,..
+    if ((0<=bmNo) && (bmNo<nBiomolecules))
+      return biomolecule[bmNo];
+    return NULL;
+  }
+
+
+  ERROR_CODE Title::GetCIF ( mmcif::PData CIF )  {
+  pstr       S;
+  ERROR_CODE RC;
+
+    S = NULL;
+    CIF->GetDataName ( S,true );
+    if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_ENTRY_ID,true );
+    if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_CODE_NDB,true );
+    if (!S) CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_CODE_PDB,true );
+    if (S)  {
+      strncpy ( idCode,S,sizeof(IDCode)-1 );
+      idCode[sizeof(IDCode)-1] = char(0);
+      delete[] S;
+      S = NULL;
+      CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
+      CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_CODE_NDB );
+      CIF->DeleteField ( CIFCAT_DATABASE,CIFTAG_CODE_PDB );
+    } else
+      idCode[0] = char(0);
+    CIF->GetString ( classification,CIFCAT_STRUCT_KEYWORDS,
+                                    CIFTAG_NDB_KEYWORDS,true );
+    CIF->GetString ( S,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL,true );
+    if (S)  {
+      DateCIFto11 ( S,depDate );
+      delete[] S;
+      S = NULL;
+    } else
+      depDate[0] = char(0);
+
+    if (CIF->GetReal(resolution,CIFCAT_REFINE,
+                     CIFTAG_LS_D_RES_HIGH,false)!=mmcif::CIFRC_Ok)
+      resolution = -2.0;
+
+    obsData .GetCIF ( CIF,ClassID_ObsLine   );
+    title   .GetCIF ( CIF,ClassID_TitleLine );
+    caveat  .GetCIF ( CIF,ClassID_CAVEAT    );
+    compound.GetCIF ( CIF,ClassID_Compound  );
+    source  .GetCIF ( CIF,ClassID_Source    );
+    keyWords.GetCIF ( CIF );
+    expData .GetCIF ( CIF,ClassID_ExpData   );
+    mdlType .GetCIF ( CIF,ClassID_MdlType   );
+    author  .GetCIF ( CIF,ClassID_Author    );
+    RC = revData.GetCIF ( CIF,ClassID_RevData );
+    if (RC!=Error_NoError)  {
+      supersede.GetCIF ( CIF,ClassID_Supersede );
+      journal  .GetCIF ( CIF,ClassID_Journal   );
+      RC = remark.GetCIF ( CIF,ClassID_Remark );
+    }
+    return RC;
+
+  }
+
+  void  Title::MakePDBHeaderString ( pstr PDBString )  {
+  //  makes the ASCII PDB HEADER line from the class' data
+  int i;
+
+    if (classification)  {
+
+      strcpy ( PDBString,"HEADER    " );
+      strcat ( PDBString,classification );
+      i = strlen(PDBString);
+      while (i<80)
+        PDBString[i++] = ' ';
+      PDBString[IMin(i,80)] = char(0);
+      Date11to9 ( depDate,&(PDBString[50]) );
+      strncpy   ( &(PDBString[62]),idCode,4 );
+
+    } else
+      strcpy ( PDBString,
+        "HEADER    XXXXXXXXXXXXXXXXXXXXXXXXXXXX            XX-XXX-XX   ----" );
+
+  }
+
+  pstr  Title::GetStructureTitle ( pstr & S )  {
+  // GetStructureTitle() returns the contents of TITLE record
+  // unfolded into single line. If Title is missing, returns
+  // contents of COMPND(:MOLECULE). If COMPND is missing, returns
+  // HEADER. If Header is missing, returns PDB code. If no PDB
+  // code is there, returns "Not available".
+  PTitleLine TLine;
+  PCompound  CLine;
+  pstr        p;
+  int         i,cl,l;
+  bool     B;
+
+    if (S)  delete[] S;
+    S  = NULL;
+
+    cl = title.Length();
+    if (cl>0)  {
+      l = 0;
+      for (i=0;i<cl;i++)  {
+        TLine = PTitleLine(title.GetContainerClass(i));
+        if (TLine)  l += strlen_des(TLine->Line)+5;
+      }
+      S = new char[l];
+      S[0] = char(0);
+      for (i=0;i<cl;i++)  {
+        TLine = PTitleLine(title.GetContainerClass(i));
+        if (TLine)  {
+          if (i>0)  strcat ( S," " );
+          strcat_des ( S,TLine->Line );
+        }
+      }
+    } else  {
+      cl = compound.Length();
+      if (cl>0)  {
+        l = 0;
+        p = NULL;
+        B = true;
+        for (i=0;(i<cl) && B;i++)  {
+          CLine = PCompound(compound.GetContainerClass(i));
+          if (CLine)  {
+            if (!p)  {
+              p = strstr(CLine->Line,"MOLECULE:");
+              if (p)  l += strlen_des(&(p[9]))+5;
+            } else  {
+              p = strstr(CLine->Line,"MOLECULE:");
+              if (p)
+                l += strlen_des(&(p[9]))+5;
+              else {
+                p = strchr(CLine->Line,':');
+                if (!p)  {
+                  l += strlen_des(CLine->Line)+5;
+                  p = CLine->Line;
+                } else
+                  B = false;
+              }
+            }
+          }
+        }
+        if (l>0)  {
+          S = new char[l];
+          S[0] = char(0);
+          p = NULL;
+          B = true;
+          for (i=0;(i<cl) && B;i++)  {
+            CLine = PCompound(compound.GetContainerClass(i));
+            if (CLine)  {
+              if (!p)  {
+                p = strstr(CLine->Line,"MOLECULE:");
+                if (p)  strcat_des ( S,&(p[9]) );
+              } else  {
+                p = strstr(CLine->Line,"MOLECULE:");
+                if (p)
+                  strcat_des ( S,&(p[9]) );
+                else {
+                  p = strchr(CLine->Line,':');
+                  if (!p)  {
+                    strcat_des ( S,CLine->Line );
+                    p = CLine->Line;
+                  } else
+                    B = false;
+                }
+              }
+              l = strlen(S)-1;
+              if (S[l]==';')  S[l] = char(0);
+            }
+          }
+        } else  {
+          l = 0;
+          for (i=0;i<cl;i++)  {
+            CLine = PCompound(compound.GetContainerClass(i));
+            if (CLine)  l += strlen_des(CLine->Line)+5;
+          }
+          S = new char[l];
+          S[0] = char(0);
+          for (i=0;i<cl;i++)  {
+            CLine = PCompound(compound.GetContainerClass(i));
+            if (CLine)  {
+              if (i>0)  strcat ( S," " );
+              strcat_des ( S,CLine->Line );
+            }
+          }
+        }
+      } else if (classification)
+        CreateCopy ( S,classification );
+      else if (idCode[0])
+        CreateCopy ( S,idCode );
+      else
+        CreateCopy ( S,pstr("Not available") );
+    }
+
+    if (!S[0])  CreateCopy ( S,pstr("Not available") );
+
+    return S;
+
+  }
+
+  void  Title::PDBASCIIDump ( io::RFile f )  {
+  char  PDBString[100];
+    if (classification)  {
+      MakePDBHeaderString ( PDBString );
+      f.WriteLine ( PDBString );
+    }
+    obsData  .PDBASCIIDump ( f );
+    title    .PDBASCIIDump ( f );
+    caveat   .PDBASCIIDump ( f );
+    compound .PDBASCIIDump ( f );
+    source   .PDBASCIIDump ( f );
+    keyWords .PDBASCIIDump ( f );
+    expData  .PDBASCIIDump ( f );
+    mdlType  .PDBASCIIDump ( f );
+    author   .PDBASCIIDump ( f );
+    revData  .PDBASCIIDump ( f );
+    supersede.PDBASCIIDump ( f );
+    journal  .PDBASCIIDump ( f );
+    remark   .PDBASCIIDump ( f );
+  }
+
+
+  void  Title::MakeCIF ( mmcif::PData CIF )  {
+  char DateCIF[20];
+
+    if (idCode[0])  {
+      CIF->PutDataName ( idCode );
+      CIF->PutString   ( idCode, CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
+      CIF->PutString   ( idCode, CIFCAT_DATABASE,CIFTAG_CODE_NDB );
+      CIF->PutString   ( idCode, CIFCAT_DATABASE,CIFTAG_CODE_PDB );
+    } else  {
+      CIF->PutDataName ( pstr("")                              );
+      CIF->PutString   ( NULL, CIFCAT_DATABASE,CIFTAG_ENTRY_ID );
+      CIF->PutString   ( NULL, CIFCAT_DATABASE,CIFTAG_CODE_NDB );
+      CIF->PutString   ( NULL, CIFCAT_DATABASE,CIFTAG_CODE_PDB );
+    }
+    CIF->PutString   ( classification, CIFCAT_STRUCT_KEYWORDS,
+                                       CIFTAG_NDB_KEYWORDS );
+    if (depDate[0])  {
+      Date11toCIF ( depDate,DateCIF );
+      CIF->PutString ( DateCIF,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL );
+    } else
+      CIF->PutString ( NULL,CIFCAT_DATABASE,CIFTAG_DATE_ORIGINAL );
+
+    CIF->PutReal ( resolution,CIFCAT_REFINE,CIFTAG_LS_D_RES_HIGH,3 );
+
+    obsData  .MakeCIF ( CIF );
+    title    .MakeCIF ( CIF );
+    caveat   .MakeCIF ( CIF );
+    compound .MakeCIF ( CIF );
+    source   .MakeCIF ( CIF );
+    keyWords .MakeCIF ( CIF );
+    expData  .MakeCIF ( CIF );
+    mdlType  .MakeCIF ( CIF );
+    author   .MakeCIF ( CIF );
+    revData  .MakeCIF ( CIF );
+    supersede.MakeCIF ( CIF );
+    journal  .MakeCIF ( CIF );
+    remark   .MakeCIF ( CIF );
+
+  }
+
+  void  Title::Copy ( PTitle TS )  {
+  int  i;
+
+    FreeBiomolecules();
+
+    if (TS)  {
+
+      CreateCopy ( classification,TS->classification );
+      strcpy     ( depDate       ,TS->depDate        );
+      strcpy     ( idCode        ,TS->idCode         );
+      resolution = TS->resolution;
+
+      obsData  .Copy ( &(TS->obsData)   );
+      title    .Copy ( &(TS->title)     );
+      caveat   .Copy ( &(TS->caveat)    );
+      compound .Copy ( &(TS->compound)  );
+      source   .Copy ( &(TS->source)    );
+      keyWords .Copy ( &(TS->keyWords)  );
+      expData  .Copy ( &(TS->expData)   );
+      mdlType  .Copy ( &(TS->mdlType)   );
+      author   .Copy ( &(TS->author)    );
+      revData  .Copy ( &(TS->revData)   );
+      supersede.Copy ( &(TS->supersede) );
+      journal  .Copy ( &(TS->journal)   );
+      remark   .Copy ( &(TS->remark)    );
+
+      nBiomolecules = TS->nBiomolecules;
+      if (nBiomolecules>0)  {
+        biomolecule = new PBiomolecule[nBiomolecules];
+        for (i=0;i<nBiomolecules;i++)
+          if (TS->biomolecule[i])  {
+            biomolecule[i] = new Biomolecule();
+            biomolecule[i]->Copy ( TS->biomolecule[i] );
+          } else
+            biomolecule[i] = NULL;
+      }
+
+    } else  {
+
+      if (classification)  delete[] classification;
+      classification = NULL;
+      resolution     = -2.0;
+      obsData  .FreeContainer();
+      title    .FreeContainer();
+      caveat   .FreeContainer();
+      compound .FreeContainer();
+      source   .FreeContainer();
+      keyWords .Delete       ();
+      expData  .FreeContainer();
+      mdlType  .FreeContainer();
+      author   .FreeContainer();
+      revData  .FreeContainer();
+      supersede.FreeContainer();
+      journal  .FreeContainer();
+      remark   .FreeContainer();
+
+    }
+
+  }
+
+  void  Title::TrimInput ( pstr PDBString )  {
+    if (col73)  {
+      if (!strncasecmp(idCode,&(PDBString[72]),4))
+        PDBString[72] = char(0);
+    }
+    PadSpaces ( PDBString,80 );
+  }
+
+  void  Title::write ( io::RFile f )  {
+  // writes header to PDB binary file
+  int  i;
+  byte Version=3;
+
+    f.WriteByte    ( &Version       );
+
+    //  Header data
+    f.CreateWrite  ( classification );
+    f.WriteTerLine ( depDate,false  );
+    f.WriteTerLine ( idCode ,false  );
+    f.WriteReal    ( &resolution    );
+
+    obsData  .write ( f );  //  Obsoletion data
+    title    .write ( f );  //  Title
+    caveat   .write ( f );  //  Error data
+    compound .write ( f );  //  Compound
+    source   .write ( f );  //  Source
+    keyWords .write ( f );  //  Key words
+    expData  .write ( f );  //  Experimental data
+    mdlType  .write ( f );  //  Model descriptions
+    author   .write ( f );  //  Author data
+    revData  .write ( f );  //  Revision data
+    supersede.write ( f );  //  Supersede records
+    journal  .write ( f );  //  Journal records
+    remark   .write ( f );  //  Remarks
+
+    f.WriteInt ( &nBiomolecules );
+    for (i=0;i<nBiomolecules;i++)
+      StreamWrite ( f,biomolecule[i] );
+
+  }
+
+  void  Title::read ( io::RFile f )  {
+  // reads header from PDB binary file
+  int  i;
+  byte Version;
+
+    f.ReadByte    ( &Version );
+
+    //  Header data
+    f.CreateRead  ( classification );
+    f.ReadTerLine ( depDate,false  );
+    f.ReadTerLine ( idCode ,false  );
+    if (Version>1)
+      f.ReadReal  ( &resolution    );
+    else
+      resolution = -2.0;
+
+    obsData  .read ( f );   //  Obsoletion data
+    title    .read ( f );   //  Title
+    caveat   .read ( f );   //  Error data
+    compound .read ( f );   //  Compound
+    source   .read ( f );   //  Source
+    keyWords .read ( f );   //  Key words
+    expData  .read ( f );   //  Experimental data
+    if (Version>2)
+      mdlType.read ( f );   //  Model descriptions
+    author   .read ( f );   //  Author data
+    revData  .read ( f );   //  Revision data
+    supersede.read ( f );   //  Supersede records
+    journal  .read ( f );   //  Journal records
+    remark   .read ( f );   //  Remarks
+
+    FreeBiomolecules();
+    if (Version>1)  {
+      f.ReadInt ( &nBiomolecules );
+      if (nBiomolecules>0)  {
+        biomolecule = new PBiomolecule[nBiomolecules];
+        for (i=0;i<nBiomolecules;i++)  {
+          biomolecule[i] = NULL;
+          StreamRead ( f,biomolecule[i] );
+        }
+      }
+    }
+
+  }
+
+  MakeStreamFunctions(Title)
+
+}  // namespace mmdb
+
+
+// ===================================================================
+
+/*
+void  TestHeader()  {
+PTitle  Hdr;
+char         S[81],S1[81];
+
+  Hdr = new Title();
+
+  Hdr->SetHeader ( pstr("MUSCLE PROTEIN"),pstr("02-JUN-1993"),pstr("1MYS") );
+  Hdr->MakePDBHeaderString ( S );
+  printf ( "1234567890123456789012345678901234567890"
+           "1234567890123456789012345678901234567890\n" );
+  printf ( S );
+  printf ( "\n" );
+
+  strcpy ( S,
+// 1234567890123456789012345678901234567890123456789012345678901234567890
+  "HEADER    HYDROLASE (CARBOXYLIC ESTER)            07-APR-01   2PHI" );
+
+  Hdr->ConvertPDBString ( S );
+  Hdr->MakePDBHeaderString    ( S1 );
+  printf ( "1234567890123456789012345678901234567890"
+           "1234567890123456789012345678901234567890\n" );
+  printf ( S1 );
+  printf ( "\n" );
+
+  Hdr->SetHeader (
+     pstr("MUSCLE PROTEIN;**A VERY LONG TITLE TEST;**ARBITRARY LENGTH"),
+     pstr("02-JUN-1993"),pstr("1MYS") );
+  Hdr->MakePDBHeaderString ( S );
+  printf ( "1234567890123456789012345678901234567890"
+           "1234567890123456789012345678901234567890\n" );
+  printf ( S );
+  printf ( "\n" );
+
+  delete Hdr;
+
+  printf ( " header deleted \n" );
+
+}
+
+void  TestTitle() {
+// reads PDB title from file 'in.title'
+// and rewrites it into 'out.title' and 'abin.title'
+CFile        f;
+char         S[81];
+PTitle  Title;
+
+  Title = new Title();
+
+  f.assign ( pstr("in.title"),true );
+  if (f.reset()) {
+    while (!f.FileEnd()) {
+      f.ReadLine ( S,sizeof(S) );
+      Title->ConvertPDBString ( S );
+    }
+    f.shut();
+  } else {
+    printf ( " Can't open input file 'in.title' \n" );
+    delete Title;
+    return;
+  }
+
+  f.assign ( pstr("out.title"),true );
+  if (f.rewrite()) {
+    Title->PDBASCIIDump ( f );
+    f.shut();
+  } else {
+    printf ( " Can't open output file 'out.title' \n" );
+    delete Title;
+    return;
+  }
+
+
+
+  f.assign ( pstr("mmdb.title.bin"),false );
+  if (f.rewrite()) {
+    Title->write ( f );
+    f.shut();
+  } else {
+    printf ( "  Can't open binary file for writing.\n" );
+    delete Title;
+    return;
+  }
+
+  delete Title;
+  printf ( "   Title deleted.\n" );
+
+  Title = new Title();
+  if (f.reset()) {
+    Title->read ( f );
+    f.shut();
+  } else {
+    printf ( "  Can't open binary file for reading.\n" );
+    delete Title;
+    return;
+  }
+
+  f.assign ( pstr("abin.title"),true );
+  if (f.rewrite()) {
+    Title->PDBASCIIDump ( f );
+    f.shut();
+  } else {
+    printf ( " Can't open output file 'abin.title' \n" );
+  }
+
+  delete Title;
+
+}
+
+
+*/
diff --git a/mmdb2/mmdb_title.h b/mmdb2/mmdb_title.h
new file mode 100644
index 0000000..1e00d38
--- /dev/null
+++ b/mmdb2/mmdb_title.h
@@ -0,0 +1,696 @@
+//  $Id: mmdb_title.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_Title <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::TitleContainer  (container of title classes)
+//       ~~~~~~~~~  mmdb::ObsLine
+//                  mmdb::TitleLine
+//                  mmdb::Caveat
+//                  mmdb::Compound
+//                  mmdb::Source
+//                  mmdb::KeyWords
+//                  mmdb::ExpData
+//                  mmdb::MdlType
+//                  mmdb::Author
+//                  mmdb::RevData
+//                  mmdb::Supersede
+//                  mmdb::Journal
+//                  mmdb::Remark
+//                  mmdb::Biomolecule
+//                  mmdb::Title       ( MMDB title section )
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Title__
+#define __MMDB_Title__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_defs.h"
+#include "mmdb_utils.h"
+#include "mmdb_mmcif_.h"
+
+namespace mmdb  {
+
+  //  ======================  TitleContainer  =======================
+
+  DefineClass(TitleContainer);
+  DefineStreamFunctions(TitleContainer);
+
+  class TitleContainer : public ClassContainer  {
+
+    public :
+
+      TitleContainer () : ClassContainer() {}
+      TitleContainer ( io::RPStream Object )
+                        : ClassContainer ( Object ) {}
+      ~TitleContainer() {}
+
+      PContainerClass MakeContainerClass ( int ClassID );
+
+  };
+
+
+  //  ==================  ObsLine  ========================
+
+  DefineClass(ObsLine);
+  DefineStreamFunctions(ObsLine);
+
+  class ObsLine : public ContainerClass  {
+
+    public :
+
+      Date   repDate;    //  date of replacement
+      IDCode idCode;     //  ID code of replaced entry
+      IDCode rIdCode[8]; //  ID codes of entries that replaced this one
+
+      ObsLine ();
+      ObsLine ( cpstr S );
+      ObsLine ( io::RPStream Object );
+      ~ObsLine();
+
+      void       PDBASCIIDump    ( pstr S, int N   );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_ObsLine; }
+
+      void  Copy  ( PContainerClass ObsLine );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitObsLine();
+
+  };
+
+
+  //  ====================  TitleLine  =====================
+
+  DefineClass(TitleLine);
+  DefineStreamFunctions(TitleLine);
+
+  class TitleLine : public ContString  {
+
+    public :
+
+      TitleLine ();
+      TitleLine ( cpstr S );
+      TitleLine ( io::RPStream Object );
+      ~TitleLine();
+
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      void       PDBASCIIDump    ( pstr S, int N );
+      bool       PDBASCIIDump1   ( io::RFile ) { return false; }
+      CLASS_ID   GetClassID      () { return ClassID_TitleLine; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitTitleLine();
+
+  };
+
+
+  //  ====================  Caveat  =====================
+
+  DefineClass(Caveat);
+  DefineStreamFunctions(Caveat);
+
+  class Caveat : public ContString  {
+
+    public :
+
+      IDCode idCode;   //  ID code of the entry
+
+      Caveat ();
+      Caveat ( cpstr S );
+      Caveat ( io::RPStream Object );
+      ~Caveat();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      bool       PDBASCIIDump1   ( io::RFile ) { return false; }
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+
+//      virtual void  GetCIF1      ( mmcif::PData CIF, ERROR_CODE & Signal,
+//                                   int & pos );
+
+      CLASS_ID   GetClassID      () { return ClassID_CAVEAT; }
+
+      void  Copy  ( PContainerClass Caveat );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitCaveat();
+
+  };
+
+
+  //  ====================  Compound  =====================
+
+  DefineClass(Compound);
+  DefineStreamFunctions(Compound);
+
+  class Compound : public ContString  {
+
+    public :
+
+      Compound ();
+      Compound ( cpstr S );
+      Compound ( io::RPStream Object );
+      ~Compound();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      bool       PDBASCIIDump1   ( io::RFile  ) { return false; }
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_Compound; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitCompound();
+
+  };
+
+
+  //  ====================  Source  =====================
+
+  DefineClass(Source);
+  DefineStreamFunctions(Source);
+
+  class Source : public ContString  {
+
+    public :
+
+      Source ();
+      Source ( cpstr S );
+      Source ( io::RPStream Object );
+      ~Source();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      bool       PDBASCIIDump1   ( io::RFile  ) { return false; }
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_Source; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitSource();
+
+  };
+
+
+  //  ====================  KeyWords  =====================
+
+  DefineClass(KeyWords);
+  DefineStreamFunctions(KeyWords);
+
+  class KeyWords : public io::Stream  {
+
+    public :
+      int      nKeyWords;     // number of key words
+      psvector KeyWord;       // key word array
+
+      KeyWords ();
+      KeyWords ( cpstr S );
+      KeyWords ( io::RPStream Object );
+      ~KeyWords();
+
+      void  Delete          ();
+
+      void  PDBASCIIDump    ( io::RFile f );
+      void  MakeCIF         ( mmcif::PData CIF );
+
+      int   ConvertPDBASCII ( cpstr S );
+      void  GetCIF          ( mmcif::PData CIF );
+
+      void  Copy  ( PKeyWords KeyWords );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      bool Cont;
+
+      void  Init();
+
+  };
+
+
+  //  ====================  ExpData  =====================
+
+  DefineClass(ExpData);
+  DefineStreamFunctions(ExpData);
+
+  class ExpData : public ContString  {
+
+    public :
+
+      ExpData ();
+      ExpData ( cpstr S );
+      ExpData ( io::RPStream Object );
+      ~ExpData();
+
+      void       PDBASCIIDump  ( pstr S, int N );
+      bool       PDBASCIIDump1 ( io::RFile ) { return false; }
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_ExpData; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitExpData();
+
+  };
+
+
+  //  ====================  MdlType  =====================
+
+  DefineClass(MdlType);
+  DefineStreamFunctions(MdlType);
+
+  class MdlType : public ContString  {
+
+    public :
+
+      MdlType ();
+      MdlType ( cpstr S );
+      MdlType ( io::RPStream Object );
+      ~MdlType();
+
+      void       PDBASCIIDump  ( pstr S, int N );
+      bool       PDBASCIIDump1 ( io::RFile ) { return false; }
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_MdlType; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitMdlType();
+
+  };
+
+
+  //  ====================  Author  =====================
+
+  DefineClass(Author);
+  DefineStreamFunctions(Author);
+
+  class Author : public ContString  {
+
+    public :
+
+      Author ();
+      Author ( cpstr S );
+      Author ( io::RPStream Object );
+      ~Author();
+
+      void       PDBASCIIDump  ( pstr S, int N   );
+      bool       PDBASCIIDump1 ( io::RFile ) { return false; }
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_Author; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitAuthor();
+
+  };
+
+
+  //  ====================  RevData  =====================
+
+  DefineClass(RevData);
+  DefineStreamFunctions(RevData);
+
+  enum REVDAT_WARNING  {
+    REVDAT_WARN_MODNUM  = 0x00000001,
+    REVDAT_WARN_MODTYPE = 0x00000002
+  };
+
+  class RevData : public ContainerClass  {
+
+    public :
+      int     modNum;
+      Date    modDate;
+      char    modId[13];
+      int     modType;
+      RecName record[4];
+      word    Warning;
+
+      RevData ();
+      RevData ( cpstr S );
+      RevData ( io::RPStream Object );
+      ~RevData();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_RevData; }
+
+      void  Copy  ( PContainerClass RevData );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitRevData();
+
+  };
+
+
+  //  ==================  Supersede  ========================
+
+  DefineClass(Supersede);
+  DefineStreamFunctions(Supersede);
+
+  class Supersede : public ContainerClass  {
+
+    public :
+      Date   sprsdeDate;  //  date of supersede
+      IDCode idCode;      //  ID code of the entry
+      IDCode sIdCode[8];  //  ID codes of superseded entries
+
+      Supersede ();
+      Supersede ( cpstr S );
+      Supersede ( io::RPStream Object );
+      ~Supersede();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_Supersede; }
+
+      void  Copy  ( PContainerClass Supersede );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitSupersede();
+
+  };
+
+
+  //  ====================  Journal  =====================
+
+  DefineClass(Journal);
+  DefineStreamFunctions(Journal);
+
+  class Journal : public ContString  {
+
+    public :
+
+      Journal ();
+      Journal ( cpstr S );
+      Journal ( io::RPStream Object );
+      ~Journal();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      bool       PDBASCIIDump1   ( io::RFile ) { return false; }
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      CLASS_ID   GetClassID      () { return ClassID_Journal; }
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitJournal();
+
+  };
+
+
+  //  ====================  Remark  =====================
+
+  DefineClass(Remark);
+  DefineStreamFunctions(Remark);
+
+  class Remark : public ContainerClass  {
+
+    public :
+
+      int  remarkNum;  // remark id
+      pstr remark;     // remark line
+
+      Remark ();
+      Remark ( cpstr S );
+      Remark ( io::RPStream Object );
+      ~Remark();
+
+      void       PDBASCIIDump    ( pstr S, int N );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      ERROR_CODE GetCIF          ( mmcif::PData CIF, int & n );
+      CLASS_ID   GetClassID      () { return ClassID_Remark; }
+
+      void  Copy  ( PContainerClass RemarkClass );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+
+      void InitRemark();
+
+  };
+
+  //  =================  Biomolecule  =====================
+
+  DefineClass(BMApply);
+  DefineStreamFunctions(BMApply);
+
+  class BMApply : public io::Stream  {
+
+    public :
+      PChainID  chain;
+      int       nChains;
+      pmat44    tm;
+      int       nMatrices;
+
+      BMApply ();
+      BMApply ( io::RPStream Object );
+      ~BMApply();
+
+      void  FreeMemory();
+
+      int   addChains ( int & i, RPRemark rem, RTitleContainer Remark );
+      int addMatrices ( int & i, RPRemark rem, RTitleContainer Remark );
+
+      void  Copy  ( PBMApply BMA );  // if BMA is NULL, then empties
+                                      // the class
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      void  InitBMApply();
+
+  };
+
+
+  DefineClass(Biomolecule);
+  DefineStreamFunctions(Biomolecule);
+
+  class Biomolecule : public io::Stream  {
+
+    public :
+      PPBMApply bmApply;
+      int       nBMAs;
+
+      Biomolecule ();
+      Biomolecule ( io::RPStream Object );
+      ~Biomolecule();
+
+      void  FreeMemory();
+
+      PBMApply addBMApply();
+
+      int   Size();
+      bool  checkComposition ( PChainID chID, ivector occ,
+                               ivector  wocc, int n );
+
+      void  Copy  ( PBiomolecule B );  // if B is NULL, then empties
+                                        // the class
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      void  InitBiomolecule();
+
+  };
+
+  //  =================  Title  =======================
+
+  DefineClass(Title);
+  DefineStreamFunctions(Title);
+
+  class Title : public io::Stream  {
+
+    friend class Model;
+    friend class Chain;
+    friend class Root;
+
+    public :
+
+      Title ();
+      Title ( io::RPStream Object );
+      ~Title();
+
+      void  FreeMemory ( bool keepBiomolecules );
+
+      // Fills the PDB file header
+      void  SetHeader ( cpstr Classification, // any length is Ok
+                        cpstr DepDate,    // DD-MMM-YYYY
+                        cpstr ID_Code );  // not more than 11 chars
+
+      // Interprets the ASCII PDB line belonging to the title section
+      // and fills the corresponding fields.
+      //   Returns zero if the line was converted, otherwise returns a
+      // non-negative value of Error_XXXX.
+      //   PDBString must be not shorter than 81 characters.
+      ERROR_CODE ConvertPDBString ( pstr PDBString );
+
+      // MakePDBString() makes the ASCII PDB HEADER line from the
+      // class data. PDBString must be not shorter than 81 characters.
+      void  MakePDBHeaderString ( pstr PDBString );
+
+      // GetStructureTitle() returns the contents of TITLE record
+      // unfolded into single line. If Title is missing, returns
+      // contents of COMPND(:MOLECULE). If COMPND is missing, returns
+      // HEADER. If Header is missing, returns PDB code. If no PDB
+      // code is there, returns "Not available".
+      pstr  GetStructureTitle ( pstr & S );
+
+      PTitleContainer GetObsData () { return &obsData;  }
+      PTitleContainer GetCaveat  () { return &caveat;   }
+      PTitleContainer GetCompound() { return &compound; }
+      PTitleContainer GetSource  () { return &source;   }
+      PKeyWords       GetKeyWords() { return &keyWords; }
+      PTitleContainer GetExpData () { return &expData;  }
+      PTitleContainer GetMdlType () { return &mdlType;  }
+      PTitleContainer GetRemarks () { return &remark;   }
+      PTitleContainer GetJournal () { return &journal;  }
+
+      realtype GetResolution(); // -1.0 mean no resolution record in file
+
+      int   ParseBiomolecules(); // returns the number of biomolecules,
+                                 // -2 for general format error
+                                 // -3 for errors in BIOMT records
+
+      int   GetNofBiomolecules();
+      void  GetBiomolecules   ( PPBiomolecule & BM, int & nBMs );
+      PBiomolecule GetBiomolecule ( int bmNo ); // bmno=0,1,..
+                                 // returns NULL if bmNo is incorrect
+
+      void  PDBASCIIDump ( io::RFile      f   );
+      void  MakeCIF      ( mmcif::PData CIF );
+
+      //   GetCIF(..) returns the same code as ConvertPDBString(..)
+      // save for Error_WrongSection
+      ERROR_CODE  GetCIF ( mmcif::PData CIF );
+
+      inline pstr  GetIDCode() { return idCode; }
+      inline bool  GetCol73 () { return col73;  }
+      void  TrimInput ( pstr PDBString );
+
+      void  Copy  ( PTitle TS );  // if TS is NULL, then empties
+                                       // the class
+
+      void  write ( io::RFile f );    // writes header to PDB binary file
+      void  read  ( io::RFile f );    // reads header from PDB binary file
+
+    protected :
+
+      //   Header data
+      pstr     classification;  // classification of the molecule
+      Date     depDate;         // deposition date DD-MMM-YYYY
+      IDCode   idCode;          // unique PDB identifier
+      realtype resolution;      // resolution
+      bool     col73;           // True if columns 73-80 contain PDB ID
+
+      TitleContainer obsData;     // obsoletion data
+      TitleContainer title;       // title data
+      TitleContainer caveat;      // error data
+      TitleContainer compound;    // compound data
+      TitleContainer source;      // source
+      KeyWords       keyWords;    // key words
+      TitleContainer expData;     // experimental data
+      TitleContainer mdlType;     // model desctiptions
+      TitleContainer author;      // author data
+      TitleContainer revData;     // revision data
+      TitleContainer supersede;   // supersede records
+      TitleContainer journal;     // journal records
+      TitleContainer remark;      // remark records
+
+      PPBiomolecule  biomolecule;
+      int            nBiomolecules;
+
+      void  Init();
+      void  FreeBiomolecules();
+
+      PBiomolecule addBiomolecule();
+
+  };
+
+  extern void  TestHeader();
+  extern void  TestTitle (); // reads PDB title from file 'in.title'
+                             // and rewrites it into 'out.title' and
+                             // 'abin.title'
+
+}  // namespace mmdb
+
+
+#endif
+
diff --git a/mmdb2/mmdb_uddata.cpp b/mmdb2/mmdb_uddata.cpp
new file mode 100644
index 0000000..1bfcc09
--- /dev/null
+++ b/mmdb2/mmdb_uddata.cpp
@@ -0,0 +1,534 @@
+//  $Id: mmdb_uddata.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_UDData <implementation>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::UDData ( user-defined data )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+
+#include "mmdb_uddata.h"
+
+namespace mmdb  {
+
+  //  ========================  UDRegister  ==========================
+
+  #define  nUDRTypes  5
+
+  UDRegister::UDRegister() : io::Stream()  {
+    InitUDRegister();
+  }
+
+  UDRegister::UDRegister ( io::RPStream Object ) : io::Stream(Object)  {
+    InitUDRegister();
+  }
+
+  UDRegister::~UDRegister()  {
+    FreeUDRegister();
+  }
+
+  void  UDRegister::InitUDRegister()  {
+  int i;
+    for (i=0;i<nUDRTypes;i++)  {
+      nIUDR[i]       = 0;
+      nRUDR[i]       = 0;
+      nSUDR[i]       = 0;
+      IUDRegister[i] = NULL;
+      RUDRegister[i] = NULL;
+      SUDRegister[i] = NULL;
+    }
+  }
+
+  void  UDRegister::FreeUDRegister()  {
+  int i,j;
+
+    for (j=0;j<nUDRTypes;j++)  {
+
+      if (IUDRegister[j])  {
+        for (i=0;i<nIUDR[j];i++)
+          if (IUDRegister[j][i])  delete[] IUDRegister[j][i];
+        delete[] IUDRegister[j];
+        IUDRegister[j] = NULL;
+      }
+      nIUDR[j] = 0;
+
+      if (RUDRegister[j])  {
+        for (i=0;i<nRUDR[j];i++)
+          if (RUDRegister[j][i])  delete[] RUDRegister[j][i];
+        delete[] RUDRegister[j];
+        RUDRegister[j] = NULL;
+      }
+      nRUDR[j] = 0;
+      if (SUDRegister[j])  {
+        for (i=0;i<nRUDR[j];i++)
+          if (SUDRegister[j][i])  delete[] SUDRegister[j][i];
+        delete[] SUDRegister[j];
+        SUDRegister[j] = NULL;
+      }
+      nSUDR[j] = 0;
+
+    }
+
+  }
+
+  int UDRegister::RegisterUDData ( psvector & UDRegister,
+                                    int      & nUDR,
+                                    cpstr      UDDataID )  {
+  psvector UDReg;
+  int      i,UDDhandle,n;
+
+    n         = -1;
+    UDDhandle = 0;
+    for (i=0;(i<nUDR) && (!UDDhandle);i++)
+      if (UDRegister[i])  {
+        if (!strcmp(UDDataID,UDRegister[i]))
+          UDDhandle = i+1;
+      } else
+        n = i;
+
+    if (!UDDhandle)  {
+      if (n<0)  {
+        UDReg = new pstr[nUDR+1];
+        for (i=0;i<nUDR;i++)
+          UDReg[i] = UDRegister[i];
+        UDReg[nUDR] = NULL;
+        if (UDRegister)  delete[] UDRegister;
+        UDRegister = UDReg;
+        n = nUDR;
+        nUDR++;
+      }
+      CreateCopy ( UDRegister[n],UDDataID );
+      UDDhandle = n+1;
+    }
+
+    return UDDhandle;
+
+  }
+
+  static int UDRegisterFlag[nUDRTypes] = {
+    UDRF_ATOM,
+    UDRF_RESIDUE,
+    UDRF_CHAIN,
+    UDRF_MODEL,
+    UDRF_HIERARCHY
+  };
+
+
+  int  UDRegister::RegisterUDInteger ( UDR_TYPE udr_type,
+                                       cpstr UDDataID )  {
+    if ((udr_type>=0) && (udr_type<nUDRTypes))
+      return RegisterUDData ( IUDRegister[udr_type],
+                              nIUDR[udr_type],UDDataID ) |
+             UDRegisterFlag[udr_type];
+    else
+      return UDDATA_WrongUDRType;
+  }
+
+  int  UDRegister::RegisterUDReal ( UDR_TYPE udr_type,
+                                    cpstr UDDataID )  {
+    if ((udr_type>=0) && (udr_type<nUDRTypes))
+      return RegisterUDData ( RUDRegister[udr_type],
+                              nRUDR[udr_type],UDDataID ) |
+             UDRegisterFlag[udr_type];
+    else
+      return UDDATA_WrongUDRType;
+  }
+
+  int  UDRegister::RegisterUDString ( UDR_TYPE udr_type,
+                                      cpstr UDDataID )  {
+    if ((udr_type>=0) && (udr_type<nUDRTypes))
+      return RegisterUDData ( SUDRegister[udr_type],
+                              nSUDR[udr_type],UDDataID ) |
+             UDRegisterFlag[udr_type];
+    else
+      return UDDATA_WrongUDRType;
+  }
+
+  int  UDRegister::GetUDDHandle ( UDR_TYPE udr_type,
+                                  cpstr UDDataID )  {
+  int  i,UDDhandle;
+
+    if ((udr_type>=0) && (udr_type<nUDRTypes))  {
+
+      UDDhandle = 0;
+
+      for (i=0;(i<nIUDR[udr_type]) && (!UDDhandle);i++)
+        if (IUDRegister[udr_type][i])  {
+          if (!strcmp(UDDataID,IUDRegister[udr_type][i]))
+            UDDhandle = i+1;
+        }
+      for (i=0;(i<nRUDR[udr_type]) && (!UDDhandle);i++)
+        if (RUDRegister[udr_type][i])  {
+          if (!strcmp(UDDataID,RUDRegister[udr_type][i]))
+            UDDhandle = i+1;
+        }
+      for (i=0;(i<nSUDR[udr_type]) && (!UDDhandle);i++)
+        if (SUDRegister[udr_type][i])  {
+          if (!strcmp(UDDataID,SUDRegister[udr_type][i]))
+            UDDhandle = i+1;
+        }
+
+      if (UDDhandle)  return UDDhandle | UDRegisterFlag[udr_type];
+                else  return UDDhandle;
+
+    } else
+      return UDDATA_WrongUDRType;
+
+  }
+
+
+  void  UDRegister::write ( io::RFile f )  {
+  int  i,j;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    for (j=0;j<nUDRTypes;j++)  {
+      f.WriteInt ( &nIUDR[j] );
+      for (i=0;i<nIUDR[j];i++)
+        f.CreateWrite ( IUDRegister[j][i] );
+      f.WriteInt ( &nRUDR[j] );
+      for (i=0;i<nRUDR[j];i++)
+        f.CreateWrite ( RUDRegister[j][i] );
+      f.WriteInt ( &nSUDR[j] );
+      for (i=0;i<nSUDR[j];i++)
+        f.CreateWrite ( SUDRegister[j][i] );
+    }
+  }
+
+  void  UDRegister::read ( io::RFile f )  {
+  int  i,j;
+  byte Version;
+    f.ReadByte ( &Version );
+    FreeUDRegister();
+    for (j=0;j<nUDRTypes;j++)  {
+      f.ReadInt ( &nIUDR[j] );
+      if (nIUDR[j]>0)  {
+        IUDRegister[j] = new pstr[nIUDR[j]];
+        for (i=0;i<nIUDR[j];i++)  {
+          IUDRegister[j][i] = NULL;
+          f.CreateRead ( IUDRegister[j][i] );
+        }
+      }
+      f.ReadInt ( &nRUDR[j] );
+      if (nRUDR[j]>0)  {
+        RUDRegister[j] = new pstr[nRUDR[j]];
+        for (i=0;i<nRUDR[j];i++)  {
+          RUDRegister[j][i] = NULL;
+          f.CreateRead ( RUDRegister[j][i] );
+        }
+      }
+      f.ReadInt ( &nSUDR[j] );
+      if (nSUDR[j]>0)  {
+        SUDRegister[j] = new pstr[nSUDR[j]];
+        for (i=0;i<nSUDR[j];i++)  {
+          SUDRegister[j][i] = NULL;
+          f.CreateRead ( SUDRegister[j][i] );
+        }
+      }
+    }
+  }
+
+
+  MakeStreamFunctions(UDRegister)
+
+
+
+  //  ==========================  UDData  ============================
+
+  UDData::UDData() : Mask()  {
+    InitUDData();
+  }
+
+  UDData::UDData ( io::RPStream Object ) : Mask(Object)  {
+    InitUDData();
+  }
+
+  UDData::~UDData()  {
+    FreeUDDMemory();
+  }
+
+  void UDData::InitUDData()  {
+    IUData = NULL;
+    RUData = NULL;
+    SUData = NULL;
+  }
+
+  void UDData::FreeUDDMemory()  {
+  int i,l;
+    FreeVectorMemory ( IUData,0 );
+    FreeVectorMemory ( RUData,0 );
+    if (SUData)  {
+      l = getNofSUData();
+      for (i=0;i<=l;i++)
+        if (SUData[i])  delete[] SUData[i];
+      delete[] SUData;
+    }
+    IUData = NULL;
+    RUData = NULL;
+    SUData = NULL;
+  }
+
+  int  UDData::getNofIUData()  {
+    if (!IUData)  return 0;
+    return IUData[0];
+  }
+
+  int  UDData::getNofRUData()  {
+    if (!RUData)  return 0;
+    return mround(RUData[0]);
+  }
+
+  int  UDData::getNofSUData()  {
+    if (!SUData)    return 0;
+    if (!SUData[0]) return 0;
+    return (int(SUData[0][0]) << 24) +
+           (int(SUData[0][1]) << 16) +
+           (int(SUData[0][2]) << 8)  +
+            int(SUData[0][3]);
+  }
+
+  void UDData::setNofSUData ( int newN )  {
+    if (!SUData)    return;
+    if (!SUData[0]) return;
+    SUData[0][3] = byte( newN & 0x000000FF);
+    SUData[0][2] = byte((newN & 0x0000FF00) >> 8);
+    SUData[0][1] = byte((newN & 0x00FF0000) >> 16);
+    SUData[0][0] = byte((newN & 0xFF000000) >> 24);
+  }
+
+
+  int  UDData::putUDData ( int UDDhandle, int iudd )  {
+  ivector IUD;
+  int     i,l,udh;
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  return UDDATA_WrongHandle;
+    l = getNofIUData();
+    if (udh>l)  {
+      GetVectorMemory ( IUD,udh+1,0 );
+      IUD[0] = udh;
+      for (i=1;i<=l;i++)
+        IUD[i] = IUData[i];
+      for (i=l+1;i<udh;i++)
+        IUD[i] = MinInt4;
+      FreeVectorMemory ( IUData,0 );
+      IUData = IUD;
+    }
+    IUData[udh] = iudd;
+    return UDDATA_Ok;
+  }
+
+  int  UDData::putUDData ( int UDDhandle, realtype rudd )  {
+  rvector RUD;
+  int     i,l,udh;
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  return UDDATA_WrongHandle;
+    l = getNofRUData();
+    if (udh>l)  {
+      GetVectorMemory ( RUD,udh+1,0 );
+      RUD[0] = udh;
+      for (i=1;i<=l;i++)
+        RUD[i] = RUData[i];
+      for (i=l+1;i<udh;i++)
+        RUD[i] = -MaxReal;
+      FreeVectorMemory ( RUData,0 );
+      RUData = RUD;
+    }
+    RUData[udh] = rudd;
+    return UDDATA_Ok;
+  }
+
+  int  UDData::putUDData ( int UDDhandle, cpstr sudd )  {
+  psvector SUD;
+  int      i,l,udh;
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  return UDDATA_WrongHandle;
+    l = getNofSUData();
+    if (udh>l)  {
+      if (l>0)  {
+        GetVectorMemory ( SUD,udh+1,0 );
+        for (i=0;i<=l;i++)
+          SUD[i] = SUData[i];
+        for (i=l+1;i<=udh;i++)
+          SUD[i] = NULL;
+        FreeVectorMemory ( SUData,0 );
+        SUData = SUD;
+      } else  {
+        GetVectorMemory ( SUData,udh+1,0 );
+        SUData[0] = new char[4];
+        for (i=1;i<=udh;i++)
+          SUData[i] = NULL;
+      }
+      setNofSUData ( udh );
+    }
+    CreateCopy ( SUData[udh],sudd );
+    return UDDATA_Ok;
+  }
+
+  int  UDData::getUDData ( int UDDhandle, int & iudd )  {
+  int l,udh;
+    iudd = 0;
+    udh  = UDDhandle & UDRF_MASK;
+    if (udh<1)  return UDDATA_WrongHandle;
+    l = getNofIUData();
+    if (udh>l)  return UDDATA_NoData;
+    iudd = IUData[udh];
+    if (iudd==MinInt4)  return UDDATA_NoData;
+    return UDDATA_Ok;
+  }
+
+  int  UDData::getUDData ( int UDDhandle, realtype & rudd )  {
+  int l,udh;
+    rudd = 0.0;
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  return UDDATA_WrongHandle;
+    l = getNofRUData();
+    if (udh>l)  return UDDATA_NoData;
+    rudd = RUData[udh];
+    if (rudd==-MaxReal)  return UDDATA_NoData;
+    return UDDATA_Ok;
+  }
+
+  int  UDData::getUDData ( int UDDhandle, pstr sudd, int maxLen )  {
+  int l,udh;
+    sudd[0] = char(0);
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  return UDDATA_WrongHandle;
+    l = getNofSUData();
+    if (udh>l)  return UDDATA_NoData;
+    if (!SUData[udh])  return UDDATA_NoData;
+    strcpy_n0 ( sudd,SUData[udh],maxLen-1 );
+    return UDDATA_Ok;
+  }
+
+  pstr  UDData::getUDData ( int UDDhandle, int * retcode )  {
+  int l,udh;
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  {
+      if (retcode)  *retcode = UDDATA_WrongHandle;
+      return NULL;
+    }
+    l = getNofSUData();
+    if (udh>l)  {
+      if (retcode)  *retcode = UDDATA_NoData;
+      return NULL;
+    }
+    if (!SUData[udh])  {
+      if (retcode)  *retcode = UDDATA_NoData;
+      return NULL;
+    }
+    if (retcode)  *retcode = UDDATA_Ok;
+    return SUData[udh];
+  }
+
+  int  UDData::getUDData ( int UDDhandle, pstr & sudd )  {
+  int l,udh;
+    udh = UDDhandle & UDRF_MASK;
+    if (udh<1)  {
+      if (sudd)  {
+        delete[] sudd;
+        sudd = NULL;
+      }
+      return UDDATA_WrongHandle;
+    }
+    l = getNofSUData();
+    if (udh>l)  {
+      if (sudd)  {
+        delete[] sudd;
+        sudd = NULL;
+      }
+      return UDDATA_NoData;
+    }
+    if (!SUData[udh])  {
+      if (sudd)  {
+        delete[] sudd;
+        sudd = NULL;
+      }
+      return UDDATA_NoData;
+    }
+    CreateCopy ( sudd,SUData[udh] );
+    return UDDATA_Ok;
+  }
+
+
+  void  UDData::write ( io::RFile f )  {
+  int  i,l;
+  byte Version=1;
+
+    f.WriteByte ( &Version );
+
+    Mask::write ( f );
+
+    if (IUData)  l = IUData[0];
+           else  l = -1;
+    f.WriteVector ( IUData,l+1,0 );
+    if (RUData)  l = mround(RUData[0]);
+           else  l = -1;
+    f.WriteVector ( RUData,l+1,0 );
+    l = getNofSUData();
+    f.WriteInt ( &l );
+    for (i=1;i<=l;i++)
+      f.CreateWrite ( SUData[i] );
+  }
+
+  void  UDData::read  ( io::RFile f )  {
+  int  i,l;
+  byte Version;
+
+    f.ReadByte ( &Version );
+
+    FreeUDDMemory();
+
+    Mask::read ( f );
+
+    f.CreateReadVector ( IUData,0 );
+    f.CreateReadVector ( RUData,0 );
+    f.ReadInt ( &l );
+    if (l>0)  {
+      SUData = new pstr[l+1];
+      SUData[0] = new char[4];
+      setNofSUData ( l );
+      for (i=1;i<=l;i++)  {
+        SUData[i] = NULL;
+        f.CreateRead ( SUData[i] );
+      }
+    }
+  }
+
+
+  MakeStreamFunctions(UDData)
+
+}  // namespace mmdb
+
diff --git a/mmdb2/mmdb_uddata.h b/mmdb2/mmdb_uddata.h
new file mode 100644
index 0000000..c591891
--- /dev/null
+++ b/mmdb2/mmdb_uddata.h
@@ -0,0 +1,154 @@
+//  $Id: mmdb_uddata.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_UDData <interface>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::UDData ( user-defined data )
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_UDData__
+#define __MMDB_UDData__
+
+#include "mmdb_mask.h"
+
+namespace mmdb  {
+
+  //  =======================  UDRegister  =========================
+
+  enum UDR_TYPE  {
+    UDR_ATOM      = 0,
+    UDR_RESIDUE   = 1,
+    UDR_CHAIN     = 2,
+    UDR_MODEL     = 3,
+    UDR_HIERARCHY = 4
+  };
+
+  enum UDD_FLAG  {
+    UDRF_ATOM      = 0x01000000,
+    UDRF_RESIDUE   = 0x02000000,
+    UDRF_CHAIN     = 0x04000000,
+    UDRF_MODEL     = 0x08000000,
+    UDRF_HIERARCHY = 0x10000000,
+    UDRF_MASK      = 0x00FFFFFF
+  };
+
+  DefineClass(UDRegister);
+  DefineStreamFunctions(UDRegister);
+
+  class UDRegister : public io::Stream  {
+
+    public :
+
+      UDRegister ();
+      UDRegister ( io::RPStream Object );
+      ~UDRegister();
+
+      int RegisterUDInteger ( UDR_TYPE udr_type, cpstr UDDataID );
+      int RegisterUDReal    ( UDR_TYPE udr_type, cpstr UDDataID );
+      int RegisterUDString  ( UDR_TYPE udr_type, cpstr UDDataID );
+      int GetUDDHandle      ( UDR_TYPE udr_type, cpstr UDDataID );
+
+      void write ( io::RFile f );
+      void read  ( io::RFile f );
+
+    protected :
+      int      nIUDR[5],nRUDR[5],nSUDR[5];
+      psvector IUDRegister[5];
+      psvector RUDRegister[5];
+      psvector SUDRegister[5];
+
+      void  InitUDRegister ();
+      void  FreeUDRegister ();
+      int   RegisterUDData ( psvector & UDRegister,
+                             int      & nUDR,
+                             cpstr      UDDataID );
+
+  };
+
+
+  //  ==========================  UDData  ===========================
+
+  enum UDDATA_RC  {
+    UDDATA_Ok           =  0,
+    UDDATA_WrongHandle  = -1,
+    UDDATA_WrongUDRType = -2,
+    UDDATA_NoData       = -3
+  };
+
+  DefineClass(UDData);
+  DefineStreamFunctions(UDData);
+
+  class UDData : public Mask  {
+
+    friend class SelManager;
+
+    public :
+
+      UDData ();
+      UDData ( io::RPStream Object );
+      ~UDData();
+
+    protected :
+      ivector  IUData;
+      rvector  RUData;
+      psvector SUData;
+
+      void  InitUDData   ();
+      void  FreeUDDMemory();
+      int   getNofIUData ();
+      int   getNofRUData ();
+      int   getNofSUData ();
+      void  setNofSUData ( int newN );
+
+      int   putUDData ( int UDDhandle, int      iudd );
+      int   putUDData ( int UDDhandle, realtype rudd );
+      int   putUDData ( int UDDhandle, cpstr    sudd );
+
+      int   getUDData ( int UDDhandle, int      & iudd );
+      int   getUDData ( int UDDhandle, realtype & rudd );
+      int   getUDData ( int UDDhandle, pstr sudd, int maxLen );
+      pstr  getUDData ( int UDDhandle, int * retcode=NULL );
+      int   getUDData ( int UDDhandle, pstr     & sudd );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+  };
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_utils.cpp b/mmdb2/mmdb_utils.cpp
new file mode 100644
index 0000000..a39f79b
--- /dev/null
+++ b/mmdb2/mmdb_utils.cpp
@@ -0,0 +1,1994 @@
+//  $Id: mmdb_utils.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_Utils <implementation>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::ContainerClass ( containered class template )
+//       ~~~~~~~~~   mmdb::ContString     ( containered string         )
+//                   mmdb::ClassContainer ( container of classes       )
+//                   mmdb::AtomPath       ( atom path ID               )
+//                   mmdb::QuickSort      ( quick sort of integers     )
+//
+//  **** Functions : Date9to11  ( DD-MMM-YY   -> DD-MMM-YYYY          )
+//       ~~~~~~~~~~~ Date11to9  ( DD-MMM-YYYY -> DD-MMM-YY            )
+//                   Date9toCIF ( DD-MMM-YY   -> YYYY-MM-DD           )
+//                   Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD           )
+//                   DateCIFto9 ( YYYY-MM-DD  -> DD-MMM-YY            )
+//                   DateCIFto11( YYYY-MM-DD  -> DD-MMM-YYYY          )
+//                   GetInteger ( reads integer from a string         )
+//                   GetReal    ( reads real from a string            )
+//                   GetIntIns  ( reads integer and insert code       )
+//                   PutInteger ( writes integer into a string        )
+//                   PutRealF   ( writes real in F-form into a string )
+//                   PutIntIns  ( writes integer and insert code      )
+//                   CIFGetInteger ( reads and deletes int from CIF   )
+//                   CIFGetReal    ( reads and deletes real from CIF  )
+//                   CIFGetString  ( reads and deletes string from CIF)
+//                   CIFGetInteger1 (reads and del-s int from CIF loop)
+//                   CIFGetReal1    (reads and del-s int from CIF loop)
+//                   Mat4Inverse    ( inversion of 4x4 matrices       )
+//                   GetErrorDescription (ascii line to an Error_XXXXX)
+//                   ParseAtomID    ( parses atom ID line             )
+//                   ParseResID     ( parses residue ID line          )
+//                   ParseAtomPath  ( parses full atom path           )
+//
+//   (C) E. Krissinel  2000-2013
+//
+//  =================================================================
+//
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "mmdb_utils.h"
+#include "hybrid_36.h"
+
+namespace mmdb  {
+
+  // ====================== Date functions  =======================
+
+  static cpstr Month[12] = {
+    "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
+  };
+
+  static cpstr nMonth[12] = {
+    "01", "02", "03", "04", "05", "06",
+    "07", "08", "09", "10", "11", "12"
+  };
+
+  void  Date9to11 ( cpstr Date9, pstr Date11 )  {
+  // converts  DD-MMM-YY to DD-MMM-YYYY
+  int i;
+    i = 0;
+    while ((i<12) && (strncmp(Month[i],&(Date9[3]),3)))  i++;
+    if (i<12)  {   // DD-MMM-YY -> DD-MMM-YYYY
+      strncpy ( Date11,Date9,7 );
+      if (Date9[7]!='0')  strncpy ( &(Date11[7]),"19",2 );
+                    else  strncpy ( &(Date11[7]),"20",2 );
+      strncpy ( &(Date11[9]),&(Date9[7]),2 );
+      Date11[2]  = '-';
+      Date11[6]  = '-';
+      Date11[11] = char(0);
+    } else  {     // DD-MM-YY -> DD-MMM-YYYY
+      strncpy ( Date11,Date9,3 );
+      i = 0;
+      while ((i<12) && (strncmp(nMonth[i],&(Date9[3]),2)))  i++;
+      if (i<12)  {
+        strncpy ( &(Date11[3]),Month[i],3 );
+          if (Date9[6]!='0')  strncpy ( &(Date11[7]),"19",2 );
+                    else  strncpy ( &(Date11[7]),"20",2 );
+        strncpy ( &(Date11[9]),&(Date9[6]),2 );
+        Date11[2]  = '-';
+        Date11[6]  = '-';
+        Date11[11] = char(0);
+      } else
+        strcpy ( Date11,"           " );
+    }
+  }
+
+  void  Date11to9 ( cpstr Date11, pstr Date9 )  {
+  // converts DD-MMM-YYYY to DD-MMM-YY
+  int i;
+    i = 0;
+    while ((i<12) && (strncmp(Month[i],&(Date11[3]),3)))  i++;
+    if (i<12)  {   // DD-MMM-YYYY -> DD-MMM-YY
+      strncpy ( Date9,Date11,7 );
+      strncpy ( &(Date9[7]),&(Date11[9]),2 );
+      Date9[2] = '-';
+      Date9[6] = '-';
+    } else  {      // DD-MM-YYYY -> DD-MMM-YY
+      strncpy ( Date9,Date11,3 );
+      i = 0;
+      while ((i<12) && (strncmp(nMonth[i],&(Date11[3]),2)))  i++;
+      if (i<12)  {
+        strncpy ( &(Date9[3]),Month[i],3 );
+        strncpy ( &(Date9[7]),&(Date11[8]),2 );
+        Date9[2] = '-';
+        Date9[6] = '-';
+      } else
+        strcpy ( Date9,"         " );
+    }
+  }
+
+  void  Date9toCIF ( cpstr Date9, pstr DateCIF )  {
+  //  DD-MMM-YY -> YYYY-MM-DD             )
+  int  i;
+    i = 0;
+    while ((i<12) && (strncmp(Month[i],&(Date9[3]),3)))  i++;
+    if (i<12)  {   //  DD-MMM-YY  -> YYYY-MM-DD
+      if (Date9[7]!='0')  strcpy ( DateCIF,"19" );
+                    else  strcpy ( DateCIF,"20" );
+      strncpy ( &(DateCIF[2]),&(Date9[7]),2 );
+      strncpy ( &(DateCIF[5]),nMonth[i],2 );
+    } else  {      //  DD-MM-YY  ->  YYYY-MM-DD
+      if (Date9[6]!='0')  strcpy ( DateCIF,"19" );
+                    else  strcpy ( DateCIF,"20" );
+      strncpy ( &(DateCIF[2]),&(Date9[6]),2 );
+      strncpy ( &(DateCIF[5]),&(Date9[3]),2 );
+    }
+    DateCIF[4] = '-';
+    DateCIF[7] = '-';
+    strncpy ( &(DateCIF[8]),Date9,2 );
+    DateCIF[10] = char(0);
+  }
+
+  void  Date11toCIF ( cpstr Date11, pstr DateCIF )  {
+  //  DD-MMM-YYYY -> YYYY-MM-DD
+  int  i;
+    i = 0;
+    while ((i<12) && (strncmp(Month[i],&(Date11[3]),3)))  i++;
+    if (i<12) {
+      strncpy ( DateCIF,&(Date11[7]),4 );
+      strncpy ( &(DateCIF[5]),nMonth[i],2 );
+    } else  {
+      strncpy ( DateCIF,&(Date11[6]),4 );
+      strncpy ( &(DateCIF[5]),&(Date11[3]),2 );
+    }
+    DateCIF[4] = '-';
+    DateCIF[7] = '-';
+    strncpy ( &(DateCIF[8]),Date11,2 );
+    DateCIF[10] = char(0);
+  }
+
+  void  DateCIFto9 ( cpstr DateCIF, pstr Date9 )  {
+  //  YYYY-MM-DD -> DD-MMM-YY
+  int  i;
+    strncpy ( Date9,&(DateCIF[8]),2 );
+    Date9[2] = '-';
+    i = 0;
+    while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2)))  i++;
+    if (i<12) strncpy ( &(Date9[3]),Month[i],3 );
+    else  {
+      strncpy ( &(Date9[3]),&(DateCIF[5]),2 );
+      Date9[5] = 'X';
+    }
+    Date9[6] = '-';
+    strncpy ( &(Date9[7]),&(DateCIF[2]),2 );
+  //  DateCIF[9] = char(0);
+  }
+
+  void  DateCIFto11 ( cpstr DateCIF, pstr Date11 )  {
+  //  YYYY-MM-DD  -> DD-MMM-YYYY
+  int  i;
+    strncpy ( Date11,&(DateCIF[8]),2 );
+    Date11[2] = '-';
+    i = 0;
+    while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2)))  i++;
+    if (i<12) strncpy ( &(Date11[3]),Month[i],3 );
+    else  {
+      strncpy ( &(Date11[3]),&(DateCIF[5]),2 );
+      Date11[5] = 'X';
+    }
+    Date11[6] = '-';
+    strncpy ( &(Date11[7]),DateCIF,4 );
+  //  DateCIF[11] = char(0);
+  }
+
+
+  //  =============== Format functions  ===================
+
+  bool GetInteger ( int & N, cpstr S, int M )  {
+  //   Returns true if S contains an integer number in its
+  // first M characters. This number is returned in N.
+  //   The return is false if no integer number may be
+  // recognized. In this case, N is assigned MinInt4 value.
+  pstr endptr;
+  char L[50];
+    strncpy ( L,S,M );
+    L[M] = char(0);
+    N    = mround(strtod(L,&endptr));
+    if ((N==0) && (endptr==L))  {
+      N = MinInt4;  // no number
+      return false;
+    } else
+      return true;
+  }
+
+  bool GetReal ( realtype & R, cpstr S, int M )  {
+  //   Returns true if S contains a real number in its
+  // first M characters. This number is returned in R.
+  //   The return is false if no real number may be
+  // recognized. In this case, R is assigned -MaxReal value.
+  pstr endptr;
+  char L[50];
+    strncpy ( L,S,M );
+    L[M] = char(0);
+    R    = strtod(L,&endptr);
+    if ((R==0.0) && (endptr==L))  {
+      R = -MaxReal;  // no number
+      return false;
+    } else
+      return true;
+  }
+
+  bool  GetIntIns ( int & N, pstr ins, cpstr S, int M )  {
+  //   Returns true if S contains an integer number in its
+  // first M characters. This number is returned in N. In addition
+  // to that, GetIntIns() retrieves the insertion code which may
+  // follow the integer and returns it in "ins" (1 character +
+  // terminating 0).
+  //   The return is false if no integer number may be
+  // recognized. In this case, N is assigned MinInt4 value,
+  // "ins" just returns (M+1)th symbol of S (+terminating 0).
+  pstr endptr;
+  char L[50];
+
+    if (S[M]!=' ')  {
+      ins[0] = S[M];
+      ins[1] = char(0);
+    } else
+      ins[0] = char(0);
+
+    strncpy ( L,S,M );
+    L[M] = char(0);
+    if ((M==4) && ((S[0]>='A') || ((S[0]=='-') && (S[1]>='A'))))
+      hy36decode ( M,L,M,&N);
+    else  {
+      endptr = NULL;
+      N      = mround(strtod(L,&endptr));
+      if ((N==0) && (endptr==L))  {
+        N = MinInt4;  // no number
+        return false;
+      }
+    }
+
+    return true;
+
+  }
+
+  void  PutInteger ( pstr S, int N, int M )  {
+  //  Integer N is converted into ASCII string of length M
+  // and pasted onto first M characters of string S. No
+  // terminating zero is added.
+  //  If N is set to MinInt4, then first M characters of
+  // string S are set to the space character.
+  char L[50];
+  int  i;
+    if (N==MinInt4)
+      for (i=0;i<M;i++)
+        S[i] = ' ';
+    else  {
+      sprintf ( L,"%*i",M,N );
+      strncpy ( S,L,M );
+    }
+  }
+
+  void  PutRealF ( pstr S, realtype R, int M, int L )  {
+  //  Real R is converted into ASCII string of length M
+  // and pasted onto first M characters of string S. No
+  // terminating zero is added. The conversion is done
+  // according to fixed format FM.L
+  //  If R is set to -MaxReal, then first M characters of
+  // string S are set to the space character.
+  char N[50];
+  int  i;
+    if (R==-MaxReal)
+      for (i=0;i<M;i++)
+        S[i] = ' ';
+    else  {
+      sprintf ( N,"%*.*f",M,L,R );
+      strncpy ( S,N,M );
+    }
+  }
+
+  ERROR_CODE CIFGetIntegerD ( int & I, mmcif::PLoop Loop, cpstr Tag,
+                             int defValue )  {
+  int        Signal;
+  ERROR_CODE RC;
+    Signal = 0;
+    RC = CIFGetInteger ( I,Loop,Tag,Signal );
+    if (RC)
+      I = defValue;
+    return RC;
+  }
+
+  ERROR_CODE CIFGetInteger ( int & I, mmcif::PLoop Loop, cpstr Tag,
+                             int & Signal )  {
+  pstr F;
+  int  RC;
+    RC = Loop->GetInteger ( I,Tag,Signal,true );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      F = Loop->GetString ( Tag,Signal,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,Signal,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,Signal );
+      Signal = -Error_UnrecognizedInteger-1;
+      return Error_UnrecognizedInteger;
+    }
+    if (RC==mmcif::CIFRC_WrongIndex)  {
+      Signal = -1;
+      return Error_NoData;
+    }
+    if (RC)  {
+      F = Loop->GetString ( Tag,Signal,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,Signal,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,Signal );
+      Signal = -Error_NoData-1;
+      return Error_NoData;
+    }
+    return Error_NoError;
+  }
+
+
+  ERROR_CODE CIFGetInteger1 ( int & I, mmcif::PLoop Loop, cpstr Tag,
+                              int nrow )  {
+  pstr F;
+  int  RC;
+    RC = Loop->GetInteger ( I,Tag,nrow,true );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      F = Loop->GetString ( Tag,nrow,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,nrow,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,nrow );
+      return Error_UnrecognizedInteger;
+    }
+    if (RC==mmcif::CIFRC_WrongIndex)
+      return Error_NoData;
+    if (RC)  {
+      F = Loop->GetString ( Tag,nrow,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,nrow,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,nrow );
+      return Error_NoData;
+    }
+    return Error_NoError;
+  }
+
+
+  ERROR_CODE CIFGetReal ( realtype & R, mmcif::PLoop Loop, cpstr Tag,
+                          int & Signal )  {
+  pstr F;
+  int  RC;
+    RC = Loop->GetReal ( R,Tag,Signal,true );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      F = Loop->GetString ( Tag,Signal,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,Signal,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,Signal );
+      Signal = -Error_UnrecognizedReal-1;
+      return Error_UnrecognizedReal;
+    }
+    if (RC==mmcif::CIFRC_WrongIndex)  {
+      Signal = -1;
+      return Error_NoData;
+    }
+    if (RC)  {
+      F = Loop->GetString ( Tag,Signal,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,Signal,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,Signal );
+      Signal = -Error_NoData-1;
+      return Error_NoData;
+    }
+    return Error_NoError;
+  }
+
+
+  ERROR_CODE CIFGetReal1 ( realtype & R, mmcif::PLoop Loop, cpstr Tag,
+                           int nrow )  {
+  pstr F;
+  int  RC;
+    RC = Loop->GetReal ( R,Tag,nrow,true );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      F = Loop->GetString ( Tag,nrow,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,nrow,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,nrow );
+      return Error_UnrecognizedReal;
+    }
+    if (RC==mmcif::CIFRC_WrongIndex)
+      return Error_NoData;
+    if (RC)  {
+      F = Loop->GetString ( Tag,nrow,RC );
+      if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
+                       Loop->GetCategoryName(),Tag,nrow,F );
+        else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
+                       Loop->GetCategoryName(),Tag,nrow );
+      return Error_NoData;
+    }
+    return Error_NoError;
+  }
+
+
+  ERROR_CODE CIFGetString ( pstr S, mmcif::PLoop Loop, cpstr Tag,
+                            int row, int SLen, cpstr DefS )  {
+  pstr F;
+  int RC;
+    F = Loop->GetString ( Tag,row,RC );
+    if ((!RC) && F)  {
+      strncpy ( S,F,SLen-1 );
+      Loop->DeleteField ( Tag,row );
+      return Error_NoError;
+    } else  {
+      strcpy ( S,DefS );
+      return Error_EmptyCIFLoop;
+    }
+  }
+
+
+  ERROR_CODE CIFGetInteger ( int & I, mmcif::PStruct Struct, cpstr Tag,
+                             bool Remove )  {
+  pstr F;
+  int  RC;
+    RC = Struct->GetInteger ( I,Tag,Remove );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      F = Struct->GetString ( Tag,RC );
+      if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+                       Struct->GetCategoryName(),Tag,F );
+        else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+                       Struct->GetCategoryName(),Tag );
+      return Error_UnrecognizedInteger;
+    }
+    if (RC)  {
+      F = Struct->GetString ( Tag,RC );
+      if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+                       Struct->GetCategoryName(),Tag,F );
+        else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+                       Struct->GetCategoryName(),Tag );
+      return Error_NoData;
+    }
+    return Error_NoError;
+  }
+
+  ERROR_CODE CIFGetReal ( realtype & R, mmcif::PStruct Struct, cpstr Tag,
+                          bool Remove )  {
+  pstr F;
+  int RC;
+    RC = Struct->GetReal ( R,Tag,Remove );
+    if (RC==mmcif::CIFRC_WrongFormat)  {
+      F = Struct->GetString ( Tag,RC );
+      if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+                       Struct->GetCategoryName(),Tag,F );
+        else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+                       Struct->GetCategoryName(),Tag );
+      return Error_UnrecognizedReal;
+    }
+    if (RC)  {
+      F = Struct->GetString ( Tag,RC );
+      if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
+                       Struct->GetCategoryName(),Tag,F );
+        else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
+                       Struct->GetCategoryName(),Tag );
+      return Error_NoData;
+    }
+    return Error_NoError;
+  }
+
+  ERROR_CODE CIFGetString ( pstr S, mmcif::PStruct Struct, cpstr Tag,
+                            int SLen, cpstr DefS, bool Remove )  {
+  pstr F;
+  int  RC;
+    F = Struct->GetString ( Tag,RC );
+    if ((!RC) && F)  {
+      strcpy_n0 ( S,F,SLen-1 );
+      if (Remove)  Struct->DeleteField ( Tag );
+      return Error_NoError;
+    } else  {
+      strcpy ( S,DefS );
+      return Error_EmptyCIFStruct;
+    }
+  }
+
+
+  void  PutIntIns ( pstr S, int N, int M, cpstr ins )  {
+  //  Integer N is converted into ASCII string of length M
+  // and pasted onto first M characters of string S. No
+  // terminating zero is added. The insert code ins is put
+  // immediately after the integer.
+  //  If N is set to MinInt4, then first M+1 characters of
+  // string S are set to space, and no insert code are
+  // appended.
+  char L[50];
+  int  i;
+
+    if (N==MinInt4)  {
+      for (i=0;i<=M;i++)
+        S[i] = ' ';
+    } else  {
+      if ((M!=4) || ((N>=-999) && (N<=9999)))
+           sprintf    ( L,"%*i",M,N );
+      else hy36encode ( M,N,L );
+      strcpy_n1 ( S,L,M );
+      if (ins[0]) S[M] = ins[0];
+    }
+
+  }
+
+
+  void  Mat4Inverse ( mat44 & A, mat44 & AI )  {
+  //       ***  FORMER RBRINV(A,AI)  ***
+  //   Function to invert 4*4 matrices (AI=A^{-1})
+  mat44    c;
+  mat33    x;
+  realtype s,s1;
+  int      ii,jj,i,i1,j,j1;
+
+  // ---- Get cofactors of 'a' in array 'c'
+
+    s1 = 1.0;
+    for (ii=0;ii<4;ii++)  {
+      s = s1;
+      for (jj=0;jj<4;jj++)  {
+        i = -1;
+        for (i1=0;i1<4;i1++)
+          if (i1!=ii)  {
+            i++;
+            j = -1;
+            for (j1=0;j1<4;j1++)
+              if (j1!=jj)  {
+                j++;
+                x[i][j] = A[i1][j1];
+              }
+          }
+        c[ii][jj] = s*(x[0][0]*(x[1][1]*x[2][2]-x[1][2]*x[2][1]) +
+                       x[0][1]*(x[1][2]*x[2][0]-x[1][0]*x[2][2]) +
+                       x[0][2]*(x[1][0]*x[2][1]-x[1][1]*x[2][0]));
+        s = -s;
+      }
+      s1 = -s1;
+    }
+
+  // ---- Calculate determinant
+
+    s = 0.0;
+    for (i=0;i<4;i++)
+      s += A[i][0]*c[i][0];
+
+  // ---- Get inverse matrix
+
+    if (s!=0.0)
+      for (i=0;i<4;i++)
+        for (j=0;j<4;j++)
+          AI[i][j] = c[j][i]/s;
+
+  }
+
+  realtype Mat3Inverse ( mat33 & A, mat33 & AI )  {
+  mat33    c,x;
+  realtype s;
+  int      ii,jj,i,i1,j,j1;
+
+    // Get cofactors of 'a' in array 'c'
+
+    s = 1.0;
+    for (ii=0;ii<3;ii++)
+      for (jj=0;jj<3;jj++)  {
+        i = -1;
+        for (i1=0;i1<3;i1++)
+          if (i1!=ii)  {
+            i++;
+            j = -1;
+            for (j1=0;j1<3;j1++)
+              if (j1!=jj)  {
+                j++;
+                x[i][j] = A[i1][j1];
+              }
+          }
+        c[ii][jj] = s*(x[0][0]*x[1][1]-x[0][1]*x[1][0]);
+        s = -s;
+      }
+
+    // Calculate determinant
+
+    s = 0.0;
+    for (i=0;i<3;i++)
+      s += A[i][0]*c[i][0];
+
+    // Get inverse matrix
+
+    if (s!=0.0)
+      for (i=0;i<3;i++)
+        for (j=0;j<3;j++)
+          AI[i][j] = c[j][i]/s;
+
+    return s;
+
+  }
+
+  void  Mat4Mult ( mat44 & A, mat44 & B, mat44 & C )  {
+  //  Calculates A=B*C
+  int i,j,k;
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)  {
+        A[i][j] = 0.0;
+        for (k=0;k<4;k++)
+          A[i][j] += B[i][k]*C[k][j];
+      }
+  }
+
+  void  Mat4Div1 ( mat44 & A, mat44 & B, mat44 & C )  {
+  //  Calculates A=B^{-1}*C
+  mat44 B1;
+  int   i,j,k;
+    B1[0][0] = 1.0; // in order to supress warnings from some
+                    // stupid compilers
+    Mat4Inverse ( B,B1 );
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)  {
+        A[i][j] = 0.0;
+        for (k=0;k<4;k++)
+          A[i][j] += B1[i][k]*C[k][j];
+      }
+  }
+
+  void  Mat4Div2 ( mat44 & A, mat44 & B, mat44 & C )  {
+  //  Calculates A=B*C^{-1}
+  mat44 C1;
+  int   i,j,k;
+    C1[0][0] = 1.0; // in order to supress warnings from some
+                    // stupid compilers
+    Mat4Inverse ( C,C1 );
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)  {
+        A[i][j] = 0.0;
+        for (k=0;k<4;k++)
+          A[i][j] += B[i][k]*C1[k][j];
+      }
+  }
+
+  void  Mat4Init ( mat44 & A )  {
+  int i,j;
+    for (i=0;i<4;i++)  {
+      for (j=0;j<4;j++)
+        A[i][j] = 0.0;
+      A[i][i] = 1.0;
+    }
+  }
+
+  realtype Mat4RotDet ( mat44 & T )  {
+  //  returns determinant of the rotation part
+    return T[0][0]*T[1][1]*T[2][2] +
+           T[0][1]*T[1][2]*T[2][0] +
+           T[1][0]*T[2][1]*T[0][2] -
+           T[0][2]*T[1][1]*T[2][0] -
+           T[0][0]*T[1][2]*T[2][1] -
+           T[2][2]*T[0][1]*T[1][0];
+  }
+
+  bool isMat4Unit ( mat44 & A, realtype eps, bool rotOnly )  {
+  // returns true if A is a unit 4x4 matrix
+  int     i,j,k;
+  bool B;
+
+    if (rotOnly)  k = 3;
+            else  k = 4;
+
+    B = true;
+    for (i=0;(i<k) && B;i++)
+      for (j=0;(j<k) && B;j++)
+        if (i==j)  B = (fabs(1.0-A[i][j])<eps);
+             else  B = (fabs(A[i][j])<eps);
+
+    return B;
+
+  }
+
+  void  Mat3Init ( mat33 & A )  {
+  int i,j;
+    for (i=0;i<3;i++)  {
+      for (j=0;j<3;j++)
+        A[i][j] = 0.0;
+      A[i][i] = 1.0;
+    }
+  }
+
+  void  Mat4Copy ( mat44 & A, mat44 & ACopy )  {
+  int i,j;
+    for (i=0;i<4;i++)
+      for (j=0;j<4;j++)
+        ACopy[i][j] = A[i][j];
+  }
+
+  void  Mat3Copy ( mat33 & A, mat33 & ACopy )  {
+  int i,j;
+    for (i=0;i<3;i++)
+      for (j=0;j<3;j++)
+        ACopy[i][j] = A[i][j];
+  }
+
+  bool isMat4Eq ( mat44 & A, mat44 & B, realtype eps,
+                     bool rotOnly )  {
+  // returns true if A is equal to B within precision eps
+  int     i,j,k;
+  bool Eq;
+
+    if (rotOnly)  k = 3;
+            else  k = 4;
+
+    Eq = true;
+    for (i=0;(i<k) && Eq;i++)
+      for (j=0;(j<k) && Eq;j++)
+        Eq = (fabs(A[i][j]-B[i][j])<eps);
+
+    return Eq;
+
+  }
+
+
+  void TransformXYZ ( mat44 & T, realtype & X, realtype & Y,
+                                               realtype & Z )  {
+  realtype x1,y1,z1;
+    x1 = T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
+    y1 = T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
+    z1 = T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
+    X = x1;
+    Y = y1;
+    Z = z1;
+  }
+
+  realtype TransformX ( mat44 & T, realtype X, realtype Y,
+                                               realtype Z )  {
+    return  T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
+  }
+
+  realtype TransformY ( mat44 & T, realtype X, realtype Y,
+                                               realtype Z )  {
+    return  T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
+  }
+
+  realtype TransformZ ( mat44 & T, realtype X, realtype Y,
+                                               realtype Z )  {
+    return  T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
+  }
+
+
+
+
+  char CIFErrorLocation[200] = "no error";
+
+  static cpstr msWrongSection =
+    "Wrong section. The sections in PDB file may be put in wrong order.";
+  static cpstr msWrongChainID =
+    "Wrong chain ID. The input may have changed to another chain.";
+  static cpstr msWrongEntryID =
+    "Entry ID does not match the header.";
+
+  static cpstr msSEQRES_serNum   =
+    "Serial numbers of SEQRES records do not increment by 1.";
+  static cpstr msSEQRES_numRes   =
+    "Different SEQRES records show different numbers of residues.";
+  static cpstr msSEQRES_extraRes =
+    "SEQRES records contain more residues than specified.";
+
+  static cpstr msNCSM_Unrecognized =
+    "Unrecognized numerical input in MTRIXn.";
+  static cpstr msNCSM_AlreadySet   =
+    "Duplicate MTRIXn record.";
+  static cpstr msNCSM_WrongSerial  =
+    "Serial number in MTRIXn record is wrong.";
+  static cpstr msNCSM_UnmatchIG    =
+    "Different MTRIXn record show different iGiven flag.";
+
+  static cpstr msATOM_Unrecognized =
+    "Numerical information in ATOM record is not recognized.";
+  static cpstr msATOM_AlreadySet   =
+    "Atom is already in the system.";
+  static cpstr msATOM_NoResidue    =
+    "No residue is found for atom.";
+  static cpstr msATOM_Unmatch      =
+    "Unmatch in different records for the same atom.";
+
+  static cpstr msCantOpenFile        = "File can not be opened.";
+  static cpstr msUnrecognizedInteger =
+    "Wrong ASCII format of an integer.";
+  static cpstr msWrongModelNo        = "Wrong model number.";
+  static cpstr msDuplicatedModel     = "Duplicate model number.";
+  static cpstr msNoModel             = "No model defined.";
+  static cpstr msForeignFile         =
+    "Attempt to read unknown-type file.";
+  static cpstr msWrongEdition        =
+    "Attempt to read a higher-version file.";
+
+  static cpstr msNoData              = "Expected data field not found.";
+  static cpstr msUnrecognizedReal    = "Wrong ASCII format of a real.";
+  static cpstr msNotACIFFile         =
+    "Not a CIF file ('data_' missing).";
+  static cpstr msUnrecognCIFItems    =
+    "Unrecognized item(s) in CIF file.";
+  static cpstr msMissingCIFField     = "Expected CIF item(s) missing.";
+  static cpstr msEmptyCIFLoop        = "Empty CIF loop encountered.";
+  static cpstr msUnexpEndOfCIF       = "Unexpected end of CIF file.";
+  static cpstr msMissgCIFLoopField   = "Inconsistent CIF loop.";
+  static cpstr msNotACIFStructure    =
+    "Wrong use of CIF structure (as a loop?).";
+  static cpstr msNotACIFLoop         =
+    "Wrong use of CIF loop (as a structure?).";
+
+  static cpstr msNoSheetID           = "No Sheet ID on PDB ASCII card.";
+  static cpstr msWrongSheetID        = "Wrong Sheet ID.";
+  static cpstr msWrongStrandNo       =
+    "Wrong Strand number on PDB SHEET card.";
+
+  static cpstr msWrongNumberOfStrands =
+    "Wrong number of strands in CIF file.";
+  static cpstr msWrongSheetOrder     = "Incomplete _struct_sheet_order.";
+  static cpstr msHBondInconsistency  =
+    "Inconsistency in _struct_sheet_hbond.";
+
+  static cpstr msEmptyResidueName    =
+          "No residue name on PDB ATOM or TER card.";
+  static cpstr msDuplicateSeqNum     =
+          "Duplicate sequence number and insertion code.";
+
+  static cpstr msEmptyFile           = "Non-existent or empty file.";
+
+  static cpstr msNoLogicalName       = "Logical file name not found.";
+
+
+  cpstr  GetErrorDescription ( ERROR_CODE ErrorCode )  {
+
+    switch (ErrorCode)  {
+
+      case Error_NoError              :  return "No errors.";
+
+      case Error_WrongSection         :  return msWrongSection;
+      case Error_WrongChainID         :  return msWrongChainID;
+      case Error_WrongEntryID         :  return msWrongEntryID;
+
+      case Error_SEQRES_serNum        :  return msSEQRES_serNum;
+      case Error_SEQRES_numRes        :  return msSEQRES_numRes;
+      case Error_SEQRES_extraRes      :  return msSEQRES_extraRes;
+
+      case Error_NCSM_Unrecognized    :  return msNCSM_Unrecognized;
+      case Error_NCSM_AlreadySet      :  return msNCSM_AlreadySet;
+      case Error_NCSM_WrongSerial     :  return msNCSM_WrongSerial;
+      case Error_NCSM_UnmatchIG       :  return msNCSM_UnmatchIG;
+
+      case Error_ATOM_Unrecognized    :  return msATOM_Unrecognized;
+      case Error_ATOM_AlreadySet      :  return msATOM_AlreadySet;
+      case Error_ATOM_NoResidue       :  return msATOM_NoResidue;
+      case Error_ATOM_Unmatch         :  return msATOM_Unmatch;
+
+      case Error_CantOpenFile         :  return msCantOpenFile;
+      case Error_UnrecognizedInteger  :  return msUnrecognizedInteger;
+      case Error_WrongModelNo         :  return msWrongModelNo;
+      case Error_DuplicatedModel      :  return msDuplicatedModel;
+      case Error_NoModel              :  return msNoModel;
+      case Error_ForeignFile          :  return msForeignFile;
+      case Error_WrongEdition         :  return msWrongEdition;
+
+      case Error_NoData               :  return msNoData;
+      case Error_UnrecognizedReal     :  return msUnrecognizedReal;
+      case Error_NotACIFFile          :  return msNotACIFFile;
+      case Error_UnrecognCIFItems     :  return msUnrecognCIFItems;
+      case Error_MissingCIFField      :  return msMissingCIFField;
+      case Error_EmptyCIFLoop         :  return msEmptyCIFLoop;
+      case Error_UnexpEndOfCIF        :  return msUnexpEndOfCIF;
+      case Error_MissgCIFLoopField    :  return msMissgCIFLoopField;
+      case Error_NotACIFStructure     :  return msNotACIFStructure;
+      case Error_NotACIFLoop          :  return msNotACIFLoop;
+
+      case Error_NoSheetID            :  return msNoSheetID;
+      case Error_WrongSheetID         :  return msWrongSheetID;
+      case Error_WrongStrandNo        :  return msWrongStrandNo;
+
+      case Error_WrongNumberOfStrands :  return msWrongNumberOfStrands;
+      case Error_WrongSheetOrder      :  return msWrongSheetOrder;
+      case Error_HBondInconsistency   :  return msHBondInconsistency;
+
+      case Error_EmptyResidueName     :  return msEmptyResidueName;
+      case Error_DuplicateSeqNum      :  return msDuplicateSeqNum;
+
+      case Error_EmptyFile            :  return msEmptyFile;
+
+      case Error_NoLogicalName        :  return msNoLogicalName;
+
+      default                         :  return "Unknown error.";
+
+    }
+  }
+
+
+  //  ==============  ContainerClass  ====================
+
+  ContainerClass::ContainerClass() : io::Stream()  {
+    ContinuationNo = 0;
+  }
+
+  ContainerClass::ContainerClass ( io::RPStream Object )
+                 : io::Stream(Object)  {
+    ContinuationNo = 0;
+  }
+
+  bool  ContainerClass::Append ( PContainerClass CC )  {
+    return  (CC->ContinuationNo>1);
+  }
+
+
+  //  ===================  ContString  =====================
+
+  ContString::ContString() : ContainerClass()  {
+    InitString();
+  }
+
+  ContString::ContString ( cpstr S ) : ContainerClass()  {
+    InitString();
+    ConvertPDBASCII ( S );
+  }
+
+  ContString::ContString ( io::RPStream Object )
+             : ContainerClass(Object)  {
+    InitString();
+  }
+
+  ContString::~ContString() {
+    if (Line)        delete[] Line;
+    if (CIFCategory) delete[] CIFCategory;
+    if (CIFTag)      delete[] CIFTag;
+  }
+
+  void  ContString::InitString()  {
+    Line        = NULL;
+    CIFCategory = NULL;
+    CIFTag      = NULL;
+  }
+
+  ERROR_CODE ContString::ConvertPDBASCII ( cpstr S )  {
+    CreateCopy ( Line,S );
+    return Error_NoError;
+  }
+
+  void  ContString::PDBASCIIDump ( pstr S, int )  {
+    if (Line)  strcpy ( S,Line );
+         else  strcpy ( S,""   );
+  }
+
+  bool ContString::PDBASCIIDump1 ( io::RFile f )  {
+    if (Line)  f.WriteLine ( Line );
+         else  f.LF();
+    return true;
+  }
+
+/*
+  void ContString::GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
+                             int & pos )  {
+  pstr F;
+  int  i,RC;
+  char c;
+    if ((!CIFCategory) || (!CIFTag))  {
+      Signal = Error_EmptyCIF;
+      return;
+    }
+    F = CIF->GetString ( CIFCategory,CIFTag,RC );
+    if (RC || (!F))  {
+      Signal = Error_EmptyCIF;
+      return;
+    }
+    if (Signal>=(int)strlen(F))  {
+      CIF->DeleteField ( CIFCategory,CIFTag );
+      Signal = Error_EmptyCIF;
+      return;
+    }
+//    i = Signal;
+//    while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
+//    if ((Signal==0) && (i==0))  {
+//      i++;
+//      if (((F[Signal]=='\n') && (F[i]=='\r')) ||
+//          ((F[Signal]=='\r') && (F[i]=='\n')))  i++;
+//      Signal = i;
+//      while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
+//    }
+//    c = F[i];
+//    F[i] = char(0);
+//    CreateCopy ( Line,&(F[Signal]) );
+//    if (c)  {
+//      F[i]   = c;
+//      Signal = i+1;
+//      if (((c=='\n') && (F[Signal]=='\r')) ||
+//          ((c=='\r') && (F[Signal]=='\n')))  Signal++;
+//    } else
+//      CIF->DeleteField ( CIFCategory,CIFTag );
+    i = pos;
+    while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
+    if ((pos==0) && (i==0))  {
+      i++;
+      if (((F[pos]=='\n') && (F[i]=='\r')) ||
+          ((F[pos]=='\r') && (F[i]=='\n')))  i++;
+      pos = i;
+      while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
+    }
+    c = F[i];
+    F[i] = char(0);
+    CreateCopy ( Line,&(F[pos]) );
+    if (c)  {
+      F[i] = c;
+      pos  = i+1;
+      if (((c=='\n') && (F[pos]=='\r')) ||
+          ((c=='\r') && (F[pos]=='\n')))  pos++;
+    } else
+      CIF->DeleteField ( CIFCategory,CIFTag );
+  }
+*/
+
+  void  ContString::MakeCIF ( mmcif::PData CIF, int N )  {
+  pstr S;
+    if ((!CIFCategory) || (!CIFTag))  return;
+    S = new char[strlen(Line)+5];
+    strcpy ( S,"\n" );
+    strcat ( S,Line );
+    CIF->PutString ( S,CIFCategory,CIFTag,(N!=0) );
+    delete[] S;
+  }
+
+  bool  ContString::Append ( PContainerClass CC )  {
+    if (ContainerClass::Append(CC))  {
+      if (!Line)  {
+        Line = PContString(CC)->Line;
+        PContString(CC)->Line = NULL;
+      } else
+        CreateConcat ( Line,pstr("\n"),PContString(CC)->Line );
+      return true;
+    }
+    return false;
+  }
+
+  void  ContString::Copy ( PContainerClass CString )  {
+    CreateCopy ( Line,PContString(CString)->Line );
+  }
+
+  void  ContString::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte   ( &Version    );
+    f.CreateWrite ( Line        );
+    f.CreateWrite ( CIFCategory );
+    f.CreateWrite ( CIFTag      );
+  }
+
+  void  ContString::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte   ( &Version    );
+    f.CreateRead ( Line        );
+    f.CreateRead ( CIFCategory );
+    f.CreateRead ( CIFTag      );
+  }
+
+  MakeStreamFunctions(ContString)
+
+
+
+  //  ==============  ClassContainer  ====================
+
+  MakeStreamFunctions(ContainerClass)
+
+  ClassContainer::ClassContainer() : io::Stream()  {
+    Init();
+  }
+
+  ClassContainer::ClassContainer ( io::RPStream Object )
+                  : io::Stream(Object)  {
+    Init();
+  }
+
+  void ClassContainer::Init()  {
+    length    = 0;
+    Container = NULL;
+  }
+
+  ClassContainer::~ClassContainer()  {
+    FreeContainer();
+  }
+
+  void  ClassContainer::FreeContainer()  {
+  int i;
+    if (Container)  {
+      for (i=0;i<length;i++)
+        if (Container[i])
+          delete Container[i];
+      delete[] Container;
+    }
+    Container = NULL;
+    length    = 0;
+  }
+
+  void  ClassContainer::AddData ( PContainerClass Data )  {
+  int               i;
+  PPContainerClass C1;
+    if (!Data)  return;
+    if (length>0)  {
+      i = length-1;
+      while (i>=0)  {
+        if (!Container[i])  i--;
+        else if (Container[i]->GetClassID()!=Data->GetClassID())  i--;
+        else break;
+      }
+      if (i>=0)  {
+        if (Container[i]->Append(Data))  {
+          delete Data;
+          return;
+        }
+      }
+    }
+    C1 = new PContainerClass[length+1];
+    for (i=0;i<length;i++)
+      C1[i] = Container[i];
+    C1[length] = Data;
+    if (Container)  delete[] Container;
+    Container = C1;
+    length++;
+  }
+
+  void  ClassContainer::PDBASCIIDump ( io::RFile f )  {
+  char S[500];
+  int  i,j;
+    for (i=0;i<length;i++)
+      if (Container[i])  {
+        if (!Container[i]->PDBASCIIDump1(f))  {
+          Container[i]->PDBASCIIDump ( S,i );
+          j = strlen(S);
+          while (j<80)  S[j++] = ' ';
+          S[80] = char(0);
+          f.WriteLine ( S );
+        }
+      }
+  }
+
+  ERROR_CODE ClassContainer::GetCIF ( mmcif::PData CIF, int ClassID )  {
+  PContainerClass ContainerClass;
+  int             n;
+  ERROR_CODE      rc;
+    n = -1;
+    do  {
+      ContainerClass = MakeContainerClass ( ClassID );
+      rc = ContainerClass->GetCIF ( CIF,n );
+      if (rc==Error_NoError)
+        AddData ( ContainerClass );
+    } while (rc==Error_NoError);
+    delete ContainerClass;
+    if (rc==Error_EmptyCIF)
+      rc = Error_NoError;
+    return rc;
+  }
+
+  void  ClassContainer::MakeCIF ( mmcif::PData CIF )  {
+  int i;
+    for (i=0;i<length;i++)
+      if (Container[i])
+        Container[i]->MakeCIF ( CIF,i );
+  }
+
+  void  ClassContainer::write ( io::RFile f )  {
+  int  i,ClassID;
+  byte Version=1;
+    f.WriteByte ( &Version );
+    f.WriteInt  ( &length  );
+    for (i=0;i<length;i++)
+      if (Container[i])  {
+        ClassID = Container[i]->GetClassID();
+        f.WriteInt ( &ClassID );
+        Container[i]->write ( f );
+      } else  {
+        ClassID = -1;
+        f.WriteInt ( &ClassID );
+      }
+  }
+
+  PContainerClass ClassContainer::MakeContainerClass ( int ClassID )  {
+    if (ClassID==ClassID_String)  return new ContString();
+    return new ContainerClass();
+  }
+
+  PContainerClass ClassContainer::GetContainerClass (int ContClassNo) {
+    if ((ContClassNo<0) || (ContClassNo>=length))  return NULL;
+    return Container[ContClassNo];
+  }
+
+  void  ClassContainer::Copy ( PClassContainer CContainer )  {
+  int i;
+    FreeContainer();
+    if (CContainer)  {
+      length = CContainer->length;
+      if (length>0)  {
+        Container = new PContainerClass[length];
+        for (i=0;i<length;i++)
+          if (CContainer->Container[i])  {
+            Container[i] = MakeContainerClass (
+                              CContainer->Container[i]->GetClassID() );
+            Container[i]->Copy ( CContainer->Container[i] );
+          } else
+            Container[i] = NULL;
+      }
+    }
+  }
+
+  void  ClassContainer::read ( io::RFile f )  {
+  int  i,ClassID;
+  byte Version;
+    FreeContainer();
+    f.ReadByte ( &Version );
+    f.ReadInt  ( &length  );
+    if (length>0)  {
+      Container = new PContainerClass[length];
+      for (i=0;i<length;i++)  {
+        f.ReadInt ( &ClassID );
+        if (ClassID>=0)  {
+          Container[i] = MakeContainerClass ( ClassID );
+          Container[i]->read ( f );
+        } else
+          Container[i] = NULL;
+      }
+    }
+  }
+
+  MakeStreamFunctions(ClassContainer)
+
+
+
+  //  ======================  ID parsers  ==========================
+
+
+  AtomPath::AtomPath() : io::Stream()  {
+    InitAtomPath();
+  }
+
+  AtomPath::AtomPath ( cpstr ID ) : io::Stream()  {
+    InitAtomPath();
+    SetPath ( ID );
+  }
+
+  AtomPath::AtomPath  ( io::RPStream Object ) : io::Stream(Object) {
+    InitAtomPath();
+  }
+
+  AtomPath::~AtomPath() {}
+
+  void AtomPath::InitAtomPath()  {
+    modelNo     = 0;
+    chainID [0] = char(0);
+    seqNum      = MinInt4;
+    insCode [0] = char(0);
+    resName [0] = char(0);
+    atomName[0] = char(0);
+    element [0] = char(0);
+    altLoc  [0] = char(0);
+    isSet       = 0;
+  }
+
+  int AtomPath::SetPath ( cpstr ID )  {
+  //  1. If ID starts with '/':
+  //   /mdl/chn/seq(res).i/atm[elm]:a
+  //
+  //  2. If ID starts with a letter:
+  //        chn/seq(res).i/atm[elm]:a
+  //
+  //  3. If ID starts with a number:
+  //            seq(res).i/atm[elm]:a
+  //
+  //  4. If ID contains colon ':' then
+  //     it may be just
+  //                       atm[elm]:a
+  //
+  //  All spaces are ignored. isSet
+  // sets bit for each element present.
+  // Any element may be a wildcard '*'.
+  // Wildcard for model will set modelNo=0,
+  // for sequence number will set
+  // seqNum=MinInt4.
+  //
+  // Returns:
+  //   0   <-> Ok
+  //   -1  <-> wrong numerical format for model
+  //   -2  <-> wrong numerical format for sequence number
+  //
+  char N[100];
+  pstr p,p1;
+  int  i,k;
+
+    isSet = 0;  // clear all bits.
+
+    p = pstr(ID);
+    while (*p==' ')  p++;
+
+    if (!(*p))  return 0;
+
+    if (*p=='/')  {
+      //  model number
+      p++;
+      i = 0;
+      while ((*p) && (*p!='/'))  {
+        if (*p!=' ')  N[i++] = *p;
+        p++;
+      }
+      N[i] = char(0);
+      if ((!N[0]) || (N[0]=='*'))  modelNo = 0;
+      else {
+        modelNo = mround(strtod(N,&p1));
+        if ((modelNo==0) && (p1==N))  return -1;
+      }
+      isSet |= APATH_ModelNo;
+      if (*p!='/')  return 0;
+      p++;
+      while (*p==' ')  p++;
+    }
+
+    if ((*p<'0') || (*p>'9'))  {
+      //  chain ID
+      i = 0;
+      k = sizeof(ChainID)-1;
+      while ((*p) && (*p!='/'))  {
+        if ((*p!=' ') && (i<k))  chainID[i++] = *p;
+        p++;
+      }
+      chainID[i] = char(0);
+      if (!chainID[0])  {
+        chainID[0] = '*';
+        chainID[1] = char(0);
+      }
+      isSet |= APATH_ChainID;
+      if (*p!='/')  return 0;
+      p++;
+      while (*p==' ')  p++;
+    }
+
+    if (((*p>='0') && (*p<='9')) || (*p=='-') ||
+         (*p=='(') || (*p=='.'))  {
+      //  sequence number, residue name and insertion code
+      i = 0;
+      while ((*p) && (*p!='/'))  {
+        if (*p!=' ')  N[i++] = *p;
+        p++;
+      }
+      N[i] = char(0);
+      i    = ParseResID ( N,seqNum,insCode,resName );
+      if (i==2)  return -2;
+      isSet |= APATH_SeqNum | APATH_InsCode | APATH_ResName;
+      if (*p!='/')  return 0;
+      p++;
+      while (*p==' ')  p++;
+    }
+
+    if (strchr(p,':') || strchr(p,'['))  {
+      // atom name, chemical element and alternative location
+      i = 0;
+      while (*p)  {
+        if (*p!=' ')  N[i++] = *p;
+        p++;
+      }
+      N[i] = char(0);
+      ParseAtomID ( N,atomName,element,altLoc );
+      isSet |= APATH_AtomName | APATH_Element | APATH_AltLoc;
+    }
+
+    return 0;
+
+  }
+
+  void AtomPath::write ( io::RFile f )  {
+  byte Version=1;
+    f.WriteByte ( &Version );
+    io::Stream::write ( f );
+    f.WriteInt  ( &modelNo );
+    f.WriteInt  ( &seqNum  );
+    f.WriteInt  ( &isSet   );
+    f.WriteTerLine ( chainID ,false );
+    f.WriteTerLine ( insCode ,false );
+    f.WriteTerLine ( resName ,false );
+    f.WriteTerLine ( atomName,false );
+    f.WriteTerLine ( element ,false );
+    f.WriteTerLine ( altLoc  ,false );
+  }
+
+  void AtomPath::read ( io::RFile f )  {
+  byte Version;
+    f.ReadByte ( &Version );
+    io::Stream::read ( f );
+    f.ReadInt  ( &modelNo );
+    f.ReadInt  ( &seqNum  );
+    f.ReadInt  ( &isSet   );
+    f.ReadTerLine ( chainID ,false );
+    f.ReadTerLine ( insCode ,false );
+    f.ReadTerLine ( resName ,false );
+    f.ReadTerLine ( atomName,false );
+    f.ReadTerLine ( element ,false );
+    f.ReadTerLine ( altLoc  ,false );
+  }
+
+
+  MakeStreamFunctions(AtomPath)
+
+
+
+  //  --------------------------------------------------------
+
+  QuickSort::QuickSort() : io::Stream()  {
+    selSortLimit = 15;
+    data         = NULL;
+    dlen         = 0;
+  }
+
+  QuickSort::QuickSort ( io::RPStream Object )
+            : io::Stream(Object)  {
+    selSortLimit = 15;
+    data         = NULL;
+    dlen         = 0;
+  }
+
+  int QuickSort::Compare ( int i, int j )  {
+  // sort by increasing data[i]
+    if (((ivector)data)[i]<((ivector)data)[j])  return -1;
+    if (((ivector)data)[i]>((ivector)data)[j])  return  1;
+    return 0;
+  }
+
+  void QuickSort::Swap ( int i, int j )  {
+  int b;
+    b = ((ivector)data)[i];
+    ((ivector)data)[i] = ((ivector)data)[j];
+    ((ivector)data)[j] = b;
+  }
+
+  void QuickSort::SelectionSort ( int left, int right )  {
+  int i,j,imin;
+    for (i=left;i<right;i++) {
+      imin = i;
+      for (j=i+1;j<=right;j++)
+        if (Compare(j,imin)<0)  imin = j;
+      Swap ( i,imin );
+    }
+  }
+
+  int QuickSort::Partition ( int left, int right )  {
+  int lv = left;
+  int lm = left-1;
+  int rm = right+1;
+    do  {
+      do
+        rm--;
+      while ((rm>0) && (Compare(rm,lv)>0));
+      do
+        lm++;
+      while ((lm<dlen) && (Compare(lm,lv)<0));
+      if (lm<rm)  {
+        if (lv==lm)  lv = rm;
+        else if (lv==rm)  lv = lm;
+        Swap ( lm,rm );
+      }
+    } while (lm<rm);
+    return rm;
+  }
+
+  void QuickSort::Quicksort ( int left, int right )  {
+  int split_pt;
+    if (left<(right-selSortLimit)) {
+      split_pt = Partition ( left,right );
+      Quicksort ( left,split_pt    );
+      Quicksort ( split_pt+1,right );
+    } else
+      SelectionSort ( left,right );
+  }
+
+  void QuickSort::Sort ( void * sortdata, int data_len )  {
+    data = sortdata;
+    dlen = data_len-1;
+    if (data)  Quicksort ( 0,data_len-1 );
+  }
+
+  //  --------------------------------------------------------
+
+  void  takeWord ( pstr & p, pstr wrd, cpstr ter, int l )  {
+  pstr p1;
+  int  i;
+    p1 = strpbrk ( p,ter );
+    if (!p1)
+      p1 = p + strlen(p);
+    i = 0;
+    while ((p!=p1) && (i<l))  {
+      wrd[i++] = *p;
+      p++;
+    }
+    if (i>=l)  i = l-1;
+    wrd[i] = char(0);
+    p      = p1;
+  }
+
+
+  void ParseAtomID ( cpstr ID, AtomName aname, Element elname,
+                               AltLoc   aloc )  {
+  pstr p;
+
+    p = pstr(ID);
+    while (*p==' ')  p++;
+
+    strcpy ( aname ,"*" );
+    strcpy ( elname,"*" );
+    if (*p)  aloc[0] = char(0);
+       else  strcpy ( aloc,"*" );
+
+    takeWord ( p,aname,pstr("[: "),sizeof(AtomName) );
+
+    if (*p=='[')  {
+      p++;
+      takeWord ( p,elname,pstr("]: "),sizeof(Element) );
+      if (*p==']')  p++;
+    }
+
+    if (*p==':')  {
+      p++;
+      takeWord ( p,aloc,pstr(" "),sizeof(AltLoc) );
+    }
+
+  }
+
+  int ParseResID ( cpstr ID, int & sn, InsCode inscode,
+                                       ResName resname )  {
+  int  RC;
+  pstr p,p1;
+  char N[100];
+
+    RC = 0;
+
+    p = pstr(ID);
+    while (*p==' ')  p++;
+
+    sn = ANY_RES;
+    strcpy ( inscode,"*" );
+    strcpy ( resname,"*" );
+
+    N[0] = char(0);
+    takeWord ( p,N,pstr("(./ "),sizeof(N) );
+    if ((!N[0]) || (N[0]=='*'))  {
+      sn = ANY_RES;
+      RC = 1;
+    }
+    if (!RC)  {
+      sn = mround(strtod(N,&p1));
+      if (p1==N)  RC = 2;
+            else  inscode[0] = char(0);
+    }
+
+    if (*p=='(')  {
+      p++;
+      takeWord ( p,resname,pstr(")./ "),sizeof(ResName) );
+      if (*p==')')  p++;
+    }
+
+    if (*p=='.')  {
+      p++;
+      takeWord ( p,inscode,pstr("/ "),sizeof(InsCode) );
+    }
+
+    return RC;
+
+  }
+
+  int ParseAtomPath ( cpstr      ID,
+                      int &      mdl,
+                      ChainID    chn,
+                      int &      sn,
+                      InsCode    ic,
+                      ResName    res,
+                      AtomName   atm,
+                      Element    elm,
+                      AltLoc     aloc,
+                      PAtomPath DefPath )  {
+  //   /mdl/chn/seq(res).i/atm[elm]:a, may be partial
+  char    N[100];
+  pstr    p,p1;
+  int     i,RC;
+  bool wasRes;
+
+    wasRes = false;
+
+    RC = 0;
+
+    p = pstr(ID);
+    while (*p==' ')  p++;
+
+    mdl = 0;
+    if (*p=='/')  {
+      p++;
+      N[0] = char(0);
+      takeWord ( p,N,pstr("/"),sizeof(N) );
+      if ((!N[0]) || (N[0]=='*'))  mdl = 0;
+      else {
+        mdl = mround(strtod(N,&p1));
+        if ((mdl==0) && (p1==N))  return -1;
+      }
+    } else if (DefPath)  {
+      if (DefPath->isSet & APATH_ModelNo)
+        mdl = DefPath->modelNo;
+    }
+
+    strcpy ( chn,"*" );
+    if (*p=='/')  p++;
+    if ((*p<'0') || (*p>'9'))  {
+      p1 = p;
+      chn[0] = char(0);
+      takeWord ( p,chn,pstr("/"),sizeof(ChainID) );
+      if (strpbrk(chn,"(.[:-"))  { // this was not a chain ID!
+        if (DefPath)  {
+          if (DefPath->isSet & APATH_ChainID)
+            strcpy ( chn,DefPath->chainID );
+        } else
+          strcpy ( chn,"*" );
+        p = p1;
+      }
+    } else if (DefPath)  {
+      if (DefPath->isSet & APATH_ChainID)
+        strcpy ( chn,DefPath->chainID );
+    }
+
+    if (*p=='/')  p++;
+    sn = ANY_RES;
+    strcpy ( ic ,"*" );
+    strcpy ( res,"*" );
+    if (((*p>='0') && (*p<='9')) || (*p=='-') ||
+         (*p=='(') || (*p=='.'))  {
+      wasRes = true;
+      N[0] = char(0);
+      takeWord ( p,N,pstr("/"),sizeof(N) );
+      i = ParseResID ( N,sn,ic,res );
+      if (i==2)  return -2;
+    } else if (DefPath)  {
+      wasRes = (*p=='/');
+      if (DefPath->isSet & APATH_SeqNum)
+        sn = DefPath->seqNum;
+      if (DefPath->isSet & APATH_InsCode)
+        strcpy ( ic,DefPath->insCode );
+      if (DefPath->isSet & APATH_ResName)
+        strcpy ( res,DefPath->resName );
+    }
+
+    if (*p=='/')  p++;
+    strcpy ( atm ,"*" );
+    strcpy ( elm ,"*" );
+    strcpy ( aloc,"*" );
+    if (wasRes || strchr(p,':') || strchr(p,'['))  {
+      ParseAtomID ( p,atm,elm,aloc );
+    } else if (DefPath)  {
+      if (DefPath->isSet & APATH_AtomName)
+        strcpy ( atm,DefPath->atomName );
+      if (DefPath->isSet & APATH_Element)
+        strcpy ( elm,DefPath->element );
+      if (DefPath->isSet & APATH_ResName)
+        strcpy ( aloc,DefPath->altLoc );
+    }
+
+    if (mdl<=0)       RC |= APATH_WC_ModelNo;
+    if (chn[0]=='*')  RC |= APATH_WC_ChainID;
+    if (sn==ANY_RES)  RC |= APATH_WC_SeqNum;
+    if (ic[0]=='*')   RC |= APATH_WC_InsCode;
+    if (res[0]=='*')  RC |= APATH_WC_ResName;
+    if (atm[0]=='*')  RC |= APATH_WC_AtomName;
+    if (elm[0]=='*')  RC |= APATH_WC_Element;
+    if (aloc[0]=='*') RC |= APATH_WC_AltLoc;
+
+    if (RC & (APATH_WC_ModelNo  | APATH_WC_ChainID |
+              APATH_WC_SeqNum   | APATH_WC_InsCode |
+              APATH_WC_AtomName | APATH_WC_AltLoc))
+      RC |= APATH_Incomplete;
+
+    return RC;
+
+  }
+
+
+  int  ParseSelectionPath (
+               cpstr   CID,
+               int &   iModel,
+               pstr    Chains,
+               int &   sNum1,
+               InsCode ic1,
+               int &   sNum2,
+               InsCode ic2,
+               pstr    RNames,
+               pstr    ANames,
+               pstr    Elements,
+               pstr    altLocs
+                          )  {
+  int     l,j;
+  pstr    p,p1;
+  pstr    N;
+  int     seqNum [2];
+  InsCode insCode[2];
+  pstr    ID;
+  bool wasModel,wasChain,wasRes,haveNeg;
+
+    l  = IMax(10,strlen(CID))+1;
+    ID = new char[l];
+    N  = new char[l];
+
+    p  = pstr(CID);
+    p1 = ID;
+    while (*p)  {
+      if (*p!=' ')  {
+        *p1 = *p;
+        p1++;
+      }
+      p++;
+    }
+    *p1 = char(0);
+
+    p = ID;
+
+    iModel = 0;
+    strcpy ( Chains,"*" );
+    seqNum[0] = ANY_RES;
+    seqNum[1] = ANY_RES;
+    strcpy ( insCode[0],"*" );
+    strcpy ( insCode[1],"*" );
+    strcpy ( RNames    ,"*" );
+    strcpy ( ANames    ,"*" );
+    strcpy ( Elements  ,"*" );
+    strcpy ( altLocs   ,"*" );
+
+    wasModel = false;
+    wasChain = false;
+    wasRes   = false;
+
+    if (*p=='/')  {
+      //  CID starts with the slash -- take model number first
+      p++;
+      N[0] = char(0);
+      takeWord ( p,N,pstr("/"),l );
+      if ((!N[0]) || (N[0]=='*'))  iModel = 0;
+      else {
+        iModel = mround(strtod(N,&p1));
+        if ((iModel==0) && (p1==N))  return -1;
+      }
+      if (*p=='/')  p++;
+      wasModel = true;
+    }
+
+    if ((*p) && (wasModel || (*p<'0') || (*p>'9')))  {
+      p1 = p;
+      Chains[0] = char(0);
+      takeWord ( p,Chains,pstr("/"),l );
+      if (strpbrk(Chains,"(.[:-"))  {  // this was not a chain ID!
+        strcpy ( Chains,"*" );
+        p = p1;
+      } else
+        wasChain = true;
+      if (*p=='/')  p++;
+    }
+
+    if ((*p) && (wasChain  || ((*p>='0') && (*p<='9')) || (*p=='-') ||
+                 (*p=='(') || (*p=='.')  || (*p=='*')))  {
+      j = 0;
+      do  {
+        // take the sequence number
+        haveNeg  = false;
+        if (*p=='-') {
+          haveNeg = true;
+          p++;
+        }
+        N[0] = char(0);
+        takeWord ( p,N,pstr("(.-/"),l );
+        if ((!N[0]) || (N[0]=='*'))
+          seqNum[j] = ANY_RES;
+        else  {
+          seqNum[j] = mround(strtod(N,&p1));
+          if (p1==N)   return -2;
+          if (haveNeg) seqNum[j] = - seqNum[j];
+        }
+        // take the residue list
+        if (*p=='(')  {
+          p++;
+          takeWord ( p,RNames,pstr(").-/"),l );
+          if (*p==')')  p++;
+        }
+        // take the insertion code
+        if (seqNum[j]!=ANY_RES)
+          insCode[j][0] = char(0);
+        if (*p=='.')  {
+          p++;
+          takeWord ( p,insCode[j],pstr("-/"),sizeof(InsCode) );
+        }
+        if (*p=='-')  {
+          p++;
+          j++;
+        } else  {
+          if (j==0)  {
+            seqNum[1] = seqNum[0];
+            strcpy ( insCode[1],insCode[0] );
+          }
+          j = 10;
+        }
+      } while (j<2);
+      wasRes = true;
+    } else
+      wasRes = (*p=='/');
+
+    if (*p=='/')  p++;
+    if ((*p) && (wasRes || strchr(p,':') || strchr(p,'[')))  {
+      if (*p)  altLocs[0] = char(0);
+      takeWord ( p,ANames,pstr("[:"),l );
+      if (!ANames[0])  strcpy ( ANames,"*" );
+      if (*p=='[')  {
+        p++;
+        takeWord ( p,Elements,pstr("]:"),l );
+        if (*p==']')  p++;
+      }
+      if (*p==':')  {
+        p++;
+        takeWord ( p,altLocs,pstr(" "),l );
+      }
+    }
+
+    /*
+    printf ( "  iModel   = %i\n"
+             "  Chains   = '%s'\n"
+             "  seqNum1  = %i\n"
+             "  insCode1 = '%s'\n"
+             "  seqNum2  = %i\n"
+             "  insCode2 = '%s'\n"
+             "  RNames   = '%s'\n"
+             "  ANames   = '%s'\n"
+             "  Elements = '%s'\n"
+             "  altLocs  = '%s'\n",
+             iModel,Chains,seqNum[0],insCode[0],
+             seqNum[1],insCode[1],RNames,ANames,
+             Elements,altLocs );
+    */
+
+    sNum1 = seqNum[0];
+    sNum2 = seqNum[1];
+    strcpy ( ic1,insCode[0] );
+    strcpy ( ic2,insCode[1] );
+
+    delete[] ID;
+    delete[] N;
+
+    return 0;
+
+  }
+
+
+  void MakeSelectionPath (
+               pstr       CID,
+               int        iModel,
+               cpstr      Chains,
+               int        sNum1,
+               const InsCode ic1,
+               int        sNum2,
+               const InsCode ic2,
+               cpstr      RNames,
+               cpstr      ANames,
+               cpstr      Elements,
+               cpstr      altLocs
+                          )  {
+  char S[100];
+  int  k;
+
+    if (iModel>0)  {
+      sprintf ( CID,"/%i",iModel );
+      k = 1;
+    } else  {
+      CID[0] = char(0);
+      k = 0;
+    }
+
+    if (Chains[0]!='*')  {
+      if (k>0)  strcat ( CID,"/"    );
+      strcat ( CID,Chains );
+      k = 2;
+    }
+
+    if ((sNum1!=-MaxInt4) || (ic1[0]!='*'))  {
+      if (k>0)  {
+        if (k<2)  strcat ( CID,"/*" );
+        strcat  ( CID,"/" );
+      }
+      if (sNum1>-MaxInt4)  sprintf ( S,"%i",sNum1 );
+                     else  strcpy  ( S,"*" );
+      if (ic1[0]!='*')  {
+        strcat ( S,"." );
+        strcat ( S,ic1 );
+      }
+      strcat ( CID,S );
+
+      if ((sNum2!=-MaxInt4) || (ic2[0]!='*'))  {
+        strcat ( CID,"-" );
+        if (sNum1>-MaxInt4)  sprintf ( S,"%i",sNum2 );
+                       else  strcpy  ( S,"*" );
+        if (ic2[0]!='*')  {
+          strcat ( S,"." );
+          strcat ( S,ic2 );
+        }
+        strcat ( CID,S );
+      }
+
+      k = 3;
+
+    }
+
+    if (RNames[0]!='*')  {
+      if      (k<1)  strcat ( CID,"("    );
+      else if (k<2)  strcat ( CID,"*/*(" );
+      else if (k<3)  strcat ( CID,"/*("  );
+      strcat ( CID,RNames );
+      strcat ( CID,")"    );
+      k = 4;
+    }
+
+    if (ANames[0]!='*')  {
+      if      (k<1)  strcat ( CID,"/*/*/*/" );  // full path
+      else if (k<2)  strcat ( CID,"/*/*/"   );  // /mdl + /*/*/
+      else if (k<3)  strcat ( CID,"/*/"     );  // /mdl/chn + /*/
+      else if (k<4)  strcat ( CID,"/"       );  // /mdl/chn/res + /
+      strcat ( CID,ANames );
+      strcat ( CID,")"    );
+      k = 5;
+    }
+
+    if (Elements[0]!='*')  {
+      if      (k<1)  strcat ( CID,"["       );
+      else if (k<2)  strcat ( CID,"/*/*/*[" );
+      else if (k<3)  strcat ( CID,"/*/*["   );
+      else if (k<4)  strcat ( CID,"/*["     );
+      else if (k<5)  strcat ( CID,"["       );
+      strcat ( CID,Elements );
+      strcat ( CID,"]"    );
+      k = 6;
+    }
+
+    if (altLocs[0]!='*')  {
+      if      (k<1)  strcat ( CID,":"       );
+      else if (k<2)  strcat ( CID,"/*/*/*:" );
+      else if (k<3)  strcat ( CID,"/*/*:"   );
+      else if (k<4)  strcat ( CID,"/*:"     );
+      else if (k<6)  strcat ( CID,":"       );
+      strcat ( CID,altLocs );
+    }
+
+  }
+
+} // namespace mmdb
+
diff --git a/mmdb2/mmdb_utils.h b/mmdb2/mmdb_utils.h
new file mode 100644
index 0000000..e17ed74
--- /dev/null
+++ b/mmdb2/mmdb_utils.h
@@ -0,0 +1,633 @@
+//  $Id: mmdb_utils.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2008.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    12.09.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :   MMDBF_Utils <interface>
+//       ~~~~~~~~~
+//  **** Project :   MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//
+//  **** Classes :   mmdb::ContainerClass ( containered class template )
+//       ~~~~~~~~~   mmdb::ContString     ( containered string         )
+//                   mmdb::ClassContainer ( container of classes       )
+//                   mmdb::AtomPath       ( atom path ID               )
+//                   mmdb::QuickSort      ( quick sort of integers     )
+//
+//  **** Functions : Date9to11  ( DD-MMM-YY   -> DD-MMM-YYYY          )
+//       ~~~~~~~~~~~ Date11to9  ( DD-MMM-YYYY -> DD-MMM-YY            )
+//                   Date9toCIF ( DD-MMM-YY   -> YYYY-MM-DD           )
+//                   Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD           )
+//                   DateCIFto9 ( YYYY-MM-DD  -> DD-MMM-YY            )
+//                   DateCIFto11( YYYY-MM-DD  -> DD-MMM-YYYY          )
+//                   GetInteger ( reads integer from a string         )
+//                   GetReal    ( reads real from a string            )
+//                   GetIntIns  ( reads integer and insert code       )
+//                   PutInteger ( writes integer into a string        )
+//                   PutRealF   ( writes real in F-form into a string )
+//                   PutIntIns  ( writes integer and insert code      )
+//                   CIFGetInteger ( reads and deletes int from CIF   )
+//                   CIFGetReal    ( reads and deletes real from CIF  )
+//                   CIFGetString  ( reads and deletes string from CIF)
+//                   CIFGetInteger1 (reads and del-s int from CIF loop)
+//                   CIFGetReal1    (reads and del-s int from CIF loop)
+//                   Mat4Inverse    ( inversion of 4x4 matrices       )
+//                   GetErrorDescription (ascii line to an Error_XXXXX)
+//                   ParseAtomID    ( parses atom ID line             )
+//                   ParseResID     ( parses residue ID line          )
+//                   ParseAtomPath  ( parses full atom path           )
+//
+//   (C) E. Krissinel  2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_Utils__
+#define __MMDB_Utils__
+
+#include "mmdb_io_stream.h"
+#include "mmdb_mmcif_.h"
+#include "mmdb_defs.h"
+
+namespace mmdb  {
+
+  // ==================  Date functions  ===================
+
+  // converts  DD-MMM-YY  to DD-MMM-YYYY; appends terminating zero
+  extern void  Date9to11   ( cpstr Date9, pstr Date11 );
+
+  // converts DD-MMM-YYYY to DD-MMM-YY;  does not append terminating zero
+  extern void  Date11to9   ( cpstr Date11, pstr Date9 );
+
+  // converts DD-MMM-YY   to YYYY-MM-DD;  appends terminating zero
+  extern void  Date9toCIF  ( cpstr Date9, pstr DateCIF );
+
+  // converts DD-MMM-YYYY to YYYY-MM-DD;  appends terminating zero
+  extern void  Date11toCIF ( cpstr Date11, pstr DateCIF );
+
+  // converts YYYY-MM-DD  to DD-MMM-YY;   appends terminating zero
+  extern void  DateCIFto9  ( cpstr DateCIF, pstr Date9 );
+
+  // converts YYYY-MM-DD  to DD-MMM-YYYY; appends terminating zero
+  extern void  DateCIFto11 ( cpstr DateCIF, pstr Date11 );
+
+
+  // =================  Format functions  ==================
+
+  //   Returns true if S contains an integer number in its
+  // first M characters. This number is returned in N.
+  //   The return is false if no integer number may be
+  // recognized. In this case, N is assigned MinInt4 value.
+  extern bool GetInteger ( int & N, cpstr S, int M );
+
+  //   Returns true if S contains a real number in its
+  // first M characters. This number is returned in R.
+  //   The return is false if no real number may be
+  // recognized. In this case, R is assigned -MaxReal value.
+  extern bool GetReal ( realtype & R, cpstr S, int M );
+
+  //   Returns true if S contains an integer number in its
+  // first M characters. This number is returned in N. In addition
+  // to that, GetIntIns() retrieves the insertion code which may
+  // follow the integer and returns it in "ins" (1 character +
+  // terminating 0).
+  //   The return is false if no integer number may be
+  // recognized. In this case, N is assigned MinInt4 value,
+  // "ins" just returns (M+1)th symbol of S (+terminating 0).
+  extern bool  GetIntIns ( int & N, pstr ins, cpstr S, int M );
+
+  //  Integer N is converted into ASCII string of length M
+  // and pasted onto first M characters of string S. No
+  // terminating zero is added.
+  //  If N is set to MinInt4, then first M characters of
+  // string S are set to space.
+  extern void  PutInteger ( pstr S, int N, int M );
+
+  //  Real R is converted into ASCII string of length M
+  // and pasted onto first M characters of string S. No
+  // terminating zero is added. The conversion is done
+  // according to fixed format FM.L
+  //  If R is set to -MaxReal, then first M characters of
+  // string S are set to the space character.
+  extern void  PutRealF ( pstr S, realtype R, int M, int L );
+
+  //  Integer N is converted into ASCII string of length M
+  // and pasted onto first M characters of string S. No
+  // terminating zero is added. The insert code ins is put
+  // immediately after the integer.
+  //  If N is set to MinInt4, then first M+1 characters of
+  // string S are set to space, and no insert code are
+  // appended.
+  extern void  PutIntIns ( pstr S, int N, int M, cpstr ins );
+
+
+  //   CIFInteger(..), CIFReal(..) and CIFGetString(..) automate
+  // extraction and analysis of data from CIF file. If the data
+  // is erroneous or absent, they store an error message in
+  // CIFErrorLocation string (below) and return non-zero.
+  extern ERROR_CODE CIFGetInteger  ( int & I, mmcif::PStruct Struct,
+                                     cpstr Tag,
+                                     bool Remove=true );
+  extern ERROR_CODE CIFGetReal     ( realtype & R, mmcif::PStruct Struct,
+                                     cpstr Tag,
+                                     bool Remove=true );
+  extern ERROR_CODE CIFGetString   ( pstr S, mmcif::PStruct Struct,
+                                      cpstr Tag, int SLen,
+                                      cpstr DefS,
+                                      bool Remove=true );
+
+  extern ERROR_CODE CIFGetInteger  ( int & I, mmcif::PLoop Loop, cpstr Tag,
+                                     int & Signal );
+  extern ERROR_CODE CIFGetIntegerD ( int & I, mmcif::PLoop Loop, cpstr Tag,
+                                     int defValue=MinInt4 );
+  extern ERROR_CODE CIFGetInteger1 ( int & I, mmcif::PLoop Loop, cpstr Tag,
+                                     int nrow );
+
+  extern ERROR_CODE CIFGetReal     ( realtype & R, mmcif::PLoop Loop,
+                                     cpstr Tag, int & Signal );
+  extern ERROR_CODE CIFGetReal1    ( realtype & R, mmcif::PLoop Loop,
+                                     cpstr Tag, int nrow );
+
+  extern ERROR_CODE CIFGetString   ( pstr S, mmcif::PLoop Loop, cpstr Tag,
+                                     int row, int SLen, cpstr DefS );
+
+  //  Calculates AI=A^{-1}
+  extern void  Mat4Inverse ( mat44 & A, mat44 & AI );
+  //  Calculates A=B*C
+  extern void  Mat4Mult    ( mat44 & A, mat44 & B, mat44 & C );
+  //  Calculates A=B^{-1}*C
+  extern void  Mat4Div1    ( mat44 & A, mat44 & B, mat44 & C );
+  //  Calculates A=B*C^{-1}
+  extern void  Mat4Div2    ( mat44 & A, mat44 & B, mat44 & C );
+  //  Calculates determinant of the rotation part
+  extern realtype Mat4RotDet ( mat44 & T );
+
+  //  Sets up a unit matrix
+  extern void  Mat4Init  ( mat44 & A );
+  extern void  Mat3Init  ( mat33 & A );
+
+  //  Calculates AI=A^{-1}, returns determinant
+  extern realtype Mat3Inverse ( mat33 & A, mat33 & AI );
+
+  extern bool isMat4Unit ( mat44 & A, realtype eps, bool rotOnly );
+
+  //  Copies A into AC
+  extern void  Mat4Copy  ( mat44 & A, mat44 & ACopy );
+  extern void  Mat3Copy  ( mat33 & A, mat33 & ACopy );
+  extern bool  isMat4Eq  ( mat44 & A, mat44 & B, realtype eps,
+                             bool rotOnly );
+
+  extern void TransformXYZ   ( mat44 & T,
+                              realtype & X, realtype & Y, realtype & Z );
+  extern realtype TransformX ( mat44 & T,
+                               realtype X, realtype Y, realtype Z );
+  extern realtype TransformY ( mat44 & T,
+                               realtype X, realtype Y, realtype Z );
+  extern realtype TransformZ ( mat44 & T,
+                               realtype X, realtype Y, realtype Z );
+
+
+  extern char CIFErrorLocation[200];
+
+  //  Returns ASCII string explaining the nature of
+  // Error_xxxx error code.
+  extern cpstr  GetErrorDescription ( ERROR_CODE ErrorCode );
+
+
+
+  //  ================  ContainerClass  ====================
+
+  DefineClass(ContainerClass);
+  DefineStreamFunctions(ContainerClass);
+
+  class ContainerClass : public io::Stream  {
+
+    friend class ClassContainer;
+
+    public :
+
+      ContainerClass ();
+      ContainerClass ( io::RPStream Object );
+      ~ContainerClass() {}
+
+      //    ConvertPDBASCII(..) will return one of the Error_XXXXX
+      // constants, see <mmdb_defs.h>
+      virtual ERROR_CODE ConvertPDBASCII ( cpstr )
+                                         { return Error_NoError; }
+      virtual void PDBASCIIDump    ( pstr, int ) {}
+      virtual bool PDBASCIIDump1   ( io::RFile ) { return false; }
+      virtual void MakeCIF         ( mmcif::PData, int ) {}
+
+      //   Append(..) should return true if CC is appended to this class.
+      // If this is not the case, CC is merely put on the top of
+      // container.
+      //   Note: Append(..) detects the necessity to append CC and
+      // performs all the necessary actions for that. The rest of CC
+      // will be disposed by Class Container.
+      //   Note: Class Container checks every new class, which is
+      // being added to it (see CClassContainer::AddData(..)), only
+      // against the top of container.
+      virtual bool Append ( PContainerClass CC );
+
+      //  GetCIF(..) extracts any necessary information from CIF and
+      //  returns in Signal:
+      //    Error_noError : the information was successfully extracted,
+      //                  this instance of container class should be
+      //                  stored, and unchanged value of Signal should
+      //                  be passed to the next (newly created) instance
+      //                  of this container class.
+      //    Error_EmptyCIF : there is no information for this type of
+      //                  containers to extract. This instance of
+      //                  container class should be deleted and input
+      //                  for this type of container class terminated.
+      //    Other          : the corresponding error. This instance of
+      //                  container class should be deleted and the
+      //                  whole input stopped.
+      virtual ERROR_CODE GetCIF ( mmcif::PData, int & n )
+                                     { n = -1; return Error_EmptyCIF; }
+      virtual CLASS_ID GetClassID () { return ClassID_Template; }
+
+      virtual void Copy ( PContainerClass ) {}
+
+      void write ( io::RFile ) {}
+      void read  ( io::RFile ) {}
+
+    protected :
+      int  ContinuationNo;
+
+  };
+
+
+  //  ========================  ContString  =========================
+
+  DefineClass(ContString);
+  DefineStreamFunctions(ContString);
+
+  class ContString : public ContainerClass  {
+
+    public :
+
+      pstr Line;  // a string
+
+      ContString ();
+      ContString ( cpstr S );
+      ContString ( io::RPStream Object );
+      ~ContString();
+
+      ERROR_CODE ConvertPDBASCII ( cpstr S );
+      void       PDBASCIIDump    ( pstr S, int N );
+      bool       PDBASCIIDump1   ( io::RFile f );
+      void       MakeCIF         ( mmcif::PData CIF, int N );
+//      void       GetCIF1         ( mmcif::PData CIF, ERROR_CODE & Signal,
+//                                   int & pos );
+      bool       Append          ( PContainerClass ContString   );
+      CLASS_ID   GetClassID      () { return ClassID_String; }
+
+      void  Copy  ( PContainerClass CString );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      pstr CIFCategory,CIFTag;
+
+      void InitString();
+
+  };
+
+
+  //  ==============  ClassContainer  ====================
+
+  DefineClass(ClassContainer);
+  DefineStreamFunctions(ClassContainer);
+
+  class ClassContainer : public io::Stream  {
+
+    public :
+
+      ClassContainer  ();
+      ClassContainer  ( io::RPStream Object );
+      ~ClassContainer ();
+
+      void    FreeContainer      ();
+      void    AddData            ( PContainerClass Data );
+      virtual void PDBASCIIDump  ( io::RFile f );
+      virtual void MakeCIF       ( mmcif::PData CIF );
+      //  GetCIF(..) will return one of the Error_XXXXX constants,
+      //  see <mmdb_defs.h>
+      virtual ERROR_CODE  GetCIF ( mmcif::PData CIF, int ClassID );
+      virtual PContainerClass MakeContainerClass ( int ClassID );
+
+      // Copy will empty the class if parameter is set to NULL
+      virtual void Copy          ( PClassContainer CContainer );
+
+      inline int Length()  { return length; }
+      PContainerClass  GetContainerClass ( int ContClassNo );
+
+      void  write ( io::RFile f );
+      void  read  ( io::RFile f );
+
+    protected :
+      int              length;
+      PPContainerClass Container;
+
+      void Init();
+
+  };
+
+
+  //  ======================  ID parsers  ==========================
+
+  DefineClass(AtomPath);
+  DefineStreamFunctions(AtomPath);
+
+  enum APATH_FLAG  {
+    APATH_ModelNo     = 0x00000001,
+    APATH_ChainID     = 0x00000002,
+    APATH_SeqNum      = 0x00000004,
+    APATH_InsCode     = 0x00000008,
+    APATH_ResName     = 0x00000010,
+    APATH_AtomName    = 0x00000020,
+    APATH_Element     = 0x00000040,
+    APATH_AltLoc      = 0x00000080,
+    APATH_Incomplete  = 0x00000100,
+    APATH_WC_ModelNo  = 0x00001000,
+    APATH_WC_ChainID  = 0x00002000,
+    APATH_WC_SeqNum   = 0x00004000,
+    APATH_WC_InsCode  = 0x00008000,
+    APATH_WC_ResName  = 0x00010000,
+    APATH_WC_AtomName = 0x00020000,
+    APATH_WC_Element  = 0x00040000,
+    APATH_WC_AltLoc   = 0x00080000
+  };
+
+  class AtomPath : public io::Stream  {
+
+    public :
+
+      int      modelNo;
+      ChainID  chainID;
+      int      seqNum;
+      InsCode  insCode;
+      ResName  resName;
+      AtomName atomName;
+      Element  element;
+      AltLoc   altLoc;
+      int      isSet;
+
+      AtomPath  ();
+      AtomPath  ( cpstr ID );
+      AtomPath  ( io::RPStream Object );
+      ~AtomPath ();
+
+      //  SetPath(..) parses the Atom Path ID string, which
+      //  may be incomplete. Below {..} means blocks that
+      //  may be omitted; any elements within such blocks
+      //  may be omitted as well.
+      //
+      //  1. If ID starts with '/' then the ID must be of
+      //     the following form:
+      //   /mdl{/chn{/seq(res).i{/atm[elm]:a}}}
+      //
+      //  2. If ID starts with a letter:
+      //        chn{/seq(res).i{/atm[elm]:a}}
+      //
+      //  3. If ID starts with a number or '(':
+      //            seq(res).i{/atm[elm]:a}
+      //
+      //  4. If ID contains colon ':' or '[' then
+      //     it may be just
+      //                       atm[elm]:a
+      //
+      //  The following are valid samples of IDs:
+      //
+      //     /1      model number 1
+      //     /1/A/23(GLU).A/CA[C]:A  model number 1, chain A,
+      //             residue 23 GLU insertion code A, C-alpha
+      //             atom in alternative location A
+      //     A/23    residue 23 of chain A
+      //     CA[C]:  atom C-alpha
+      //     [C]     a carbon
+      //     *[C]:*  same as above
+      //     :A      an atom with insertion code A
+      //     5       residue number 5
+      //     (GLU)   residue GLU
+      //
+      //   All spaces are ignored. SetPath(..) sets bit of isSet
+      // for each element present. Any element may be a wildcard
+      // '*'. Wildcard for model will set modelNo=0, for sequence
+      // number will set seqNum=MinInt4.
+      //
+      // Returns:
+      //   0   <-> Ok
+      //   -1  <-> wrong numerical format for model
+      //   -2  <-> wrong numerical format for sequence number
+      int SetPath ( cpstr ID );
+
+      void write ( io::RFile f );
+      void read  ( io::RFile f );
+
+    protected :
+      void InitAtomPath();
+
+  };
+
+
+  //  --------------------------------------------------------------
+
+  DefineClass(QuickSort);
+
+  class QuickSort : public io::Stream  {
+
+    public :
+      QuickSort ();
+      QuickSort ( io::RPStream Object );
+      ~QuickSort() {}
+      virtual int  Compare ( int i, int j );
+      virtual void Swap    ( int i, int j );
+      void Sort ( void * sortdata, int data_len );
+
+    protected :
+      int    selSortLimit,dlen;
+      void * data;
+
+      void SelectionSort ( int left, int right );
+      int  Partition     ( int left, int right );
+      void Quicksort     ( int left, int right );
+
+  };
+
+
+  //  --------------------------------------------------------------
+
+  extern void  takeWord ( pstr & p, pstr wrd, cpstr ter, int l );
+
+  //   ParseAtomID(..) reads the atom ID of the following form:
+  //    {name} {[element]} {:altcode}
+  // (here {} means that the item may be omitted; any field may have
+  // value of wildcard '*'), and returns the atom name in aname,
+  // element name - in elname, and alternate location code - in aloc.
+  // Except for the alternate location code, missing items are
+  // replaced by wildcards. Missing alternate location code is
+  // returned as empty string "".
+  //   Leading spaces are allowed; any other space will terminate
+  // the parsing.
+  //   The followings are perfectly valid atom IDs:
+  //        CA[C]:A     (carbon C_alpha in location A)
+  //        CA[*]:A     (either C_alpha or Ca in location A)
+  //        CA:A        (same as above)
+  //        CA          (either C_alpha or Ca with no location indicator)
+  //        CA[]        (same as above)
+  //        CA[C]:      (C_alpha with no location indicator)
+  //        [C]         (any carbon with no location indicator)
+  //        [C]:*       (any carbon with any location indicator)
+  //        *[C]:*      (same as above)
+  //        :A          (any atom in location A)
+  //        *[*]:A      (same as above)
+  //        *[*]:*      (any atom)
+  //        *           (any atom with no alternate location indicator)
+  extern void ParseAtomID ( cpstr ID, AtomName aname,
+                            Element elname, AltLoc   aloc );
+
+  //   ParseResID(..) reads the residue ID of the following form:
+  //    {seqnum} {(name)} {.inscode}
+  // (here {} means that the item may be omitted; any field may have
+  // value of wildcard '*'), and returns the sequence number in sn,
+  // insertion code - in inscode, and residue name - in resname.
+  // If a wildcard was specified for the sequence number, then
+  // ParseResID(..) returns 1. Missing residue name is replaced by
+  // the wildcard '*', and misisng insertion code is returned as empty
+  // string "".
+  //   Leading spaces are allowed; any other space will terminate
+  // the parsing.
+  //   Return 0 means Ok, 1 - wildcard for the sequence number,
+  // 2 - an error in numerical format of the sequence number
+  // (other items are parsed).
+  //   The followings are perfectly valid residue IDs:
+  //        27(ALA).A   (residue 27A ALA)
+  //        27().A      (residue 27A)
+  //        27(*).A     (same as above)
+  //        27.A        (same as above)
+  //        27          (residue 27)
+  //        27().       (same as above)
+  //        (ALA)       (any ALA without insertion code)
+  //        (ALA).      (same as above)
+  //        (ALA).*     (any ALA)
+  //        *(ALA).*    (any ALA)
+  //        .A          (any residue with insertion code A)
+  //        *(*).A      (same as above)
+  //        *(*).*      (any residue)
+  //        *           (any residue with no insertion code)
+  extern int ParseResID ( cpstr ID, int & sn,
+                          InsCode inscode, ResName resname );
+
+
+  //   ParseAtomPath(..) parses an atom path string of the following
+  // structure:
+  //   /mdl/chn/seq(res).i/atm[elm]:a
+  // where all items may be represented by a wildcard '*' and
+  //   mdl   - model number (mandatory); at least model #1 is always
+  //           present; returned in mdl; on a wildcard mdl is set to 0
+  //   chn   - chain identifier ( mandatory); returned in chn; on a
+  //           wildcard chn is set to '*'
+  //   seq   - residue sequence number (mandatory); returned in sn;
+  //           on a wild card ParseAtomPath(..) returns 1
+  //   (res) - residue name in round brackets (may be omitted);
+  //           returnded in res; on a wildcard res is set to '*'
+  //   .i    - insert code after a dot; if '.i' or 'i' is missing
+  //           then a residue without an insertion code is looked for;
+  //           returned in ic; on a wildcard (any insertion code would
+  //           do) ic is set to '*'
+  //   atm   - atom name (mandatory); returned in atm; on a wildcard
+  //           atm is set to '*'
+  //   [elm] - chemical element code in square brackets; it may
+  //           be omitted but could be helpful for e.g.
+  //           distinguishing C_alpha and CA; returned in elm;
+  //           in a wildcard elm is set to '*'
+  //   :a    - alternate location indicator after colon; if
+  //           ':a' or 'a' is missing then an atom without
+  //           alternate location indicator is looked for; returned
+  //           in aloc; on a wildcard (any alternate code would do)
+  //           aloc is set to '*'.
+  // All spaces are ignored, all identifiers should be in capital
+  // letters (comparisons are case-sensitive).
+  //   The atom path string may be incomplete. If DefPath is supplied,
+  // the function will try to get missing elements from there. If
+  // missing items may not be found in DefPath, they are replaced by
+  // wildcards.
+  //   ParseAtomPath(..) returns the following bits:
+  //      0                 - Ok
+  //      APATH_Incomplete  - if path contains wildcards. Wildcards for
+  //                          residue name and chemical element will be
+  //                          ignored here if sequence number and
+  //                          atom name, correspondingly, are provided.
+  //      APATH_WC_XXXXX    - wildcard for different elements
+  //      -1                - wrong numerical format for model (fatal)
+  //      -2                - wrong numerical format for seqNum (fatal)
+
+  extern int ParseAtomPath ( cpstr     ID,
+                             int &     mdl,
+                             ChainID   chn,
+                             int &     sn,
+                             InsCode   ic,
+                             ResName   res,
+                             AtomName  atm,
+                             Element   elm,
+                             AltLoc    aloc,
+                             PAtomPath DefPath=NULL );
+
+
+
+  extern int ParseSelectionPath ( cpstr   CID,
+                                  int &   iModel,
+                                  pstr    Chains,
+                                  int &   sNum1,
+                                  InsCode ic1,
+                                  int &   sNum2,
+                                  InsCode ic2,
+                                  pstr    RNames,
+                                  pstr    ANames,
+                                  pstr    Elements,
+                                  pstr    altLocs );
+
+
+
+  extern void MakeSelectionPath ( pstr       CID,
+                                  int        iModel,
+                                  cpstr      Chains,
+                                  int        sNum1,
+                                  const InsCode ic1,
+                                  int        sNum2,
+                                  const InsCode ic2,
+                                  cpstr      RNames,
+                                  cpstr      ANames,
+                                  cpstr      Elements,
+                                  cpstr      altLocs );
+
+}  // namespace mmdb
+
+#endif
+
diff --git a/mmdb2/mmdb_xml_.cpp b/mmdb2/mmdb_xml_.cpp
new file mode 100644
index 0000000..da0c532
--- /dev/null
+++ b/mmdb2/mmdb_xml_.cpp
@@ -0,0 +1,986 @@
+//  $Id: mmdb_xml_.cpp $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    06.12.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_XML <implementation>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::xml::XMLObject
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mmdb_xml_.h"
+
+namespace mmdb  {
+
+  namespace xml  {
+
+    //  ======================  XMLObject  ==========================
+
+    XMLObject::XMLObject() : io::Stream()  {
+      InitXMLObject();
+    }
+
+    XMLObject::XMLObject ( cpstr Tag ) : io::Stream()  {
+      InitXMLObject();
+      SetTag  ( Tag );
+    }
+
+    XMLObject::XMLObject ( cpstr Tag, cpstr Data ) : io::Stream()  {
+      InitXMLObject();
+      SetTag  ( Tag  );
+      SetData ( Data );
+    }
+
+    XMLObject::XMLObject ( cpstr Tag, realtype V, int length )
+              : io::Stream()  {
+      InitXMLObject();
+      SetTag  ( Tag      );
+      SetData ( V,length );
+    }
+
+    XMLObject::XMLObject ( cpstr Tag, int iV, int length )
+              : io::Stream()  {
+      InitXMLObject();
+      SetTag  ( Tag       );
+      SetData ( iV,length );
+    }
+
+    XMLObject::XMLObject ( cpstr Tag, bool bV ) : io::Stream()  {
+      InitXMLObject();
+      SetTag  ( Tag );
+      SetData ( bV  );
+    }
+
+    XMLObject::XMLObject ( cpstr Tag, PXMLObject XMLObject )
+              : io::Stream()  {
+      InitXMLObject();
+      SetTag    ( Tag       );
+      AddObject ( XMLObject );
+    }
+
+
+    XMLObject::XMLObject ( io::RPStream Object ) : io::Stream(Object)  {
+      InitXMLObject();
+    }
+
+    XMLObject::~XMLObject()  {
+      FreeMemory();
+    }
+
+    void  XMLObject::InitXMLObject()  {
+      parent      = NULL;
+      objTag      = NULL;
+      objData     = NULL;
+      nObjects    = 0;
+      nAlloc      = 0;
+      object      = NULL;
+      nAttributes = 0;
+      nAttrAlloc  = 0;
+      attr_name   = NULL;
+      attr_value  = NULL;
+    }
+
+    void  XMLObject::FreeMemory()  {
+    int i;
+
+      if (objTag)   delete[] objTag;
+      if (objData)  delete[] objData;
+
+      objTag   = NULL;
+      objData  = NULL;
+
+      if (object)  {
+        for (i=0;i<nAlloc;i++)
+          if (object[i])  delete object[i];
+        delete[] object;
+      }
+
+      nObjects = 0;
+      nAlloc   = 0;
+      object   = NULL;
+
+      if (attr_name)  {
+        for (i=0;i<nAttrAlloc;i++)  {
+          if (attr_name [i])  delete[] attr_name [i];
+          if (attr_value[i])  delete[] attr_value[i];
+        }
+        FreeVectorMemory ( attr_name ,0 );
+        FreeVectorMemory ( attr_value,0 );
+      }
+
+      nAttributes = 0;
+      nAttrAlloc  = 0;
+      attr_name   = NULL;
+      attr_value  = NULL;
+
+    }
+
+    void  XMLObject::SetTag ( cpstr Tag )  {
+    pstr p,t;
+    int  n;
+
+      // count ampersands
+      p = pstr(Tag);
+      n = 0;
+      while (*p)  {
+        if (*p=='&')  n++;
+        p++;
+      }
+      // calculate the tag length
+      n = n*4 + strlen(Tag) + 1;
+      // substract leading underscores
+      p = pstr(Tag);
+      while (*p=='_')  {
+        p++;
+        n--;
+      }
+      // allocate tag space
+      if (objTag)  delete[] objTag;
+      objTag = new char[n];
+      // copy tag, replacing square brackets and ampersands
+      t = objTag;
+      while (*p)  {
+        if (*p=='[')  {
+          *t = '-';
+          t++;
+        } else if (*p==']')  {
+          if ((p[1]) && (p[1]!='['))  {
+            *t = '-';
+            t++;
+          }
+        } else if (*p=='&')  {
+          strcpy ( t,"_and_" );
+          if (p[1])  t += 5;
+               else  t += 4;
+        } else  {
+          *t = *p;
+          t++;
+        }
+        p++;
+      }
+      *t = char(0);
+    }
+
+    void  XMLObject::AddAttribute ( cpstr name, cpstr value )  {
+    psvector an,av;
+    int      i;
+
+      if (nAttributes>=nAttrAlloc)  {
+        nAttrAlloc = nAttributes + 10;
+        GetVectorMemory ( an,nAttrAlloc,0 );
+        GetVectorMemory ( av,nAttrAlloc,0 );
+        for (i=0;i<nAttrAlloc;i++)  {
+          an[i] = NULL;
+          av[i] = NULL;
+        }
+        for (i=0;i<nAttributes;i++)  {
+          CreateCopy ( an[i],attr_name [i] );
+          CreateCopy ( av[i],attr_value[i] );
+          if (attr_name [i])  delete[] attr_name [i];
+          if (attr_value[i])  delete[] attr_value[i];
+        }
+        FreeVectorMemory ( attr_name ,0 );
+        FreeVectorMemory ( attr_value,0 );
+        attr_name  = an;
+        attr_value = av;
+      }
+
+      CreateCopy ( attr_name [nAttributes],name  );
+      CreateCopy ( attr_value[nAttributes],value );
+      nAttributes++;
+
+    }
+
+    void  XMLObject::AddAttribute ( cpstr name, const int iV )  {
+    char S[100];
+      sprintf ( S,"%i",iV );
+      AddAttribute ( name,S );
+    }
+
+    void  XMLObject::AddAttribute ( cpstr name, const bool bV )  {
+      if (bV)  AddAttribute ( name,"Yes" );
+         else  AddAttribute ( name,"No"  );
+    }
+
+    void  XMLObject::SetData ( cpstr Data )  {
+    pstr p,d;
+    int  n;
+      // count ampersands
+      p = pstr(Data);
+      n = 0;
+      while (*p)  {
+        if (*p=='&')  n += 4;
+        p++;
+      }
+      // calculate the Data length
+      n += strlen(Data) + 1;  // eugene
+      // allocate data space
+      if (objData)  delete[] objData;
+      objData = new char[n];
+      // copy data, preceeding ampersands with the escape
+      p = pstr(Data);
+      d = objData;
+      while (*p)  {
+        if (*p=='&')  {
+          d[0] = '&';
+          d[1] = 'a';
+          d[2] = 'm';
+          d[3] = 'p';
+          d[4] = ';';
+          d += 5;
+        } else  {
+          *d = *p;
+          d++;
+        }
+        p++;
+      }
+      *d = char(0);
+    }
+
+    void  XMLObject::AddData ( cpstr Data )  {
+    pstr d1,d2;
+      d1      = objData;
+      objData = NULL;
+      SetData ( Data );
+      d2      = objData;
+      objData = NULL;
+      CreateConcat ( objData,d1,d2 );
+    }
+
+    void  XMLObject::SetData ( const realtype V, const int length )  {
+    char N[500];
+      sprintf    ( N,"%-.*g",length,V );
+      CreateCopy ( objData,N );
+    }
+
+    void  XMLObject::SetData ( const int iV, const int length )  {
+    char N[500];
+      sprintf    ( N,"%*i",length,iV );
+      CreateCopy ( objData,N );
+    }
+
+    void  XMLObject::SetData ( const bool bV )  {
+      if (bV)  CreateCopy ( objData,pstr("Yes") );
+         else  CreateCopy ( objData,pstr("No")  );
+    }
+
+
+    int XMLObject::AddMMCIFCategory ( mmcif::PCategory mmCIFCat )  {
+      if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Loop)
+        return AddMMCIFLoop ( mmcif::PLoop(mmCIFCat) );
+      if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Struct)
+        return AddMMCIFStruct ( mmcif::PStruct(mmCIFCat) );
+      return -1;
+    }
+
+    pstr getCCIFTag ( pstr & ccifTag, cpstr Tag )  {
+      if (Tag[0]=='_')  return CreateCopCat ( ccifTag,pstr("ccif") ,Tag );
+                  else  return CreateCopCat ( ccifTag,pstr("ccif_"),Tag );
+    }
+
+    int XMLObject::AddMMCIFStruct ( mmcif::PStruct mmCIFStruct )  {
+    PXMLObject XMLObject1,XMLObject2;
+    pstr       SName,Tag,Field, ccifTag;
+    int        nTags,i,k;
+
+      XMLObject1 = this;
+
+      ccifTag = NULL;
+
+      SName = mmCIFStruct->GetCategoryName();
+      if (SName)  {
+        if (SName[0]!=char(1))
+          XMLObject1 = new XMLObject ( getCCIFTag(ccifTag,SName) );
+      }
+
+      k = 0;
+      nTags = mmCIFStruct->GetNofTags();
+      for (i=0;i<nTags;i++)  {
+        Tag = mmCIFStruct->GetTag ( i );
+        if (Tag)  {
+          XMLObject2 = new XMLObject ( getCCIFTag(ccifTag,Tag) );
+          Field = mmCIFStruct->GetField ( i );
+          if (Field)  {
+            if (Field[0]!=char(2))  XMLObject2->SetData ( Field );
+                              else  XMLObject2->SetData ( &(Field[1]) );
+          }
+          XMLObject1->AddObject ( XMLObject2 );
+          k++;
+        }
+      }
+
+      if (SName)  {
+        if (SName[0]!=char(1))
+          AddObject ( XMLObject1 );
+      }
+
+      if (ccifTag)  delete[] ccifTag;
+
+      return k;
+
+    }
+
+    int XMLObject::AddMMCIFLoop ( mmcif::PLoop mmCIFLoop )  {
+    PXMLObject XMLObject1,XMLObject2,XMLObject3;
+    pstr        SName,Tag,Field,ccifTag;
+    int         nTags,nRows,i,j,k;
+
+      XMLObject1 = this;
+
+      ccifTag = NULL;
+
+      SName = mmCIFLoop->GetCategoryName();
+      if (SName)  {
+        if (SName[0]!=char(1))
+          XMLObject1 = new XMLObject ( getCCIFTag(ccifTag,SName) );
+      }
+
+      k = 0;
+      nTags = mmCIFLoop->GetNofTags   ();
+      nRows = mmCIFLoop->GetLoopLength();
+      for (i=0;i<nRows;i++)  {
+        XMLObject2 = new XMLObject ( pstr("row"),
+                          new XMLObject(pstr("_sernum_"),i+1) );
+        for (j=0;j<nTags;j++)  {
+          Tag = mmCIFLoop->GetTag ( j );
+          if (Tag)  {
+            XMLObject3 = new XMLObject ( getCCIFTag(ccifTag,Tag) );
+            Field = mmCIFLoop->GetField ( i,j );
+            if (Field)  {
+              if (Field[0]!=char(2))  XMLObject3->SetData ( Field );
+                                else  XMLObject3->SetData ( &(Field[1]) );
+            }
+            XMLObject2->AddObject ( XMLObject3 );
+            k++;
+          }
+        }
+        XMLObject1->AddObject ( XMLObject2 );
+      }
+
+      if (SName)  {
+        if (SName[0]!=char(1))
+          AddObject ( XMLObject1 );
+      }
+
+      if (ccifTag)  delete[] ccifTag;
+
+      return k;
+
+    }
+
+    int  XMLObject::AddMMCIFData ( mmcif::PData mmCIFData )  {
+    mmcif::PCategory mmCIFCat;
+    int              nCats,i,k,n;
+      nCats = mmCIFData->GetNumberOfCategories();
+      k     = 0;
+      n     = 0;
+      for (i=0;(i<nCats) && (n>=0);i++)  {
+        mmCIFCat = mmCIFData->GetCategory ( i );
+        if (mmCIFCat)  {
+          if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Loop)
+            n = AddMMCIFLoop ( mmcif::PLoop(mmCIFCat) );
+          else if (mmCIFCat->GetCategoryID()==mmcif::MMCIF_Struct)
+            n = AddMMCIFStruct ( mmcif::PStruct(mmCIFCat) );
+          else
+            n = -1;
+          if (n>=0)  k += n;
+        }
+      }
+      if (n<0)  return -(k+1);
+      return k;
+    }
+
+    pstr  XMLObject::GetData ( cpstr Tag, int objNo )  {
+    PXMLObject XMLObject;
+      XMLObject = GetObject ( Tag,objNo );
+      if (XMLObject)  return XMLObject->objData;
+      return NULL;
+    }
+
+    XML_RC XMLObject::GetData ( pstr & Data, cpstr Tag, int objNo )  {
+    PXMLObject XMLObject;
+      XMLObject = GetObject ( Tag,objNo );
+      if (XMLObject)  {
+        Data = XMLObject->objData;
+        return XMLRC_Ok;
+      } else  {
+        Data = NULL;
+        return XMLRC_NoTag;
+      }
+    }
+
+    XML_RC XMLObject::GetData ( realtype & V, cpstr Tag, int objNo )  {
+    pstr   d,p;
+    XML_RC rc;
+      rc = GetData ( d,Tag,objNo );
+      if (d)  {
+        V = strtod(d,&p);
+        if ((V==0.0) && (p==d))  rc = XMLRC_RFormatError;
+                           else  rc = XMLRC_Ok;
+      } else if (!rc)
+        rc = XMLRC_NoTag;
+      return rc;
+    }
+
+    XML_RC XMLObject::GetData ( int & iV, cpstr Tag, int objNo )  {
+    pstr d,p;
+    XML_RC rc;
+      rc = GetData ( d,Tag,objNo );
+      if (d)  {
+        iV = mround(strtod(d,&p));
+        if ((iV==0) && (p==d))  rc = XMLRC_IFormatError;
+                          else  rc = XMLRC_Ok;
+      } else if (!rc)
+        rc = XMLRC_NoTag;
+      return rc;
+    }
+
+    XML_RC XMLObject::GetData ( bool & bV, cpstr Tag, int objNo )  {
+    pstr   d;
+    XML_RC rc;
+      rc = GetData ( d,Tag,objNo );
+      if (d)  {
+        if (!strcasecmp(d,"Yes"))
+          bV = true;
+        else {
+          bV = false;
+          if (strcasecmp(d,"No"))  rc = XMLRC_OFormatError;
+        }
+      } else if (rc==XMLRC_Ok)
+        rc = XMLRC_NoTag;
+      return rc;
+    }
+
+    PXMLObject XMLObject::GetObject ( cpstr Tag, int objNo )  {
+    // allow for "tag1>tag2>tag3>..."
+    PXMLObject XMLObject;
+    pstr       p,p1;
+    int        i,j,k,l;
+      XMLObject = this;
+      if (Tag)  {
+        p = pstr(Tag);
+        do  {
+          p1 = p;
+          l  = 0;
+          while (*p1 && (*p1!='>'))  {
+            p1++;
+            l++;
+          }
+          if (l>0)  {
+            k = -1;
+            j = 0;
+            for (i=0;(i<XMLObject->nObjects) && (k<0);i++)
+              if (XMLObject->object[i])  {
+                if (!strncmp(XMLObject->object[i]->objTag,p,l))  {
+                  j++;
+                  if (j==objNo)  k = i;
+                }
+              }
+            if (k<0)  {
+              XMLObject = NULL;
+              l = 0;
+            } else  {
+              XMLObject = XMLObject->object[k];
+              if (*p1)  p = p1 + 1;
+                  else  l = 0;
+            }
+          }
+        } while (l>0);
+      }
+      return XMLObject;
+    }
+
+    PXMLObject XMLObject::GetFirstObject()  {
+      if (nObjects>0)  return object[0];
+      return NULL;
+    }
+
+    PXMLObject XMLObject::GetLastObject()  {
+      if (nObjects>0)  return object[nObjects-1];
+      return NULL;
+    }
+
+    PXMLObject XMLObject::GetObject ( int objectNo )  {
+      if ((0<=objectNo) && (objectNo<nObjects))
+        return object[objectNo];
+      return NULL;
+    }
+
+    void  XMLObject::AddObject ( PXMLObject XMLObject, int lenInc )  {
+    PPXMLObject obj1;
+    int         i;
+
+      if (!XMLObject)  return;
+
+      if (nObjects>=nAlloc)  {
+        nAlloc += lenInc;
+        obj1 = new PXMLObject[nAlloc];
+        for (i=0;i<nObjects;i++)
+          obj1[i] = object[i];
+        for (i=nObjects;i<nAlloc;i++)
+          obj1[i] = NULL;
+        if (object)  delete[] object;
+        object = obj1;
+      }
+
+      if (object[nObjects])  delete object[nObjects];
+      object[nObjects] = XMLObject;
+      XMLObject->SetParent ( this );
+      nObjects++;
+
+    }
+
+
+    void  XMLObject::InsertObject ( PXMLObject XMLObject, int pos,
+                                    int lenInc )  {
+    PPXMLObject obj1;
+    int         i;
+
+      if (!XMLObject)  return;
+      if (pos>=nObjects)  {
+        AddObject ( XMLObject,lenInc );
+        return;
+      }
+
+      if (nObjects>=nAlloc)  {
+        nAlloc += lenInc;
+        obj1 = new PXMLObject[nAlloc];
+        for (i=0;i<nObjects;i++)
+          obj1[i] = object[i];
+        for (i=nObjects;i<nAlloc;i++)
+          obj1[i] = NULL;
+        if (object)  delete[] object;
+        object = obj1;
+      }
+
+      for (i=nObjects;i>pos;i--)
+        object[i] = object[i-1];
+
+      object[pos] = XMLObject;
+      XMLObject->SetParent ( this );
+      nObjects++;
+
+    }
+
+    XML_RC XMLObject::WriteObject ( cpstr FName, int pos, int indent )  {
+    io::File f;
+      f.assign ( FName,true );
+      if (f.rewrite())  {
+        WriteObject ( f,pos,indent );
+        f.shut();
+        return XMLRC_Ok;
+      }
+      return XMLRC_CantOpenFile;
+    }
+
+    void  XMLObject::WriteObject ( io::RFile f, int pos, int indent )  {
+    int   i,pos1,lm,rm,tl;
+    pstr  indstr,p,p1,q;
+    bool  sngline;
+
+      if (objTag)  {
+
+        pos1   = pos + indent;
+        indstr = new char[pos1+1];
+        for (i=0;i<pos1;i++)  indstr[i] = ' ';
+        indstr[pos1] = char(0);
+
+        indstr[pos]  = char(0);
+        f.Write ( indstr    );
+        f.Write ( pstr("<") );
+        f.Write ( objTag    );
+        for (i=0;i<nAttributes;i++)  {
+          f.Write ( " " );
+          f.Write ( attr_name[i] );
+          f.Write ( "=\"" );
+          f.Write ( attr_value[i] );
+          f.Write ( "\"" );
+        }
+        if ((!objData) && (nObjects<=0))  {
+          f.WriteLine ( pstr("/>") );
+          delete[] indstr;
+          return;
+        }
+        f.Write ( pstr(">") );
+
+        sngline = false;
+        if (objData)  {
+          rm = 72;               // right margin
+          lm = IMin ( pos1,36 ); // left margin
+          tl = strlen(objTag);
+          if ((pos+tl+2+(int)strlen(objData)<rm-tl-2) &&
+              (nObjects<=0))  {
+            // single-line output
+            sngline = true;
+            f.Write ( objData );
+          } else  {
+            // multiple-line output with indentation
+            indstr[pos] = ' ';
+            indstr[lm]  = char(0);
+            f.LF();
+            p = objData;
+            do  {
+              p1 = p;
+              i  = lm;
+              q  = NULL;
+              while ((*p1) && ((i<rm) || (!q)))  {
+                if (*p1==' ')  q = p1;
+                p1++;
+                i++;
+              }
+              f.Write ( indstr );
+              if (*p1)  {  // wrap data
+                *q = char(0);
+                f.WriteLine ( p );
+                *q = ' ';
+                p  = q;
+                while (*p==' ')  p++;
+                if (*p==char(0))  p = NULL;
+
+              } else {  // data exchausted
+                f.WriteLine ( p );
+                p = NULL;
+              }
+            } while (p);
+            indstr[lm]  = ' ';
+            indstr[pos] = char(0);
+          }
+        } else
+          f.LF();
+
+        for (i=0;i<nObjects;i++)
+          if (object[i])
+            object[i]->WriteObject ( f,pos+indent,indent );
+
+        if (!sngline)  f.Write ( indstr );
+        f.Write ( pstr("</") );
+        f.Write ( objTag  );
+        f.WriteLine ( pstr(">") );
+
+        delete[] indstr;
+
+      }
+
+    }
+
+
+    XML_RC XMLObject::ReadObject ( cpstr FName )  {
+    io::File f;
+    char     S[500];
+    int      i;
+    XML_RC   rc;
+
+      f.assign ( FName,true );
+      if (f.reset(true))  {
+        S[0] = char(0);
+        i    = 0;
+        rc   = ReadObject ( f,S,i,sizeof(S) );
+        f.shut();
+      } else
+        rc = XMLRC_NoFile;
+
+      if (rc!=XMLRC_Ok)  FreeMemory();
+
+      return rc;
+
+    }
+
+    XML_RC XMLObject::ReadObject ( io::RFile f, pstr S,
+                                   int & pos, int slen )  {
+    PXMLObject xmlObject;
+    pstr       S1;
+    int        k,k1,k2;
+    XML_RC     rc;
+    bool       Done;
+
+      FreeMemory();
+
+      rc = XMLRC_Ok;
+
+      k1 = -1;
+      k2 = -1;
+      while ((!f.FileEnd()) && (k1<0))  {
+        k = strlen(S);
+        while ((pos<k) && (k1<0))
+          if (S[pos]=='<')  {
+            if (S[pos+1]=='?') // in this version, ignore <?xxx ?>
+                               //   constructions
+                 pos++;
+            else if (S[pos+1]!='<')
+                 k1 = pos;
+            else pos += 2;
+          } else
+            pos++;
+        if (k1>=0)  {
+          k2 = -1;
+          while ((pos<k) && (k2<0))
+            if (S[pos]=='>')  {
+              if (S[pos+1]!='>')  k2 = pos;
+                            else  pos += 2;
+            } else
+              pos++;
+          if (k2<0)  rc = XMLRC_BrokenTag;
+        }
+        if (k1<0)  {
+          f.ReadLine ( S,slen );
+          pos = 0;
+        }
+      }
+
+      if (k1<0)         return XMLRC_NoTag;
+      if (rc!=XMLRC_Ok) return rc;
+
+      pos++;
+      if (S[k2-1]=='/')  {  // <Tag/>
+        S[k2-1] = char(0);
+        CreateCopy ( objTag,&(S[k1+1]) );
+        return XMLRC_Ok;
+      }
+
+      S[k2] = char(0);
+      CreateCopy ( objTag,&(S[k1+1]) );
+      S[k2] = '>';
+
+      S1   = new char[slen+1];
+      Done = false;
+      while ((!f.FileEnd()) && (!Done))  {
+        k = strlen(S);
+        while ((pos<k) && (!Done))  {
+          k1 = pos;
+          k2 = -1;
+          while ((pos<k) && (k2<0))
+            if (S[pos]=='<')  {
+              if (S[pos+1]!='<')  k2 = pos;
+                            else  pos +=2;
+            } else
+              pos++;
+          if (k2>=0)  S[k2] = char(0);
+          strcpy_des   ( S1,&(S[k1]) );
+          if (S1[0])  {
+            if (objData)  CreateConcat ( objData,pstr(" "),S1 );
+                    else  CreateConcat ( objData,S1 );
+          }
+          if (k2>=0)  {
+            S[k2] = '<';
+            if (S[k2+1]!='/')  {
+              xmlObject = new XMLObject();
+              AddObject ( xmlObject );
+              rc   = xmlObject->ReadObject ( f,S,pos,slen );
+              Done = (rc!=XMLRC_Ok);
+            } else  {
+              Done = true;
+              k1   = k2+2;
+              k2   = -1;
+              while ((pos<k) && (k2<0))
+                if (S[pos]=='>')  {
+                  if (S[pos+1]!='>')  k2 = pos;
+                                else  pos += 2;
+                  } else
+                    pos++;
+              if (k2<0)
+                rc = XMLRC_BrokenTag;
+              else  {
+                S[k2] = char(0);
+                if (strcmp(objTag,&(S[k1])))  rc = XMLRC_UnclosedTag;
+                                        else  pos++;
+              }
+            }
+          }
+        }
+        if (!Done)  {
+          f.ReadLine ( S,slen );
+          pos = 0;
+        }
+      }
+
+      delete[] S1;
+
+      // this keeps pairs <tag></tag> instead of replacing them for <tag/>
+      // on output
+      if ((!objData) && (nObjects<=0))
+        CreateCopy ( objData,pstr("") );
+
+      if (rc!=XMLRC_Ok)  FreeMemory();
+      return rc;
+
+    }
+
+
+    void  XMLObject::Copy ( PXMLObject xmlObject )  {
+    int i;
+
+      FreeMemory();
+
+      CreateCopy ( objTag ,xmlObject->objTag  );
+      CreateCopy ( objData,xmlObject->objData );
+
+      nObjects = xmlObject->nObjects;
+      nAlloc   = nObjects;
+      if (nObjects>0)  {
+        object = new PXMLObject[nObjects];
+        for (i=0;i<nObjects;i++)
+          if (xmlObject->object[i])  {
+            object[i] = new XMLObject();
+            object[i]->Copy ( xmlObject->object[i] );
+          } else
+            object[i] = NULL;
+      }
+
+      nAttributes = xmlObject->nAttributes;
+      nAttrAlloc  = nAttributes;
+      if (nAttributes>0)  {
+        GetVectorMemory ( attr_name ,nAttrAlloc,0 );
+        GetVectorMemory ( attr_value,nAttrAlloc,0 );
+        for (i=0;i<nAttributes;i++)  {
+          attr_name [i] = NULL;
+          attr_value[i] = NULL;
+          CreateCopy ( attr_name [i],xmlObject->attr_name [i] );
+          CreateCopy ( attr_value[i],xmlObject->attr_value[i] );
+        }
+      }
+
+    }
+
+
+    void  XMLObject::write ( io::RFile f )  {
+    int i;
+      f.CreateWrite ( objTag       );
+      f.CreateWrite ( objData      );
+      f.WriteInt    ( &nObjects    );
+      for (i=0;i<nObjects;i++)
+        StreamWrite ( f,object[i] );
+      f.WriteInt    ( &nAttributes );
+      for (i=0;i<nAttributes;i++)  {
+        f.CreateWrite ( attr_name [i] );
+        f.CreateWrite ( attr_value[i] );
+      }
+    }
+
+    void  XMLObject::read ( io::RFile f )  {
+    int i;
+
+      FreeMemory();
+
+      f.CreateRead ( objTag    );
+      f.CreateRead ( objData   );
+
+      f.ReadInt    ( &nObjects );
+      nAlloc = nObjects;
+      if (nObjects>0)  {
+        object = new PXMLObject[nObjects];
+        for (i=0;i<nObjects;i++)  {
+          object[i] = NULL;
+          StreamRead ( f,object[i] );
+        }
+      }
+
+      f.ReadInt    ( &nAttributes );
+      nAttrAlloc = nAttributes;
+      if (nAttributes>0)  {
+        GetVectorMemory ( attr_name ,nAttrAlloc,0 );
+        GetVectorMemory ( attr_value,nAttrAlloc,0 );
+        for (i=0;i<nAttributes;i++)  {
+          attr_name [i] = NULL;
+          attr_value[i] = NULL;
+          f.CreateRead ( attr_name [i] );
+          f.CreateRead ( attr_value[i] );
+        }
+      }
+
+    }
+
+
+    MakeStreamFunctions(XMLObject)
+
+
+
+    PXMLObject mmCIF2XML ( mmcif::PData mmCIFData, int * rc )  {
+    PXMLObject xmlObject;
+    pstr       dataName;
+    int        k;
+      xmlObject = NULL;
+      if (rc) *rc = -2;
+      if (mmCIFData)  {
+        dataName = mmCIFData->GetDataName();
+        if (dataName)  {
+          if (dataName[0])
+            xmlObject = new XMLObject ( dataName );
+        }
+        if (!xmlObject)
+          xmlObject = new XMLObject ( pstr("no_data_name") );
+        k = xmlObject->AddMMCIFData ( mmCIFData );
+        if (rc)  *rc = k;
+      }
+      return xmlObject;
+    }
+
+    PXMLObject mmCIF2XML ( cpstr XMLName, mmcif::PFile mmCIFFile,
+                           int * rc )  {
+    PXMLObject   xmlObject1,xmlObject2;
+    mmcif::PData mmCIFData;
+    int          nData,i,k,rc1;
+      xmlObject1 = new XMLObject ( XMLName );
+      if (rc) *rc = -1;
+      if (mmCIFFile)  {
+        nData = mmCIFFile->GetNofData();
+        k   = 0;
+        rc1 = 0;
+        for (i=0;(i<nData) && (rc1>=0);i++)  {
+          mmCIFData = mmCIFFile->GetCIFData ( i );
+          if (mmCIFData)  {
+            xmlObject2 = mmCIF2XML ( mmCIFData,&rc1 );
+            if (xmlObject2)  {
+              if (rc1>=0)  {
+                xmlObject1->AddObject ( xmlObject2 );
+                k += rc1;
+              } else
+                delete xmlObject2;
+            }
+          }
+        }
+        if (rc1<0)  {
+          delete xmlObject1;
+          if (rc)  *rc = -2;
+        } else if (rc)
+          *rc = k;
+      }
+      return xmlObject1;
+    }
+
+
+  }  // namespace xml
+
+}  // namespace mmdb
diff --git a/mmdb2/mmdb_xml_.h b/mmdb2/mmdb_xml_.h
new file mode 100644
index 0000000..540334c
--- /dev/null
+++ b/mmdb2/mmdb_xml_.h
@@ -0,0 +1,162 @@
+//  $Id: mmdb_xml_.h $
+//  =================================================================
+//
+//   CCP4 Coordinate Library: support of coordinate-related
+//   functionality in protein crystallography applications.
+//
+//   Copyright (C) Eugene Krissinel 2000-2013.
+//
+//    This library is free software: you can redistribute it and/or
+//    modify it under the terms of the GNU Lesser General Public
+//    License version 3, modified in accordance with the provisions
+//    of the license to address the requirements of UK law.
+//
+//    You should have received a copy of the modified GNU Lesser
+//    General Public License along with this library. If not, copies
+//    may be downloaded from http://www.ccp4.ac.uk/ccp4license.php
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU Lesser General Public License for more details.
+//
+//  =================================================================
+//
+//    06.12.13   <--  Date of Last Modification.
+//                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//  -----------------------------------------------------------------
+//
+//  **** Module  :  MMDB_XML <interface>
+//       ~~~~~~~~~
+//  **** Project :  MacroMolecular Data Base (MMDB)
+//       ~~~~~~~~~
+//  **** Classes :  mmdb::xml::XMLObject
+//       ~~~~~~~~~
+//
+//   (C) E. Krissinel 2000-2013
+//
+//  =================================================================
+//
+
+#ifndef __MMDB_XML__
+#define __MMDB_XML__
+
+#include "mmdb_mmcif_.h"
+
+namespace mmdb  {
+
+  namespace xml  {
+
+
+    //  ======================  XMLObject  ==========================
+
+    enum XML_RC  {
+      XMLRC_Ok           = 0,
+      XMLRC_NoFile       = 1,
+      XMLRC_CantOpenFile = 2,
+      XMLRC_NoTag        = 3,
+      XMLRC_BrokenTag    = 4,
+      XMLRC_UnclosedTag  = 5,
+      XMLRC_RFormatError = 6,
+      XMLRC_IFormatError = 7,
+      XMLRC_OFormatError = 8
+    };
+
+    DefineClass(XMLObject);
+    DefineStreamFunctions(XMLObject);
+
+    class XMLObject : public io::Stream  {
+
+      public :
+
+        XMLObject ();
+        XMLObject ( cpstr Tag );
+        XMLObject ( cpstr Tag, cpstr Data );
+        XMLObject ( cpstr Tag, realtype V, int length=11 );
+        XMLObject ( cpstr Tag, int     iV, int length=0  );
+        XMLObject ( cpstr Tag, bool    bV );
+        XMLObject ( cpstr Tag, PXMLObject XMLObject );
+        XMLObject ( io::RPStream Object );
+        ~XMLObject();
+
+        void  SetTag       ( cpstr Tag                             );
+        void  AddAttribute ( cpstr name, cpstr      value          );
+        void  AddAttribute ( cpstr name, const int  iV             );
+        void  AddAttribute ( cpstr name, const bool bV             );
+        void  SetData      ( cpstr Data                            );
+        void  AddData      ( cpstr Data                            );
+        void  SetData      ( const realtype V, const int length=11 );
+        void  SetData      ( const int     iV, const int length=0  );
+        void  SetData      ( const bool    bV                      );
+
+        int AddMMCIFCategory ( mmcif::PCategory mmCIFCat    );
+        int AddMMCIFStruct   ( mmcif::PStruct   mmCIFStruct );
+        int AddMMCIFLoop     ( mmcif::PLoop     mmCIFLoop   );
+        int AddMMCIFData     ( mmcif::PData     mmCIFData   );
+
+        inline pstr GetTag()  { return objTag; }
+
+        //   Here and below the functions allow for "tag1>tag2>tag3>..."
+        // as a composite multi-level tag, e.g. the above may stand for
+        // <tag1><tag2><tag3>data</tag3></tag2></tag1>. NULL tag
+        // corresponds to "this" object.
+        //   objNo counts same-tag objects of the *highest* level used
+        // (e.g. level tag3 for composite tag  tag1>tag2>tag3 ).
+        //   GetData ( pstr& ... ) only copies a pointer to data.
+        pstr   GetData ( cpstr Tag=NULL, int objNo=1 );
+        XML_RC GetData ( pstr   & Data, cpstr Tag=NULL, int objNo=1 );
+        XML_RC GetData ( realtype &  V, cpstr Tag=NULL, int objNo=1 );
+        XML_RC GetData ( int      & iV, cpstr Tag=NULL, int objNo=1 );
+        XML_RC GetData ( bool     & bV, cpstr Tag=NULL, int objNo=1 );
+
+        PXMLObject GetObject     ( cpstr Tag, int objNo=1 );
+        PXMLObject GetFirstObject();
+        PXMLObject GetLastObject ();
+        inline int GetNumberOfObjects() { return nObjects; }
+        PXMLObject GetObject     ( int objectNo );  // 0,1,...
+
+        inline PXMLObject GetParent() { return parent; }
+
+        void   AddObject    ( PXMLObject XMLObject, int lenInc=10 );
+        void   InsertObject ( PXMLObject XMLObject, int pos,
+                              int lenInc=10 );
+
+        XML_RC WriteObject ( cpstr FName, int pos=0, int ident=2  );
+        void   WriteObject ( io::RFile f, int pos=0, int ident=2  );
+        XML_RC ReadObject  ( cpstr FName );
+        XML_RC ReadObject  ( io::RFile f, pstr S, int & pos, int slen );
+
+        virtual void Copy ( PXMLObject xmlObject );
+
+        void  write ( io::RFile f );
+        void  read  ( io::RFile f );
+
+      protected:
+        PXMLObject  parent;
+        pstr        objTag;
+        pstr        objData;
+        int         nObjects,nAlloc;
+        PPXMLObject object;
+        int         nAttributes,nAttrAlloc;
+        psvector    attr_name,attr_value;
+
+        void         InitXMLObject();
+        virtual void FreeMemory   ();
+
+        inline void SetParent ( PXMLObject p ) { parent = p; }
+
+    };
+
+
+    extern PXMLObject mmCIF2XML ( mmcif::PData mmCIFData,
+                                  int * rc=NULL );
+    extern PXMLObject mmCIF2XML ( cpstr XMLName, mmcif::PFile mmCIFFile,
+                                  int * rc=NULL );
+
+  }  // namespace xml
+
+}  // namespace mmdb
+
+#endif
+
+

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



More information about the debian-science-commits mailing list