Index: trunk/doc/pslib/psLibSDRS.tex
===================================================================
--- trunk/doc/pslib/psLibSDRS.tex	(revision 3537)
+++ trunk/doc/pslib/psLibSDRS.tex	(revision 3564)
@@ -1,3 +1,3 @@
-%%% $Id: psLibSDRS.tex,v 1.191 2005-03-29 03:42:21 price Exp $
+%%% $Id: psLibSDRS.tex,v 1.192 2005-03-30 21:14:48 eugene Exp $
 \documentclass[panstarrs,spec]{panstarrs}
 
@@ -11,7 +11,8 @@
 \project{Pan-STARRS Image Processing Pipeline}
 \organization{Institute for Astronomy}
-\version{12}
+\version{13}
 \docnumber{PSDC-430-007}
 
+% \setcounter{tocdepth}{5} % lowest level to be included in toc
 \setlength{\topsep}{-2pt}
   
@@ -137,7 +138,6 @@
 \href{heasarc.gsfc.nasa.gov/docs/software/fitsio}{\tt heasarc.gsfc.nasa.gov/docs/software/fitsio}
 
-\item \tbd{SLALIB support is likely to be dropped} Many of the
-astronomy routines will wrap the StarLink Positional Astronomy
-libraries (SLALib):
+\item the StarLink Positional Astronomy libraries (SLALib) are a
+  useful reference:
 
 \href{star-www.rl.ac.uk/star/docs/sun67.htx/sun67.html}{\tt
@@ -183,4 +183,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+\pagebreak 
 \section{System Utilities}
 
@@ -1193,4 +1194,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+\pagebreak 
 \section{Basic Data Types and Collections}
 
@@ -1894,4 +1896,5 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+\pagebreak 
 \section{Data manipulation}
 
@@ -3028,4 +3031,86 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+\subsection{Image Pixel Lists}
+
+Usually an image mask is the best way to carry information about what
+pixels mean what.  However, in the case where the number of pixels in
+which we are interested is limited, it is more efficient to simply
+carry a list of pixels.  An example of this is in the image
+combination code, where we want to perform an operation on a
+relatively small fraction of pixels, and it is inefficient to go
+through an entire mask image checking each pixel.
+
+\begin{verbatim}
+typedef struct {
+    psVector *x;			// x coordinate
+    psVector *y;			// y coordinate
+} psPixels;
+\end{verbatim}
+
+Of course, the size of each of the vectors should match.  In the event
+that they do not match, any function which detects the problem shall
+generate a warning and use the size of the shorter of the vectors as
+the size.  The order in which the pixels are kept is not considered
+important.
+
+\begin{verbatim}
+psImage *psPixelsToMask(psImage *out, const psPixels *pixels, const psRegion *region, unsigned int maskVal);
+psPixels *psMaskToPixels(psPixels *out, const psImage *mask, unsigned int maskVal);
+\end{verbatim}
+
+\code{psPixelsToMask} shall return an image of type U8 with the
+\code{pixels} lying within the specified \code{region} set to the
+\code{maskVal}.  The \code{out} image shall be modified if supplied,
+or allocated and returned if \code{NULL}.  The size of the output
+image shall be \code{region->x1 - region->x0} by \code{region->y1 -
+region->y0}, with \code{out->x0 = region->x0} and \code{out->y0 =
+region->y0}.  In the event that either of \code{pixels} or
+\code{region} are \code{NULL}, the function shall generate an error
+and return \code{NULL}.
+
+\code{psMaskToPixels} shall return a \code{psPixels} consisting of the
+coordinates in the \code{mask} that match the \code{maskVal}.  The
+\code{out} pixel list shall be modified if supplied, or allocated and
+returned if \code{NULL}.  In hte event that \code{mask} is
+\code{NULL}, the function shall generate an error and return
+\code{NULL}.
+
+\begin{verbatim}
+psPixels *psPixelsConcatenate(psPixels *out, const psPixels *pixels);
+\end{verbatim}
+
+\code{psPixelsConcatenate} shall concatenate \code{pixels} onto
+\code{out}.  In the event that \code{out} is \code{NULL}, a new
+\code{psPixels} shall be allocated, and the contents of \code{pixels}
+simply copied in.  If \code{pixels} is \code{NULL}, the function shall
+generate an error and return \code{NULL}.  The function shall take
+care to ensure that there are no duplicate pixels in \code{out} (since
+the order in which the pixels are stored is not important, the values
+may be sorted, allowing the use of a faster algorithm than a linear
+scan).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Image Regions}
+
+In many places, we need to refer to a rectangular area.  We define a
+structure to represent a rectangle:
+\begin{verbatim}
+typedef struct {
+  float x0;
+  float x1;
+  float y0;
+  float y1;
+} psRegion;
+psRegion *psRegionAlloc (float x0, float x1, float y0, float y1);
+\end{verbatim}
+
+\begin{verbatim}
+psRegion *psRegionFromString (char *region);
+\end{verbatim}
+This function converts the IRAF description of a region in the form
+\code{[x0:x1,y0:y1]}, used for header entries such as \code{BIASSEC},
+into the corresponding \code{psRegion} structure.
+
 \subsection{Vector and Image Arithmetic}
 \label{sec:arithmetic}
@@ -3443,4 +3528,1002 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+\pagebreak 
+\section{Rich Data Structures and I/O}
+
+\subsection{Metadata}
+\label{sec:metadata}
+
+\subsubsection{Conceptual Overview}
+
+Within PSLib, we provide a data structure to carry metadata and
+mechanisms to manipulate the metadata.  Metadata is a general concept
+that requires some discussion.  In any data analysis task, the
+ensemble of all possible data may be divided into two or three
+classes: there is the specific data of interest, there is data which
+is related or critical but not the primary data of interest, and there
+is all of the other data which may or may not be interesting.  For
+example, consider a simple 2D image obtained of a galaxy from a CCD
+camera on a telescope.  If you want to study the galaxy, the specific
+data of interest is the collection of pixels.  There are a variety of
+other pieces of data which are closely related and crucial to
+understanding the data in those pixels, such as the dimensions of the
+image, the coordinate system, the time of the image, the exposure
+time, and so forth.  Other data may be known which may be less
+critical to understanding the image, but which may be interesting or
+desired at a later date.  For example, the observer who took the
+image, the filter manufacturer, the humidity at the telescope, etc.
+
+Formally, all of the related data which describe the principal data of
+interest are metadata.  Note that which piece is the metadata and
+which is the data may depend on the context.  If you are examining the
+pixels in an image, the coordinate and flux of an object may be part
+of the metadata.  However, if you are analyzing a collection of
+objects extracted from an image, you may consider then pixel data
+simply part of the metadata associated with the list of objects.  
+
+There are various ways to handle metadata vs data within a programming
+environment.  In C, it is convenient to use structures to group
+associated data together.  One possibility is to define the metadata
+as part of the associated data structure.  For example, the image data
+structure would have elements for all possible associated measurement.
+This approach is both cumbersome (because of the large number metadata
+types), impractical (because the full range of necessary metadata is
+difficult to know in advance) and inflexible (because any change in
+the collection of metadata requires addition of new structure elements
+and recompilation).  
+
+An alternative is to place the metadata in a generic container and use
+lookup mechanisms to extract the appropriate metadata when needed.  An
+example of this is would be a text-based FITS header for an image read
+into a flat text buffer.  In this implementation, metadata lookup
+functions could return the current value of, for example, NAXIS1 (the
+number of columns of the image) by scanning through the header buffer.
+This method has the benefits of flexibility and simplicity of
+programming interface, but it has the disadvantage that all metadata
+is accessed though this lookup mechanism.  This may make the code less
+readable and it may slow down the access.  
+
+PSLib implements an intermediate solution to this problem.  We specify
+a flexible, generic metadata container and access methods.  Data types
+which require association with a general collection of metadata should
+include an entry of this metadata type.  However, a subset of metadata
+concepts which are basic and frequently required may be placed in the
+coded structure elements.  This approach allows the code to refer to
+the basic metadata concepts as part of the data structure (ie,
+\code{image.nx}), but also allows us to provide access to any
+arbitrary metadata which may be generated.  As a practical matter, the
+choice of which entries are only in the metadata and which are part of
+the explicit structure elements is rather subjective.  Any data
+elements which are frequently used should be put in the structure;
+those which are only infrequently needed should be left in the generic
+metadata.
+
+There are some points of caution which must be noted.  Any
+manipulation of the data should be reflected in the metadata where
+appropriate.  This is always an issue of concern.  For example,
+consider an image of dimensions \code{nx, ny}.  If a function extracts
+a subraster, it must change the values of \code{nx, ny} to match the
+new dimensions.  What should it do to the corresponding metadata?
+Clearly, it should change the corresponding value which defines
+\code{nX, nY}.  However, it is not quite so simple: there may be other
+metadata values which depend on those values.  These must also be
+changed appropriately.  What if the metadata element points to a
+copy of the metadata which may be shared by other representations of
+the image?  These must be treated differently because the change would
+invalidate those other references.  Care must be taken, therefore,
+when writing functions which operate on the data to consider all of
+the relevant metadata entries which must also be updated. 
+
+A related issue is the definition of metadata names.  Entries in a
+structure have the advantage of being hardwired: every instance of
+that structure will have the same name for the same entry.  This is
+not necessarily the case with a more flexible metadata container.  The
+image exposure time is a notorious example in astronomy.  Different
+observatories use different header keywords (ie, metadata names) for
+the same concept of the exposure time (\code{EXPTIME},
+\code{EXPOSURE}, \code{OPENTIME}, \code{INTTIME}, etc).  Any system
+which operates on these metadata needs to address the issue of
+identifying these names.  This issue seems like an argument for
+hardwiring metadata in the structure, but in fact it does not present
+such a strong case.  If the metadata are hardwired, some function will
+still have to know how to interpret the various names to populate the
+structure.  The concept can still be localized with generic metadata
+containers by including abstract metadata names within the code which
+are tied to the various implementations-specific metadata names.
+
+\subsubsection{Metadata Representation}
+
+\begin{figure}
+\psfig{file=Metadata,width=6.5in}
+\caption{Metadata Structures\label{fig:metadata}}
+\end{figure}
+
+This section addresses the question of how \PS{} metadata should be
+represented in memory, not how it should be represented on disk.
+
+We define an item of metadata with the following structure:
+\filbreak
+\begin{verbatim}
+typedef struct {
+    int id;                             ///< unique ID for this item
+    char *name;                         ///< Name of item
+    psMetadataType type;                ///< type of this item
+    psElemType ptype;                   ///< primitive data type
+    const union {
+        psS32 S32;                      ///< integer data
+        psF32 F32;                      ///< floating-point data
+        psF64 F64;                      ///< double-precision data
+        void *V;                        ///< other type
+        psList *list;                   ///< psList entry
+        psMetadata *md;                 ///< psMetadata entry
+    } data;                             ///< value of metadata
+    char *comment;                      ///< optional comment ("", not NULL)
+} psMetadataItem;
+\end{verbatim}
+
+The \code{id} is a unique identifier for this item of metadata;
+experience shows that such tags are useful.  The entry \code{name}
+specifies the name of the metadata item.  The value of the metadata is
+given by the union \code{data}, and may be of type \code{psS32},
+\code{psF32}, \code{psF64}, or an arbitrary rich structure pointed at
+by the \code{void} pointer \code{V}.  A character string comment
+associated with this metadata item may be stored in the element
+\code{comment}. The \code{type} entry specifies how to interpret the
+type of the data being represented, given by the enumerated type
+\code{psMetadataType}:
+%
+\filbreak
+\begin{verbatim}
+typedef enum {                          ///< type of item.data is:
+    PS_META_PRIMITIVE,                  ///< primitive type: use item.ptype
+    PS_META_LIST,                       ///< psList; use item.data.list (used for non-unique data)
+    PS_META_META,                       ///< psMetadata: use item.data.list
+    PS_META_STR,                        ///< string (item.data.V)
+    PS_META_MATH,                       ///< psScalar, psVector, psImage (item.data.V)
+    PS_META_JPEG,                       ///< JPEG (item.data)
+    PS_META_PNG,                        ///< PNG (item.data)
+    PS_META_ASTROM,                     ///< astrometric coefficients (item.data)
+    PS_META_UNKNOWN,                    ///< other (item.data)
+    PS_META_NTYPE                       ///< Number of types; must be last
+} psMetadataType;
+\end{verbatim}
+If the data is a PSLib primitive data value, the primitive data type
+is given by the value of \code{ptype}.
+
+A collection of metadata is represented by the \code{psMetadata} structure:
+\begin{verbatim}
+typedef struct {
+    psList *list;                       ///< list of psMetadataItem
+    psHash *table;                      ///< hash table of the same metadata
+} psMetadata;
+\end{verbatim}
+The type \code{psMetadata} is a container class for metadata. Note
+that there are in fact \emph{two} representations of the metadata
+(each \code{psMetadataItem} appears on both).  The first
+representation employs a doubly-linked list that allows the order of
+the metadata to be preserved (e.g., if FITS headers are read in a
+particular order, they should be written in the same order).  The
+second representation employs a hash table which allows fast look-up
+given a specific metadata keyword.
+
+Certain metadata names (such as the FITS keywords \code{COMMENT} and
+\code{HISTORY} in a FITS header) may be repeated with different
+values.  In such a case, the \code{psMetadata.list} structure contains
+the entries in their original sequence with duplicate keys.  The
+\code{psMetadata.hash} entries, which are required to have unique
+keys, would have a single entry with the keyword of the repeated key,
+with the value of \code{psMetadataType} set to \code{PS_META_LIST},
+and the \code{psMetadataItem.data} element pointing to a \code{psList}
+containing the actual entries.  If \code{psMetadataItemAlloc} is
+called with the type set to \code{PS_META_LIST}, such a repeated key
+is created.  If the data value passed to \code{psMetadataItemAlloc}
+(the quantity in ellipsis) is \code{NULL}, then an empty
+\code{psMetadataItem} with the given keyword is created to hold future
+entries of that keyword.
+
+The \code{psMetadataAdd} routine is required to check that all
+metadata names are unique unless the type is already qualified as
+\code{PS_META_LIST}; in this case the data are added to the
+corresponding \code{psMetadataItem.data} list.
+
+\subsubsection{Metadata APIs}
+
+The allocator for \code{psMetadataItem} returns a full
+\code{psMetadataItem} ready for insertion into the \code{psMetadata}.
+The \code{name} entry specifies the name to use for this metadata
+item, and may include \code{sprintf}-type formating codes.  The
+\code{comment} entry is a fixed string which is used for the comment
+associated with this metadata item.  The metadata data and the
+arguments to the \code{name} formatting codes are passed, in that
+order (metadata pointer first), to \code{psMetadataItemAlloc} as
+arguments following the comment string.  The data must be a pointer
+for any data types which are stored in the element \code{data.void},
+while other data types are passed as numeric values.  The argument
+list must be interpreted appropriately by the \code{va_list} operators
+in the function.
+\begin{verbatim}
+psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...);
+psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list list);
+\end{verbatim}
+
+The constructor for the collection of metadata, \code{psMetadata},
+simply returns an empty metadata container (employing the constructors
+for the doubly-linked list and hash table).  The destructor needs to
+free each of the \code{psMetadataItem}s using \code{psMetadataItemFree}.
+\begin{verbatim}
+psMetadata *psMetadataAlloc(void);
+\end{verbatim}
+
+Items may be added to the metadata in one of two ways --- firstly, an
+item may be added by appending a \code{psMetadataItem} which has
+already been created; and secondly by directly providing the data to
+be appended.  In both cases, the return value defines the success
+(\code{true}) or failure of the operation.  The second function,
+\code{psMetadataAdd} takes a pointer or value which is interpreted by
+the function using variadic argument interpretation.  The third
+version is the \code{va_list} version of the second function.  All
+three functions take a parameter, \code{location}, which specifies
+where in the list to place the element, following the conventions for
+the \code{psList}.  The entry \code{mode} for \code{psMetadataAddItem}
+is a bit mask constructed by OR-ing the allowed option flags (eg,
+\code{PS_META_REPLACE}) which specifies minor variations on the
+behavior.  The \code{format} entry, which specifies both the metadata
+type and the optional flags, is constructed by bit-wise OR-ing the
+appropriate \code{psMetadataType} and allowed option option flags.
+Care should be taken not to leak memory when appending an item for
+which the key already exists in the metadata (and is not
+\code{PS_META_LIST}).
+%
+\begin{verbatim}
+bool psMetadataAddItem(psMetadata *md, psMetadataItem *item, int location, int mode);
+bool psMetadataAdd(psMetadata *md, int location, const char *name, int format, const char *comment, ...);
+bool psMetadataAddV(psMetadata *md, int location, const char *name, int format, const char *comment,
+                    va_list list);
+\end{verbatim}
+
+The functions above take option flags which modify the behavior when
+metadata items are added to the metadata list.  These flags must be
+bit-exclusive of those used above for the \code{psMetadataTypes}.  The
+flags have the following meanings: 
+
+\code{PS_META_DEFAULT}: This is the zero bit mask, to allow the
+default behavior for \code{psMetadataAddItem} above.  If this is OR-ed
+with a \code{psMetadataType}, the result is as if no OR-ing took
+place.
+
+\code{PS_META_REPLACE}: If the given metadata item exists in the
+metadata list, and is not of type \code{PS_META_LIST} or
+\code{PS_META_META} (ie, not a container type), then this entry is
+allowed to replace the existing entry.  If this mode bit is not set, a
+duplicate (non-container-type) entry is an error.
+
+\begin{verbatim}
+typedef enum {                          ///< option flags for psMetadata functions
+    PS_META_DEFAULT,                    ///< default behavior (0x0000) for use in mode above
+    PS_META_REPLACE,                    ///< allow entry to be replaced
+} psMetadataFlags;
+\end{verbatim}
+
+An example of code to use these metadata APIs to generate the
+structure seen in Figure~\ref{fig:metadata} is given below.
+
+\begin{verbatim}
+md = psMetadataAlloc();
+
+psMetadataAdd(md, PS_LIST_TAIL, "SIMPLE",   PS_META_BOOL, "basic fits",            TRUE);
+psMetadataAdd(md, PS_LIST_TAIL, "BLANK",    PS_META_S32,  "invalid pixel data",    -32768);
+psMetadataAdd(md, PS_LIST_TAIL, "DATE-OBS", PS_META_STR,  "observing date UT", "   2004-6-16");
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_LIST, "head of comment block", NULL);
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "DATA");
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "PARAMS"); 
+psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32,  "exposure time (sec)",   1.05);
+psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "FOO");
+
+cell = psMetadataAlloc();
+psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD00");
+psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-00");
+psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.00");
+psMetadataAdd(md,   PS_LIST_TAIL, "CELL.00",  PS_META_META, "",                    cell);
+
+cell = psMetadataAlloc();
+psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD01");
+psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-01");
+psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.01");
+psMetadataAdd(md,   PS_LIST_TAIL, "CELL.01",  PS_META_META, "",                    cell);
+\end{verbatim}
+
+The following code shows how to use the APIs to replace one of these values:
+\begin{verbatim}
+psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32 | PS_REPLACE,  "new exposure time (sec)",   2.05);
+\end{verbatim}
+
+Items may be removed from the metadata by specifying a key or a
+location in the list.  If the value of \code{name} is \code{NULL}, the
+value of \code{location} is used.  If the value of \code{name} is not
+\code{NULL}, then \code{location} must be set to
+\code{PS_LIST_UNKNOWN}.  If the key matches a metadata item, the item
+is removed from the metadata and \code{true} is returned; otherwise,
+\code{false} is returned.  If the key is not unique, then \emph{all}
+items corresponding to the key are removed, and \code{true} is
+returned.
+%
+\begin{verbatim}
+bool psMetadataRemove(psMetadata *md, int location, const char *key);
+\end{verbatim}
+
+Items may be found within the metadata by providing a key.  In the
+event that the key is non-unique, the first item is returned.
+\begin{verbatim}
+psMetadataItem *psMetadataLookup(const psMetadata *md, const char *key);
+\end{verbatim}
+
+Several utility functions are provided for simple cases.  These
+functions perform the effort of casting the data to the appropriate
+type.  The numerical functions shall return 0.0 if their key is not
+found.  If the pointer value of \code{status} is not \code{NULL}, it
+is set to reflect the success or failure of the lookup.
+\begin{verbatim}
+void *psMetadataLookupPtr(bool *status, const psMetadata *md, const char *key);
+psS32 psMetadataLookupS32(bool *status, const psMetadata *md, const char *key);
+psF64 psMetadataLookupF64(bool *status, const psMetadata *md, const char *key);
+\end{verbatim}
+
+Items may be retrieved from the metadata by their entry position.  The
+value of which specifies the desired entry in the fashion of
+\code{psList}.
+\begin{verbatim}
+psMetadataItem *psMetadataGet(const psMetadata *md, int location);
+\end{verbatim}
+
+The metadata list component may be iterated over by using a
+\code{psListIterator} in a fashion equivalent to the usage for
+\code{psList}.  The iterator may be set to a location in the
+\code{psMetadata} list, and the user may get the previous or next item
+in the list relative to that location.  \code{psMetadataGetNext} has
+the ability to match the key using a POSIX regex, e.g., if the user
+only wants to iterate through \code{IPP.machines.sky} and doesn't want
+to bother with \code{IPP.machines.detector}.  The iterator should
+iterate over every item in the metadata list, even those that are
+contained in a \code{PS_META_LIST}.  The value \code{iterator}
+specifies the iterator to be used.  In setting the iterator, the
+position of the iterator is defined by \code{location}, which follows
+the conventions of the \code{psList} iterators.
+\begin{verbatim}
+psListIterator *psMetadataIteratorAlloc(psMetadata *md, int location, bool mutable);
+bool psMetadataIteratorSet(psListIterator *iterator, int location);
+psMetadataItem *psMetadataGetAndIncrement(psListIterator *iterator, const char *regex);
+psMetadataItem *psMetadataGetAndDecrement(psListIterator *iterator, const char *regex);
+\end{verbatim}
+
+Metadata items may be printed to an open file descriptor based on a
+provided format.  The format string is an sprintf format statement
+with exactly one \% formatting command.  If the metadata item type is
+a numeric type, this formatting command must also be numeric, and type
+conversion performed to the value to match the format type.  If the
+metadata item type is a string, the formatting command must also be
+for a string (\%s type of command).  If the metadata type is any other
+data type, printing is not allowed.
+\begin{verbatim}
+bool psMetadataItemPrint(FILE *fd, const char *format, const psMetadataItem *md);
+\end{verbatim}
+
+\subsubsection{Configuration files}
+\label{sec:configspec}
+
+It will be necessary for the \PS{} system, in order to load
+pre-defined settings, to parse a configuration file into a
+\code{psMetadata} structure.  This shall be performed by the
+function \code{psMetadataParseConfig}, as described below.
+
+\begin{verbatim}
+psMetadata *psMetadataParseConfig(psMetadata *md, int *nFail, const char *filename, bool overwrite);
+\end{verbatim}
+
+Given a metadata container, \code{md}, and the name of a configuration
+file, \code{filename}, \code{psMetadataParseConfig} shall parse the
+configuration file, placing the contained key/type/value/comment quads
+into the metadata, and returning a pointer to the metadata structure.
+The number of lines that failed to parse is returned in \code{nFail}.
+Multiple specifications of a key that haven't been declared (see
+below) are overwritten if and only if \code{overwrite} is \code{true}.
+If the metadata container is \code{NULL}, it shall be allocated.  
+
+On error, the function shall return \code{NULL}.
+
+The configuration file shall consist of plain text with
+key/type/value/comment quads on separate lines.  Blank lines,
+including those consisting solely of whitespace (both spaces and
+tabs), shall be ignored, as shall lines that commence with the comment
+character (a hash mark, \code{#}), either immediately at the start of
+the line, or preceded by whitespace.  The key/type/value/comment quads
+shall all lie on a single line, separated by whitespace.
+
+The key shall be first, possibly preceded on the line by whitespace
+which should not form part of the key.
+
+Next, to assist the casting of the value, shall be a string
+identifying the type of the value, which shall correspond to one of
+the simple types supported in \code{psMetadata}:
+\code{STRING,BOOL,S32,F32,F64}; \code{STR} may be used to abbreviate
+\code{STRING}.
+
+\tbd{May, in the future, require more types, including U8,S16,C64,
+which will also necessitate updating the definition of psMetadata.}
+
+The value shall follow the type: strings may consist of multiple
+words, and shall have all leading and trailing whitespace removed;
+booleans shall simply be either \code{T} or \code{F}.
+
+Following the value may be an optional comment, preceded by a comment
+character (a hash mark, \code{#}), which in the case of a string
+value, serves to mark the end of the value, and for other types serves
+to identify the comment to the reader.  Only one comment character may
+be present on any single line (i.e., neither strings nor comments are
+permitted to contain the comment character).  The comment may consist
+of multiple words, and shall have leading and trailing whitespace
+removed.
+
+One wrinkle is the specification of vectors.  Keys for which the value
+is to be parsed as a vector shall be preceded immediately by a
+``vector symbol'', which we choose to be the ``at'' sign, \code{@}.
+In this case, the type shall be interpreted as the type for the
+vector, which may be any of the signed or unsigned integer or floating
+point types (\code{U8,U16,U32,U64,S8,S16,S32,S32,S64,F32,F64}) but not
+the complex floating point types; and the value shall consist of
+multiple numbers, separated either by a comma or whitespace.  These
+values shall populate a \code{psVector} of the appropriate type in the
+order in which they appear in the configuration file.
+
+\tbd{May add complex types, likely to be specified with values such as
+  1.23+4.56i in the future.}
+
+An additional hurdle is the specification of keys that may be
+non-unique (such as the \code{COMMENT} keyword in a FITS header).
+These keys shall be specified in the configuration file as non-unique
+by specifying the key at the start of the line (possibly preceded by
+whitespace) and specifying the type as a ``multiple symbol'', which we
+choose to be an asterisk, \code{*}.  No other data may be provided on
+this line, though a comment, preceeded by the comment marker, is
+valid.  A warning shall be produced when a key which has not been
+specified to be non-unique is repeated; in this case, the former value
+shall be overwritten if \code{overwrite} is \code{true}, otherwise the
+line shall be ignored and counted as one that could not be parsed.
+
+If a line does not conform to the rules laid out here, a warning shall
+be generated, it shall be ignored and counted as a line that could not
+be parsed.  The total number of lines that were not able to be parsed
+(including those that were ignored because \code{overwrite} is
+\code{false}, and any other parsing problems, but not including blank
+lines and comment lines) shall be returned by the function in the
+argument \code{nFail}.
+
+Here are some examples of lines of a valid configuration file:
+\filbreak
+\begin{verbatim}
+Double     F64     1.23456789      # This is a comment
+Float    F32 0.98765 # This is a comment too
+String  STR This is the string that forms the value #comment
+
+ # This is a comment line and is to be ignored
+boolean     BOOL    T # The value of `boolean' is `true'
+
+@primes U8  2,3 5 7,11,13 17 #   These are prime numbers
+
+comment MULTI # The rest of this line is ignored, but `comment' is set to be non-unique
+comment STR This
+comment STR     is
+comment STR       a
+comment STR        non-unique
+comment STR                  key
+Float F64 1.23456 # This generates a warning, and, if `overwrite' is `false', is ignored
+\end{verbatim}
+
+Of course, a real configuration file should look much nicer to humans
+than the above example, but PSLib must be able to parse such ugly
+files.
+
+We extend \code{psMetadataParseConfig} to allow a modest tree
+structure by defining a reserved keyword \code{TYPE}.  Any line in the
+config file which starts with the word \code{TYPE} shall be
+interpretted as defining a new valid type.  The defined type name
+follows the word \code{TYPE}, and is in turn followed by an arbitrary
+number of words.  These words are to be interpreted as the names of an
+embedded \code{psMetadata} entry, where the values are given on any
+line which (following the \code{TYPE} definition) employs the new type
+name.  For example, a new type may be defined as:
+\begin{verbatim}
+TYPE      CELL   EXTNAME   BIASSEC  CHIP
+CELL.00   CELL   CCD00     BSEC-00  CHIP.00
+CELL.01   CELL   CCD01     BSEC-01  CHIP.00
+\end{verbatim}
+
+When \code{psMetadataParseConfig} encounters the \code{TYPE} line, it
+should construct a \code{psMetadata} container and fill it with
+\code{psMetadataItems} having the names \code{EXTNAME, BIASSEC, CHIP},
+with type \code{PS_META_STR}, but data allocated.  When it next
+encounters an entry of type \code{CELL}, it should then use the given
+name (e.g., \code{CELL.00}) for the \code{psMetadataItem}, and copy
+the \code{psMetadata} data onto the \code{psMetadataItem.data.md}
+entry, filling in the values from the rest of the line (\code{CCD00,
+BSEC-00, CHIP.00}).  This hierarchical structure is illustrated in
+Figure~\ref{fig:metadata}.
+
+We further extend \code{psMetadataParseConfig} to allow the definition
+of a \code{psMetadata} entry using a sequence of successive lines to
+define the values of the \code{psMetadataItem} entries.  The initial
+line defines the new \code{psMetadata} entry and its name.  The
+following lines have the same format as the other metadata config file
+entries.  The sequence is terminated with a line with a single word
+\code{END}.  For example, a metadata entry may be defined as:
+\begin{verbatim}
+CELL      METADATA
+ EXTNAME   STR   CCD00
+ BIASSEC   STR   BSEC-00
+ CHIP      STR   CHIP.00
+ NCELL     S32   24
+END
+\end{verbatim}
+
+A series of test inputs is contained in
+\S\ref{sec:configtest}.
+
+\subsection{XML Functions}
+
+Within Pan-STARRS, we will use XML documents as a transport mechanism
+to carry data between programs and between IPP and other subsystems.
+Configuration information may be stored as well as XML documents, in
+addition to the text format discussed in the discussion on Metadata.
+XML is an extremely variable document format, and it is not currently
+the intention of PSLib to provide a complete PSLib version of XML
+operations.  Rather, a limited number of operations are defined to
+convert specific data structures to an appropriate XML document.  To
+maximize the simplicity of the XML APIs, we will use the convention
+that a single XML document to be parsed by PSLib shall contain only a
+single data structure.  Each of the XML APIs therefore take as input a
+reference to a complete XML document and return a PSLib data
+structure, or take a PSLib data structure and return a complete XML
+document.
+
+We start by defining a PSLib wrapper type which is a pointer to an XML
+document in memory.  We wrap the \code{libxml2} version of an XML
+document pointer for now:
+\begin{verbatim}
+typedef xmlDocPtr psXMLDoc;
+void psXMLDocFree(psXMLDoc *doc);
+\end{verbatim}
+
+The next pair of functions convert a \code{psMetadata} data structure
+to a complete \code{psXMLDoc} (in memory) and vice versa:
+\begin{verbatim}
+psXMLDoc *psMetadataToXMLDoc(const psMetadata *metadata);
+psMetadata *psXMLDocToMetadata(const psXMLDoc *doc);
+\end{verbatim}
+
+The next pair of functions loads the data in a named file into a
+complete \code{psXMLDoc} (in memory) and write out the \code{psXMLDoc}
+to a named file:
+\begin{verbatim}
+psXMLDoc *psXMLParseFile(const char *filename);
+int psXMLDocToFile(const psXMLDoc *doc, const char *filename);
+\end{verbatim}
+
+The next pair of functions accepts a block of memory and parses it
+into a complete \code{psXMLDoc} (also in memory), and vice versa:
+\begin{verbatim}
+psXMLDoc *psXMLParseMemory(const char *buffer, const int size);
+int psXMLDocToMemory(const psXMLDoc *doc, char *buffer);
+\end{verbatim}
+
+The next pair of functions read from and write to a file descriptor.
+The first converts the imcoming data to a complete \code{psXMLDoc}
+(also in memory), the second writes the \code{psXMLDoc} to the file
+descriptor:
+\begin{verbatim}
+psXMLDoc *psXMLParseFD(int fd);
+int psXMLDocToFD(const psXMLDoc *doc, int fd);
+\end{verbatim}
+
+\subsection{Database Functions}
+
+Many of the applications that PSLib will be used for will require
+access to a simple relational database.  PSLib includes generic
+database-independent interface mechanisms as part of its API set.  The
+most important aspect of PSLib's database support is to abstract as
+much database specific complexity as is feasible.  As almost all RDBMS
+provide at least a simple transactional model, commit and rollback
+support should be provided.
+
+Currently, only support for MySQL 4.1.x is required but other backends
+may be added as options in the future.  As a particular example which
+has implications for the database interaction model, support for
+SQLite may be required in the future.  Currently, the choice of
+backend database interface may be made as a compile option.  Details
+of the specified APIs in the discussion below refer to the relevant
+MySQL functions.
+
+Database errors must be trapped and placed onto the psError stack.
+The complete error message should be retrieved with the database's
+error function.
+
+\subsubsection{Managing the Database Connection}
+
+We specify a database handle which carries the information about the
+database connection:
+
+\begin{verbatim}
+    typedef struct {
+        MYSQL *mysql;
+    } psDB;
+\end{verbatim}
+
+The following collection of functions provides basic database functionality:
+
+\begin{verbatim}
+    // wraps mysql_init() & mysql_real_connect()
+    psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname);
+
+    // wraps mysql_close()
+    void psDBCleanup(psDB *dbh);
+
+    // wraps mysql_create_db()
+    bool psDBCreate(psDB *dbh, const char *dbname);
+
+    // wraps mysql_select_db()
+    bool psDBChange(psDB *dbh, const char *dbname);
+
+    // wraps mysql_drop_db()
+    bool psDBDrop(psDB *dbh, const char *dbname);
+\end{verbatim}
+
+For MySQL support, \code{psDBInit()} wraps \code{mysql_init()} and
+\code{mysql_real_connect()} in order to initialize a psDB structure and
+establish a database connection.  A null pointer should be returned on
+failure.
+
+When implementing support for SQLite, or other DB which is purely
+file-based, the \code{host}, \code{user}, and \code{passwd} arguments
+would be ignored while \code{dbname} would specify the path to the
+SQLite db file.
+
+\subsubsection{Interacting with Database Tables}
+
+The functions in this section perform high level interactions with the
+database tables.  All of them should behave ``atomically'' with
+respect to the state of the database.  Specifically, all interactions
+with the database should be done as a part of a transaction that is
+rolled-back on failure and committed only after all queries used by
+the API have been run.  In general, this API set attempts to treat a
+database table as a 2D matrix where columns can be represented by a
+\code{psVector} and rows as a \code{psMetadata} type.  A
+\code{psMetadata} collection is also used to define the columns of a
+table and as part of the query restrictions.
+
+\begin{verbatim}
+    bool psDBCreateTable(psDB *dbh, const char *tableName, psMetadata *md);
+\end{verbatim}
+
+This function generates and executes the SQL needed to create a table
+named \code{tableName}, with the column names and datatypes as
+described in \code{md}.  Each data item in the \code{psMetadata}
+collection represents a single table field.  The name of the field is
+given by the name of the \code{psMetadataItem} and the data type is
+give by the \code{psMetadataItem.type} and \code{psMetadataItem.ptype}
+entries.  A lookup table should be used to convert from PSLib types
+into MySQL compatible SQL data types.  For example, a
+\code{PS_META_STR} would map to an SQL99 varchar.  If the value of
+\code{type} is \code{PS_META_STR} then the \code{psMetadataItem.data}
+element is set to a string with the length for the field written as a
+text string.  The value of the \code{psMetadataItem.data} element is
+unused for the \code{PS_META_PRIMITIVE} types.  Other metadata types
+beyond \code{PS_META_STR} and \code{PS_META_PRIMITIVE} are not allowed
+in a table definition metadata collection.
+
+Database indexes can be specified setting the \code{comment} field to
+``\code{Primary Key}'' or ``\code{Key}''.  Comment are otherwise
+ignored.
+
+\begin{verbatim}
+    bool psDBDropTable(psDB *dbh, const char *tableName);
+\end{verbatim}
+
+This function deletes the specified table.
+
+\begin{verbatim}
+    psArray *psDBSelectColumn(psDB *dbh, const char *tableName, const char *col, const psU64 limit);
+    psVector *psDBSelectColumnNum(psDB *dbh, const char *tableName, const char *col, psElemType pType, const psU64 limit);
+\end{verbatim}
+
+These functions generates and executes the SQL needed to select an entire
+column from a table or up to \code{limit} rows from it.  If \code{limit} is 0,
+the entire range is returned.  The database response is processed and a
+\code{psArray} of strings is returned.  The Num version of the function returns
+the data in a \code{psVector}, data cast to \code{pType}.  It returns an error
+(NULL) if the requested field is not a numerical type.
+
+\begin{verbatim}
+    psArray *psDBSelectRows(psDB *dbh, const char *tableName, psMetadata *where, const psU64 limit);
+\end{verbatim}
+
+This function returns rows from the specified table which match
+the restrictions given by \code{where}.  The restrictions are
+specified as field / value pairs.  The \code{psMetadata} collection
+where must consist of valid database fields, though the database query
+checking functions may be used to validate the fields as part of the
+query.  If \code{where} is \code{NULL}, then there are no restrictions
+on the rows selected.  The selected rows are returned as a
+\code{psArray} of \code{psMetadata} values, one per row. 
+
+\begin{verbatim}
+    bool psDBInsertOneRow(psDB *dbh, const char *tableName, psMetadata *row);
+\end{verbatim}
+
+Insert the data from \code{row} into \code{tableName}.  It should be noted in
+the API reference that if fields are specified in \code{row} that do not exist
+in \code{tablename}, the insert will fail.
+
+\begin{verbatim}
+    bool psDBInsertRows(psDB *dbh, const char *tableName, psArray *rowSet);
+\end{verbatim}
+
+Similar to \code{psDBInsertOneRow()}, this function inserts many rows at once
+and is atomic for the complete set of rows.
+
+\begin{verbatim}
+    psArray *psDBDumpRows(psDB *dbh, const char *tableName);
+\end{verbatim}
+
+Fetch all rows as an psArray of psMetadata.
+
+\begin{verbatim}
+    psMetadata *psDBDumpCols(psDB *dbh, const char *tableName);
+\end{verbatim}
+
+Fetch all columns, as either a psVector or a psArray depnding on whether or not
+the column is numeric, and return them in a psMetadata structure where
+psMetadataItem.name contains the column's name.
+
+\begin{verbatim}
+    psS64 psDBUpdateRows(psDB *dbh, const char *tableName, psMetadata *where, psMetadata *values);
+\end{verbatim}
+
+Update the columns contained in \code{values} in the row(s) that have a field
+with the value indicated by \code{where} (note that this is only allows very
+limited use of SQL99's ``where'' semantics).  The number of rows modified is
+returned.  A negative value is return to indicate an error. If there are
+multiple psMetadataItems in \code{where} then each item should be considered as
+an additional constraint.  e.g.  ``where foo = x and where bar = y''
+
+\begin{verbatim}
+    psS64 psDBDeleteRows(psDB *dbh, const char *tableName, psMetadata *where);
+\end{verbatim}
+
+Delete the rows that are matched by \code{where} using the same semantics for
+\code{where} as in psDBUpdateRow().  A negative value is returned to indicate an
+error.
+
+\subsection{FITS I/O Functions}
+
+We need a variety of I/O functions between the disk and certain of our
+PSLib data structures.  We need the ability to access FITS headers,
+images and tables (both ASCII and Binary).  We define here the FITS
+I/O functions, all of which are currently specified as wrappers to
+functions within CFITSIO.  CFITSIO provides a wide range of utilities
+which we do not feel are particularly appropriate as part of a generic
+I/O library, such as assumptions about names which change the data
+interpretation, etc.  We are defining our calls to avoid the hidden
+'features'.  The CFITSIO functions which are wrapped should in general
+be the most basic versions.
+
+\begin{verbatim}
+typedef struct {
+    fitsfile fd;
+} psFits;
+\end{verbatim}
+We begin by defining a datatype to wrap the CFITSIO \code{fitsfile}
+structure.  This is necessary to allow repeated access to the data in
+a file without multiple open commands (which are expensive).
+
+\subsubsection{FITS File Manipulations}
+
+\begin{verbatim}
+psFits *psFitsAlloc(const char *filename);
+\end{verbatim}
+
+Opens a FITS file at positions the pointer to the PHU.
+
+\begin{verbatim}
+bool psFitsMoveExtName(psFits *fits, const char *extname);
+\end{verbatim}
+
+Positions the pointer to the beginning of the specified
+\code{extname}.  If the \code{extname} does not exist, the function
+shall fail.  
+
+\begin{verbatim}
+bool psFitsMoveExtNum(psFits* fits, int extnum, bool relative);
+\end{verbatim}
+
+Moves the pointer to the beginning of the specified HDU number.  If
+\code{relative} is TRUE, \code{extnum} represents the number of HDUs
+relative to the current HDU.  The PHU is entry number 0, while the
+extended data segments start at number 1.
+
+\begin{verbatim}
+int psFitsGetExtNum(psFits* fits);
+\end{verbatim}
+
+Returns the current HDU number (i.e., file position).  
+
+\begin{verbatim}
+int psFitsGetSize(psFits* fits);
+\end{verbatim}
+
+Returns the number of HDUs in the file.
+
+\begin{verbatim}
+psFitsType psFitsGetExtType(psFits* fits);
+\end{verbatim}
+
+Gets the current HDU's type (table or image).
+
+\subsubsection{FITS Header I/O Functions}
+
+\begin{verbatim}
+psMetadata *psFitsReadHeader(psMetadata *out, const psFits *fits);
+\end{verbatim}
+Read header data into a \code{psMetadata} structure.  The data is read
+from the current HDU pointed at by the \code{psFits *fits} entry.  If
+\code{out} is \code{NULL}, a new psMetadata is created.
+
+\begin{verbatim}
+psMetadata *psFitsReadHeaderSet (psFits *fits);
+\end{verbatim}
+Load a complete set of headers from the \code{psFits} file pointer.
+This function loads the headers from all extensions into a
+\code{psMetadata} collection, each entry of which is a pointer to a
+\code{psMetadata} structure containing the header data.  The metadata
+entry names are the \code{EXTNAME} values for each header (with the
+value of \code{PHU} for the primary header unit).  At the start of the
+operation, the file pointer is rewound to the beginning of the file.
+At the end, it is positioned where it started when the function was
+called.
+
+\begin{verbatim}
+bool psFitsWriteHeader(psMetadata *output, const psFits *fits);
+\end{verbatim}
+Write metadata into the header of a FITS image file.  The header is
+written at the current HDU.
+
+\subsubsection{FITS Image I/O Functions}
+
+\begin{verbatim}
+psImage *psFitsReadImage(psImage *output, psFits *fits, psRegion region, int z);
+\end{verbatim}
+Read an image or subimage from the \code{psFits} file pointer.  This
+function is a wrapper to the CFITSIO library function.  The input
+parameters allow a full image or a subimage to be read.  The region to
+be read is specified by \code{region}.  A negative value for either of
+\code{region.x1} or \code{region.y1} specifies the size of the region
+to be read counting down from the end of the array.  
+
+If the native image is a cube, the value of z specifies the requested
+slice of the image.  This function must call \code{psError} and return
+\code{NULL} if any of the specified parameters are out of range for
+the data in the image file, or if the image on disk is zero- or
+one-dimensional.  This function need only read images of the native
+FITS image types (\code{psU8}, \code{psS16}, \code{psS32},
+\code{psF32}, \code{psF64}).  The user is expected to convert the data
+type as needed with \code{psImageCopy}.
+ 
+\begin{verbatim}
+bool psFitsUpdateImage(psFits *fits, const psImage *input, psRegion region, int z);
+\end{verbatim}
+\tbd{we have discussed this as the alternate name} 
+Write an image section to the open \code{psFits} file pointer.  This
+operation may write a portion of an image over the existing bytes of
+an existing image.  Care must be taken to interpret \code{region},
+which specified the output pixels to be written / over-written.  If
+the combination of \code{region} and the size of \code{psImage *input}
+implies writing pixels outside the existing data area of the image,
+the function shall return an error (ie, if \code{region.x0 + image.nx
+>= NAXIS1}, \code{region.y0 + image.ny >= NAXIS2}, or \code{z >=
+NAXIS3}).  This function will only write images of the native FITS
+image types (\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32},
+\code{psF64}).  The user is expected to convert the data type as
+needed with \code{psImageCopy}.  The return value must be 0 for a
+successful operation and 1 for an error.
+
+\begin{verbatim}
+bool psFitsWriteImage(psFits *fits, psMetadata *header, const psImage *input, int depth);
+\end{verbatim}
+Create a new image based on the dimensions specified for the image and
+the requested depth.  The header and image data segments are written
+in the file at the current position of the \code{psFits} pointer.
+This function will only write images of the native FITS image types
+(\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32}, \code{psF64}).
+The user is expected to convert the data type as needed with
+\code{psImageCopy}.  The return value must be 0 for a successful
+operation and 1 for an error.
+
+\subsubsection{FITS Table I/O Functions}
+
+\begin{verbatim}
+psMetadata *psFitsReadTableRow (psFits *fits, int row);
+\end{verbatim}
+This function reads a single row of the table in the extension pointed
+at by the \code{psFits} file pointer.  The row number to be read is
+given by \code{row}.  The result is returned as a \code{psMetadata}
+collection with elements of the apporpriate types and keys
+corresponding to the table column names.  The function must apply the
+needed byte-swapping on the data in the row based on the description
+of the table data in the table header.  \tbr{we may need to be more
+flexible here: if we call this function repeatedly, it would be more
+efficient to pass the corresponding header or keep it somewhere (and
+the file pointer location, for that matter).}
+
+\begin{verbatim}
+void *psFitsReadTableRowRaw (int *nBytes, psFits *fits, int row);
+\end{verbatim}
+This function reads a single row of the table in the extension pointed
+at by the \code{psFits} file pointer.  The row number to be read is
+given by \code{row}.  The result is returned as collection of
+\code{nBytes} bytes allocated by the function.  The function must
+apply the needed byte-swapping on the data in the row based on the
+description of the table data in the table header.  \tbr{we may need
+to be more flexible here: if we call this function repeatedly, it
+would be more efficient to pass the corresponding header or keep it
+somewhere (and the file pointer location, for that matter).}
+
+\begin{verbatim}
+psArray *psFitsReadTableColumn (psFits *fits, char *colname);
+\end{verbatim}
+This function reads a single column of the table in the extension
+pointed at by the \code{psFits} file pointer.  The column is specified
+by the FITS table column key given by \code{row}.  The result is
+returned as a \code{psArray}, with the data from one row of the table
+column per array element.
+
+\begin{verbatim}
+psVector *psFitsReadTableColumnNum (psFits *fits, char *colname);
+\end{verbatim}
+This function reads a single column of the table in the extension
+pointed at by the \code{psFits} file pointer.  The column is specified
+by the FITS table column key given by \code{row} and must be of a
+numeric data type.  The result is returned as a \code{psVector} of the
+appropriate data type, with the data from one row of the table column
+per array element.
+
+\begin{verbatim}
+psArray *psFitsReadTableRaw (int *nBytes, psFits *fits);
+\end{verbatim}
+This function reads the entire data block from a table into the a
+\code{psArray}, with one element of the array per row.  The number of
+bytes per row is returned in \code{nBytes}.  The function must apply
+the needed byte-swapping on the data in each row based on the
+description of the table data in the table header.
+
+\begin{verbatim}
+psArray *psFitsReadTable (psFits *fits);
+\end{verbatim}
+This function reads the entire data block from a table into the a
+\code{psArray}, with one element of the array per row.  Each row is
+stored as a \code{psMetadata} collection as described above for
+\code{psFitsReadTableRow}. 
+
+\begin{verbatim}
+bool psFitsWriteTable(psFits* fits, psMetadata *header, psArray* table); 
+\end{verbatim}
+Accepts a \code{psArray} of \code{psMetadata} and writes it to the
+current HDU.  If the current HDU is not a table type, this will fail
+and return FALSE.
+
+\begin{verbatim}
+bool psFitsUpdateTable(psFits* fits, psMetadata *header, psMetadata* data, int row); 
+\end{verbatim}
+Writes the \code{psMetadata} data to a FITS table at the specified row
+in the current HDU.  If the current HDU is not a table type, this will
+fail and return FALSE.  
+
+\pagebreak
 \section{Astronomy-Specific Functions}
 
@@ -3457,7 +4540,6 @@
 \begin{itemize}
 \item Dates and times
-\item Metadata
 \item Detector and sky positions
-\item Astronomy Image
+\item Astronomical Image Containers
 \item Astrometry
 \item Photometry
@@ -3487,11 +4569,11 @@
 
 typedef enum {
-    PS_IERS_A,                      ///< IERS Bulliten A
-    PS_IERS_B,                      ///< IERS Bulliten B
-} psTimeBulliten;
+    PS_IERS_A,                      ///< IERS Bulletin A
+    PS_IERS_B,                      ///< IERS Bulletin B
+} psTimeBulletin;
 
 typedef struct {
     psS64            sec;           ///< seconds, negative values represent dates before 1970
-    psU32            nsec;          ///< nanseconds
+    psU32            nsec;          ///< nanoseconds
     bool             leapsecond;    ///< if time falls on a UTC leapsecond
     psTimeType       type;          ///< type of time
@@ -3523,11 +4605,12 @@
 This function may be used to convert between the various \code{psTimeType} time
 representations.  The \code{time} is modified and returned.  Conversion between
-all of the \emph{SI} length second systems should be implimented as first
+all of the \emph{SI} length second systems should be implimented by first
 converting to TAI and then to the destination system.  UT1 is a special case
 for conversion as it uses variable length secounds.  Conversation to UT1, via
 TAI, is allowed but conversion \emph{from} UT1 is currently forbidden.
 
-To convert to Local Mean Sidereal Time, it is necessary to provide the local
-longitude (specified in radians, positive East of Greenwich) as well:
+The following function converts to Local Mean Sidereal Time.  It is
+necessary to provide the local longitude (specified in radians,
+positive East of Greenwich) as well:
 
 \begin{verbatim}
@@ -3535,19 +4618,27 @@
 \end{verbatim}
 
-The function may accept any of the \code{psTimeType} types with \emph{SI}
-length seconds.  The \code{time} is modified and returned.  Note that this
-function must supply the value $UT1-UTC$, which is available externally (see
-\code{psTimeGetUT1Delta()}) and should use the UT1 values interpolated from
-IERS bulliten B.  The following utility function encapsulates the PSLib
-mechanism to extract the value of $UT1-UTC$:
-
-\begin{verbatim}
-double psTimeGetUT1Delta(const psTime *time, psTimeBulliten bulliten);
-psSphere *psTimeGetPoleCoords(const psTime *time, psTimeBulliten bulliten);
-\end{verbatim}
-
-Leap seconds are added to UTC in order to keep it within $0.9s$ of UT1 (which
-is defined relative to the Earth's rotation, and hence is useful for
-astronomical purposes).
+The function may accept any of the \code{psTimeType} types with
+\emph{SI} length seconds.  The \code{time} is modified and returned.
+Note that this function requires the value $UT1-UTC$ (see
+\code{psTimeGetUT1Delta()}) and should use the UT1 values interpolated
+from IERS bulletin B.  
+
+The following utility function encapsulates the PSLib mechanism to
+extract the value of $UT1-UTC$ from the IERS Time Tables:
+
+\begin{verbatim}
+double psTimeGetUT1Delta(const psTime *time, psTimeBulletin bulletin);
+\end{verbatim}
+
+The following function provides tidal corrections to UT1-UTC, using
+the Ray model of Simon et al (REF).
+\begin{verbatim}
+psTime *psTime_TideUT1Corr(const psTime *time);
+\end{verbatim}
+
+Leap seconds are added to UTC in order to keep it within $0.9s$ of UT1
+(which is defined relative to the Earth's rotation, and hence is
+useful for astronomical purposes).  The following function calculates
+the absolute number of leap seconds different between two times.
 
 \begin{verbatim}
@@ -3555,13 +4646,11 @@
 \end{verbatim}
 
-This function calculates the absolute number of leap seconds different between
-two times.
+The following function accepts \code{PS_TIME_UTC} objects and
+determines if the time is potentaly a leapsecond, returning
+\code{TRUE} if so.
 
 \begin{verbatim}
 bool psTimeIsLeapSecond(const psTime *utc);
 \end{verbatim}
-
-This function only accepts \code{PS_TIME_UTC} objects and determines if the
-time is potentaly a leapsecond.
 
 \subsubsection{External Date and Time Formats}
@@ -3581,7 +4670,7 @@
 \end{verbatim}
 
-The \code{psTimeToISO()} function will convertion \code{PS_TIME_UTC} objects
-with the \code{leapsecond} flag set to represent the number of seconds as
-``:60''.
+The \code{psTimeToISO()} function converts \code{PS_TIME_UTC} objects
+with the \code{leapsecond} flag set to represent the number of seconds
+as ``:60''.
 
 \subsubsection{Date and Time Parsing}
@@ -3622,17 +4711,17 @@
 \code{psS64} (the type of \code{psTime.sec}).
 
-Note that in both these functions, when handling UTC, that the difference
-between two times is not inclusive of leap seconds.  For example, if we add 30
-seconds to 1998-12-31T23:59:45Z, the result is 1999-01-01T00:00:14Z, since a
-leap second was introduced at 1999-01-01T00:00:00Z.
-
-Time math may only be done on the of \code{psTime} objects of the same type,
-and in the case of UT1, the functions shall internally convert the
-\code{psTime} inputs to TAI before performing the math; this is in order that
-leap seconds are accounted for.
-
-The type of the time returned by \code{psTimeMath} shall be the same as that of
-the input \code{time}.
-
+Note that in both these functions the difference between two times is
+the elapsed number of seconds, inclusing leap seconds.  For example,
+if we add 30 seconds to 1998-12-31T23:59:45Z, the result is
+1999-01-01T00:00:14Z, since a leap second was introduced at
+1999-01-01T00:00:00Z.
+
+Time math may only be done on \code{psTime} objects of the same type,
+and except in the case of UT1, the functions shall internally convert
+the \code{psTime} inputs to TAI before performing the math; this
+ensures that leap seconds are correctly counted.
+
+The type of the time returned by \code{psTimeMath} shall be the same
+as that of the input \code{time}.
 
 \subsubsection{Time Tables}
@@ -3645,10 +4734,10 @@
 
 \begin{itemize}
-\item IERS Bulliten A \& B (1 year ago $\rightarrow$ now + $\sim$3 months)
+\item IERS Bulletin A \& B (1 year ago $\rightarrow$ now + $\sim$3 months)
 \begin{itemize}
 \item \code{ftp://maia.usno.navy.mil/ser7/finals.daily}
 \end{itemize}
 
-\item IERS Bulliten A \& B (1973-1-2 $\rightarrow$ now + $\sim$1 year)
+\item IERS Bulletin A \& B (1973-1-2 $\rightarrow$ now + $\sim$1 year)
 \begin{itemize}
 \item \code{ftp://maia.usno.navy.mil/ser7/finals.all}
@@ -3673,5 +4762,5 @@
 format of these files shall be simple, for speed in reading.  Each line shall
 contain the date in MJD and the following values from both the A \& B IERS
-bullitens: $x_p$ (in arcseconds), $y_p$ (in arcseconds) and $\Delta$UT (in
+bulletins: $x_p$ (in arcseconds), $y_p$ (in arcseconds) and $\Delta$UT (in
 seconds).  This format must be readable by \code{psLookupTableRead}.  For
 example:
@@ -3756,1027 +4845,15 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-\subsection{Regions}
-
-In many places, we need to refer to a rectangular area.  We define a
-structure to represent a rectangle:
-\begin{verbatim}
-typedef struct {
-  float x0;
-  float x1;
-  float y0;
-  float y1;
-} psRegion;
-psRegion *psRegionAlloc (float x0, float x1, float y0, float y1);
-\end{verbatim}
-
-\begin{verbatim}
-psRegion *psRegionFromString (char *region);
-\end{verbatim}
-This function converts the IRAF description of a region in the form
-\code{[x0:x1,y0:y1]}, used for header entries such as \code{BIASSEC},
-into the corresponding \code{psRegion} structure.
-
-\subsection{Metadata}
-\label{sec:metadata}
-
-\subsubsection{Conceptual Overview}
-
-Within PSLib, we provide a data structure to carry metadata and
-mechanisms to manipulate the metadata.  Metadata is a general concept
-that requires some discussion.  In any data analysis task, the
-ensemble of all possible data may be divided into two or three
-classes: there is the specific data of interest, there is data which
-is related or critical but not the primary data of interest, and there
-is all of the other data which may or may not be interesting.  For
-example, consider a simple 2D image obtained of a galaxy from a CCD
-camera on a telescope.  If you want to study the galaxy, the specific
-data of interest is the collection of pixels.  There are a variety of
-other pieces of data which are closely related and crucial to
-understanding the data in those pixels, such as the dimensions of the
-image, the coordinate system, the time of the image, the exposure
-time, and so forth.  Other data may be known which may be less
-critical to understanding the image, but which may be interesting or
-desired at a later date.  For example, the observer who took the
-image, the filter manufacturer, the humidity at the telescope, etc.
-
-Formally, all of the related data which describe the principal data of
-interest are metadata.  Note that which piece is the metadata and
-which is the data may depend on the context.  If you are examining the
-pixels in an image, the coordinate and flux of an object may be part
-of the metadata.  However, if you are analyzing a collection of
-objects extracted from an image, you may consider then pixel data
-simply part of the metadata associated with the list of objects.  
-
-There are various ways to handle metadata vs data within a programming
-environment.  In C, it is convenient to use structures to group
-associated data together.  One possibility is to define the metadata
-as part of the associated data structure.  For example, the image data
-structure would have elements for all possible associated measurement.
-This approach is both cumbersome (because of the large number metadata
-types), impractical (because the full range of necessary metadata is
-difficult to know in advance) and inflexible (because any change in
-the collection of metadata requires addition of new structure elements
-and recompilation).  
-
-An alternative is to place the metadata in a generic container and use
-lookup mechanisms to extract the appropriate metadata when needed.  An
-example of this is would be a text-based FITS header for an image read
-into a flat text buffer.  In this implementation, metadata lookup
-functions could return the current value of, for example, NAXIS1 (the
-number of columns of the image) by scanning through the header buffer.
-This method has the benefits of flexibility and simplicity of
-programming interface, but it has the disadvantage that all metadata
-is accessed though this lookup mechanism.  This may make the code less
-readable and it may slow down the access.  
-
-PSLib implements an intermediate solution to this problem.  We specify
-a flexible, generic metadata container and access methods.  Data types
-which require association with a general collection of metadata should
-include an entry of this metadata type.  However, a subset of metadata
-concepts which are basic and frequently required may be placed in the
-coded structure elements.  This approach allows the code to refer to
-the basic metadata concepts as part of the data structure (ie,
-\code{image.nx}), but also allows us to provide access to any
-arbitrary metadata which may be generated.  As a practical matter, the
-choice of which entries are only in the metadata and which are part of
-the explicit structure elements is rather subjective.  Any data
-elements which are frequently used should be put in the structure;
-those which are only infrequently needed should be left in the generic
-metadata.
-
-There are some points of caution which must be noted.  Any
-manipulation of the data should be reflected in the metadata where
-appropriate.  This is always an issue of concern.  For example,
-consider an image of dimensions \code{nx, ny}.  If a function extracts
-a subraster, it must change the values of \code{nx, ny} to match the
-new dimensions.  What should it do to the corresponding metadata?
-Clearly, it should change the corresponding value which defines
-\code{nX, nY}.  However, it is not quite so simple: there may be other
-metadata values which depend on those values.  These must also be
-changed appropriately.  What if the metadata element points to a
-copy of the metadata which may be shared by other representations of
-the image?  These must be treated differently because the change would
-invalidate those other references.  Care must be taken, therefore,
-when writing functions which operate on the data to consider all of
-the relevant metadata entries which must also be updated. 
-
-A related issue is the definition of metadata names.  Entries in a
-structure have the advantage of being hardwired: every instance of
-that structure will have the same name for the same entry.  This is
-not necessarily the case with a more flexible metadata container.  The
-image exposure time is a notorious example in astronomy.  Different
-observatories use different header keywords (ie, metadata names) for
-the same concept of the exposure time (\code{EXPTIME},
-\code{EXPOSURE}, \code{OPENTIME}, \code{INTTIME}, etc).  Any system
-which operates on these metadata needs to address the issue of
-identifying these names.  This issue seems like an argument for
-hardwiring metadata in the structure, but in fact it does not present
-such a strong case.  If the metadata are hardwired, some function will
-still have to know how to interpret the various names to populate the
-structure.  The concept can still be localized with generic metadata
-containers by including abstract metadata names within the code which
-are tied to the various implementations-specific metadata names.
-
-\subsubsection{Metadata Representation}
-
-\begin{figure}
-\psfig{file=Metadata,width=6.5in}
-\caption{Metadata Structures\label{fig:metadata}}
-\end{figure}
-
-This section addresses the question of how \PS{} metadata should be
-represented in memory, not how it should be represented on disk.
-
-We define an item of metadata with the following structure:
-\filbreak
-\begin{verbatim}
-typedef struct {
-    int id;                             ///< unique ID for this item
-    char *name;                         ///< Name of item
-    psMetadataType type;                ///< type of this item
-    psElemType ptype;                   ///< primitive data type
-    const union {
-        psS32 S32;                      ///< integer data
-        psF32 F32;                      ///< floating-point data
-        psF64 F64;                      ///< double-precision data
-        void *V;                        ///< other type
-        psList *list;                   ///< psList entry
-        psMetadata *md;                 ///< psMetadata entry
-    } data;                             ///< value of metadata
-    char *comment;                      ///< optional comment ("", not NULL)
-} psMetadataItem;
-\end{verbatim}
-
-The \code{id} is a unique identifier for this item of metadata;
-experience shows that such tags are useful.  The entry \code{name}
-specifies the name of the metadata item.  The value of the metadata is
-given by the union \code{data}, and may be of type \code{psS32},
-\code{psF32}, \code{psF64}, or an arbitrary rich structure pointed at
-by the \code{void} pointer \code{V}.  A character string comment
-associated with this metadata item may be stored in the element
-\code{comment}. The \code{type} entry specifies how to interpret the
-type of the data being represented, given by the enumerated type
-\code{psMetadataType}:
-%
-\filbreak
-\begin{verbatim}
-typedef enum {                          ///< type of item.data is:
-    PS_META_PRIMITIVE,                  ///< primitive type: use item.ptype
-    PS_META_LIST,                       ///< psList; use item.data.list (used for non-unique data)
-    PS_META_META,                       ///< psMetadata: use item.data.list
-    PS_META_STR,                        ///< string (item.data.V)
-    PS_META_MATH,                       ///< psScalar, psVector, psImage (item.data.V)
-    PS_META_JPEG,                       ///< JPEG (item.data)
-    PS_META_PNG,                        ///< PNG (item.data)
-    PS_META_ASTROM,                     ///< astrometric coefficients (item.data)
-    PS_META_UNKNOWN,                    ///< other (item.data)
-    PS_META_NTYPE                       ///< Number of types; must be last
-} psMetadataType;
-\end{verbatim}
-If the data is a PSLib primitive data value, the primitive data type
-is given by the value of \code{ptype}.
-
-A collection of metadata is represented by the \code{psMetadata} structure:
-\begin{verbatim}
-typedef struct {
-    psList *list;                       ///< list of psMetadataItem
-    psHash *table;                      ///< hash table of the same metadata
-} psMetadata;
-\end{verbatim}
-The type \code{psMetadata} is a container class for metadata. Note
-that there are in fact \emph{two} representations of the metadata
-(each \code{psMetadataItem} appears on both).  The first
-representation employs a doubly-linked list that allows the order of
-the metadata to be preserved (e.g., if FITS headers are read in a
-particular order, they should be written in the same order).  The
-second representation employs a hash table which allows fast look-up
-given a specific metadata keyword.
-
-Certain metadata names (such as the FITS keywords \code{COMMENT} and
-\code{HISTORY} in a FITS header) may be repeated with different
-values.  In such a case, the \code{psMetadata.list} structure contains
-the entries in their original sequence with duplicate keys.  The
-\code{psMetadata.hash} entries, which are required to have unique
-keys, would have a single entry with the keyword of the repeated key,
-with the value of \code{psMetadataType} set to \code{PS_META_LIST},
-and the \code{psMetadataItem.data} element pointing to a \code{psList}
-containing the actual entries.  If \code{psMetadataItemAlloc} is
-called with the type set to \code{PS_META_LIST}, such a repeated key
-is created.  If the data value passed to \code{psMetadataItemAlloc}
-(the quantity in ellipsis) is \code{NULL}, then an empty
-\code{psMetadataItem} with the given keyword is created to hold future
-entries of that keyword.
-
-The \code{psMetadataAdd} routine is required to check that all
-metadata names are unique unless the type is already qualified as
-\code{PS_META_LIST}; in this case the data are added to the
-corresponding \code{psMetadataItem.data} list.
-
-\subsubsection{Metadata APIs}
-
-The allocator for \code{psMetadataItem} returns a full
-\code{psMetadataItem} ready for insertion into the \code{psMetadata}.
-The \code{name} entry specifies the name to use for this metadata
-item, and may include \code{sprintf}-type formating codes.  The
-\code{comment} entry is a fixed string which is used for the comment
-associated with this metadata item.  The metadata data and the
-arguments to the \code{name} formatting codes are passed, in that
-order (metadata pointer first), to \code{psMetadataItemAlloc} as
-arguments following the comment string.  The data must be a pointer
-for any data types which are stored in the element \code{data.void},
-while other data types are passed as numeric values.  The argument
-list must be interpreted appropriately by the \code{va_list} operators
-in the function.
-\begin{verbatim}
-psMetadataItem *psMetadataItemAlloc(const char *name, psMetadataType type, const char *comment, ...);
-psMetadataItem *psMetadataItemAllocV(const char *name, psMetadataType type, const char *comment, va_list list);
-\end{verbatim}
-
-The constructor for the collection of metadata, \code{psMetadata},
-simply returns an empty metadata container (employing the constructors
-for the doubly-linked list and hash table).  The destructor needs to
-free each of the \code{psMetadataItem}s using \code{psMetadataItemFree}.
-\begin{verbatim}
-psMetadata *psMetadataAlloc(void);
-\end{verbatim}
-
-Items may be added to the metadata in one of two ways --- firstly, an
-item may be added by appending a \code{psMetadataItem} which has
-already been created; and secondly by directly providing the data to
-be appended.  In both cases, the return value defines the success
-(\code{true}) or failure of the operation.  The second function,
-\code{psMetadataAdd} takes a pointer or value which is interpreted by
-the function using variadic argument interpretation.  The third
-version is the \code{va_list} version of the second function.  All
-three functions take a parameter, \code{location}, which specifies
-where in the list to place the element, following the conventions for
-the \code{psList}.  The entry \code{mode} for \code{psMetadataAddItem}
-is a bit mask constructed by OR-ing the allowed option flags (eg,
-\code{PS_META_REPLACE}) which specifies minor variations on the
-behavior.  The \code{format} entry, which specifies both the metadata
-type and the optional flags, is constructed by bit-wise OR-ing the
-appropriate \code{psMetadataType} and allowed option option flags.
-Care should be taken not to leak memory when appending an item for
-which the key already exists in the metadata (and is not
-\code{PS_META_LIST}).
-%
-\begin{verbatim}
-bool psMetadataAddItem(psMetadata *md, psMetadataItem *item, int location, int mode);
-bool psMetadataAdd(psMetadata *md, int location, const char *name, int format, const char *comment, ...);
-bool psMetadataAddV(psMetadata *md, int location, const char *name, int format, const char *comment,
-                    va_list list);
-\end{verbatim}
-
-The functions above take option flags which modify the behavior when
-metadata items are added to the metadata list.  These flags must be
-bit-exclusive of those used above for the \code{psMetadataTypes}.  The
-flags have the following meanings: 
-
-\code{PS_META_DEFAULT}: This is the zero bit mask, to allow the
-default behavior for \code{psMetadataAddItem} above.  If this is OR-ed
-with a \code{psMetadataType}, the result is as if no OR-ing took
-place.
-
-\code{PS_META_REPLACE}: If the given metadata item exists in the
-metadata list, and is not of type \code{PS_META_LIST} or
-\code{PS_META_META} (ie, not a container type), then this entry is
-allowed to replace the existing entry.  If this mode bit is not set, a
-duplicate (non-container-type) entry is an error.
-
-\begin{verbatim}
-typedef enum {                          ///< option flags for psMetadata functions
-    PS_META_DEFAULT,                    ///< default behavior (0x0000) for use in mode above
-    PS_META_REPLACE,                    ///< allow entry to be replaced
-} psMetadataFlags;
-\end{verbatim}
-
-An example of code to use these metadata APIs to generate the
-structure seen in Figure~\ref{fig:metadata} is given below.
-
-\begin{verbatim}
-md = psMetadataAlloc();
-
-psMetadataAdd(md, PS_LIST_TAIL, "SIMPLE",   PS_META_BOOL, "basic fits",            TRUE);
-psMetadataAdd(md, PS_LIST_TAIL, "BLANK",    PS_META_S32,  "invalid pixel data",    -32768);
-psMetadataAdd(md, PS_LIST_TAIL, "DATE-OBS", PS_META_STR,  "observing date UT", "   2004-6-16");
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_LIST, "head of comment block", NULL);
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "DATA");
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "PARAMS"); 
-psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32,  "exposure time (sec)",   1.05);
-psMetadataAdd(md, PS_LIST_TAIL, "COMMENT",  PS_META_STR,  "",                      "FOO");
-
-cell = psMetadataAlloc();
-psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD00");
-psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-00");
-psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.00");
-psMetadataAdd(md,   PS_LIST_TAIL, "CELL.00",  PS_META_META, "",                    cell);
-
-cell = psMetadataAlloc();
-psMetadataAdd(cell, PS_LIST_TAIL, "EXTNAME",  PS_META_STR,  "",                    "CCD01");
-psMetadataAdd(cell, PS_LIST_TAIL, "BIASNAME", PS_META_STR,  "",                    "BSEC-01");
-psMetadataAdd(cell, PS_LIST_TAIL, "CHIP",     PS_META_STR,  "",                    "CHIP.01");
-psMetadataAdd(md,   PS_LIST_TAIL, "CELL.01",  PS_META_META, "",                    cell);
-\end{verbatim}
-
-The following code shows how to use the APIs to replace one of these values:
-\begin{verbatim}
-psMetadataAdd(md, PS_LIST_TAIL, "EXPTIME",  PS_META_F32 | PS_REPLACE,  "new exposure time (sec)",   2.05);
-\end{verbatim}
-
-Items may be removed from the metadata by specifying a key or a
-location in the list.  If the value of \code{name} is \code{NULL}, the
-value of \code{location} is used.  If the value of \code{name} is not
-\code{NULL}, then \code{location} must be set to
-\code{PS_LIST_UNKNOWN}.  If the key matches a metadata item, the item
-is removed from the metadata and \code{true} is returned; otherwise,
-\code{false} is returned.  If the key is not unique, then \emph{all}
-items corresponding to the key are removed, and \code{true} is
-returned.
-%
-\begin{verbatim}
-bool psMetadataRemove(psMetadata *md, int location, const char *key);
-\end{verbatim}
-
-Items may be found within the metadata by providing a key.  In the
-event that the key is non-unique, the first item is returned.
-\begin{verbatim}
-psMetadataItem *psMetadataLookup(const psMetadata *md, const char *key);
-\end{verbatim}
-
-Several utility functions are provided for simple cases.  These
-functions perform the effort of casting the data to the appropriate
-type.  The numerical functions shall return 0.0 if their key is not
-found.  If the pointer value of \code{status} is not \code{NULL}, it
-is set to reflect the success or failure of the lookup.
-\begin{verbatim}
-void *psMetadataLookupPtr(bool *status, const psMetadata *md, const char *key);
-psS32 psMetadataLookupS32(bool *status, const psMetadata *md, const char *key);
-psF64 psMetadataLookupF64(bool *status, const psMetadata *md, const char *key);
-\end{verbatim}
-
-Items may be retrieved from the metadata by their entry position.  The
-value of which specifies the desired entry in the fashion of
-\code{psList}.
-\begin{verbatim}
-psMetadataItem *psMetadataGet(const psMetadata *md, int location);
-\end{verbatim}
-
-The metadata list component may be iterated over by using a
-\code{psListIterator} in a fashion equivalent to the usage for
-\code{psList}.  The iterator may be set to a location in the
-\code{psMetadata} list, and the user may get the previous or next item
-in the list relative to that location.  \code{psMetadataGetNext} has
-the ability to match the key using a POSIX regex, e.g., if the user
-only wants to iterate through \code{IPP.machines.sky} and doesn't want
-to bother with \code{IPP.machines.detector}.  The iterator should
-iterate over every item in the metadata list, even those that are
-contained in a \code{PS_META_LIST}.  The value \code{iterator}
-specifies the iterator to be used.  In setting the iterator, the
-position of the iterator is defined by \code{location}, which follows
-the conventions of the \code{psList} iterators.
-\begin{verbatim}
-psListIterator *psMetadataIteratorAlloc(psMetadata *md, int location, bool mutable);
-bool psMetadataIteratorSet(psListIterator *iterator, int location);
-psMetadataItem *psMetadataGetAndIncrement(psListIterator *iterator, const char *regex);
-psMetadataItem *psMetadataGetAndDecrement(psListIterator *iterator, const char *regex);
-\end{verbatim}
-
-Metadata items may be printed to an open file descriptor based on a
-provided format.  The format string is an sprintf format statement
-with exactly one \% formatting command.  If the metadata item type is
-a numeric type, this formatting command must also be numeric, and type
-conversion performed to the value to match the format type.  If the
-metadata item type is a string, the formatting command must also be
-for a string (\%s type of command).  If the metadata type is any other
-data type, printing is not allowed.
-\begin{verbatim}
-bool psMetadataItemPrint(FILE *fd, const char *format, const psMetadataItem *md);
-\end{verbatim}
-
-\subsubsection{Configuration files}
-\label{sec:configspec}
-
-It will be necessary for the \PS{} system, in order to load
-pre-defined settings, to parse a configuration file into a
-\code{psMetadata} structure.  This shall be performed by the
-function \code{psMetadataParseConfig}, as described below.
-
-\begin{verbatim}
-psMetadata *psMetadataParseConfig(psMetadata *md, int *nFail, const char *filename, bool overwrite);
-\end{verbatim}
-
-Given a metadata container, \code{md}, and the name of a configuration
-file, \code{filename}, \code{psMetadataParseConfig} shall parse the
-configuration file, placing the contained key/type/value/comment quads
-into the metadata, and returning a pointer to the metadata structure.
-The number of lines that failed to parse is returned in \code{nFail}.
-Multiple specifications of a key that haven't been declared (see
-below) are overwritten if and only if \code{overwrite} is \code{true}.
-If the metadata container is \code{NULL}, it shall be allocated.  
-
-On error, the function shall return \code{NULL}.
-
-The configuration file shall consist of plain text with
-key/type/value/comment quads on separate lines.  Blank lines,
-including those consisting solely of whitespace (both spaces and
-tabs), shall be ignored, as shall lines that commence with the comment
-character (a hash mark, \code{#}), either immediately at the start of
-the line, or preceded by whitespace.  The key/type/value/comment quads
-shall all lie on a single line, separated by whitespace.
-
-The key shall be first, possibly preceded on the line by whitespace
-which should not form part of the key.
-
-Next, to assist the casting of the value, shall be a string
-identifying the type of the value, which shall correspond to one of
-the simple types supported in \code{psMetadata}:
-\code{STRING,BOOL,S32,F32,F64}; \code{STR} may be used to abbreviate
-\code{STRING}.
-
-\tbd{May, in the future, require more types, including U8,S16,C64,
-which will also necessitate updating the definition of psMetadata.}
-
-The value shall follow the type: strings may consist of multiple
-words, and shall have all leading and trailing whitespace removed;
-booleans shall simply be either \code{T} or \code{F}.
-
-Following the value may be an optional comment, preceded by a comment
-character (a hash mark, \code{#}), which in the case of a string
-value, serves to mark the end of the value, and for other types serves
-to identify the comment to the reader.  Only one comment character may
-be present on any single line (i.e., neither strings nor comments are
-permitted to contain the comment character).  The comment may consist
-of multiple words, and shall have leading and trailing whitespace
-removed.
-
-One wrinkle is the specification of vectors.  Keys for which the value
-is to be parsed as a vector shall be preceded immediately by a
-``vector symbol'', which we choose to be the ``at'' sign, \code{@}.
-In this case, the type shall be interpreted as the type for the
-vector, which may be any of the signed or unsigned integer or floating
-point types (\code{U8,U16,U32,U64,S8,S16,S32,S32,S64,F32,F64}) but not
-the complex floating point types; and the value shall consist of
-multiple numbers, separated either by a comma or whitespace.  These
-values shall populate a \code{psVector} of the appropriate type in the
-order in which they appear in the configuration file.
-
-\tbd{May add complex types, likely to be specified with values such as
-  1.23+4.56i in the future.}
-
-An additional hurdle is the specification of keys that may be
-non-unique (such as the \code{COMMENT} keyword in a FITS header).
-These keys shall be specified in the configuration file as non-unique
-by specifying the key at the start of the line (possibly preceded by
-whitespace) and specifying the type as a ``multiple symbol'', which we
-choose to be an asterisk, \code{*}.  No other data may be provided on
-this line, though a comment, preceeded by the comment marker, is
-valid.  A warning shall be produced when a key which has not been
-specified to be non-unique is repeated; in this case, the former value
-shall be overwritten if \code{overwrite} is \code{true}, otherwise the
-line shall be ignored and counted as one that could not be parsed.
-
-If a line does not conform to the rules laid out here, a warning shall
-be generated, it shall be ignored and counted as a line that could not
-be parsed.  The total number of lines that were not able to be parsed
-(including those that were ignored because \code{overwrite} is
-\code{false}, and any other parsing problems, but not including blank
-lines and comment lines) shall be returned by the function in the
-argument \code{nFail}.
-
-Here are some examples of lines of a valid configuration file:
-\filbreak
-\begin{verbatim}
-Double     F64     1.23456789      # This is a comment
-Float    F32 0.98765 # This is a comment too
-String  STR This is the string that forms the value #comment
-
- # This is a comment line and is to be ignored
-boolean     BOOL    T # The value of `boolean' is `true'
-
-@primes U8  2,3 5 7,11,13 17 #   These are prime numbers
-
-comment MULTI # The rest of this line is ignored, but `comment' is set to be non-unique
-comment STR This
-comment STR     is
-comment STR       a
-comment STR        non-unique
-comment STR                  key
-Float F64 1.23456 # This generates a warning, and, if `overwrite' is `false', is ignored
-\end{verbatim}
-
-Of course, a real configuration file should look much nicer to humans
-than the above example, but PSLib must be able to parse such ugly
-files.
-
-We extend \code{psMetadataParseConfig} to allow a modest tree
-structure by defining a reserved keyword \code{TYPE}.  Any line in the
-config file which starts with the word \code{TYPE} shall be
-interpretted as defining a new valid type.  The defined type name
-follows the word \code{TYPE}, and is in turn followed by an arbitrary
-number of words.  These words are to be interpreted as the names of an
-embedded \code{psMetadata} entry, where the values are given on any
-line which (following the \code{TYPE} definition) employs the new type
-name.  For example, a new type may be defined as:
-\begin{verbatim}
-TYPE      CELL   EXTNAME   BIASSEC  CHIP
-CELL.00   CELL   CCD00     BSEC-00  CHIP.00
-CELL.01   CELL   CCD01     BSEC-01  CHIP.00
-\end{verbatim}
-
-When \code{psMetadataParseConfig} encounters the \code{TYPE} line, it
-should construct a \code{psMetadata} container and fill it with
-\code{psMetadataItems} having the names \code{EXTNAME, BIASSEC, CHIP},
-with type \code{PS_META_STR}, but data allocated.  When it next
-encounters an entry of type \code{CELL}, it should then use the given
-name (e.g., \code{CELL.00}) for the \code{psMetadataItem}, and copy
-the \code{psMetadata} data onto the \code{psMetadataItem.data.md}
-entry, filling in the values from the rest of the line (\code{CCD00,
-BSEC-00, CHIP.00}).  This hierarchical structure is illustrated in
-Figure~\ref{fig:metadata}.
-
-We further extend \code{psMetadataParseConfig} to allow the definition
-of a \code{psMetadata} entry using a sequence of successive lines to
-define the values of the \code{psMetadataItem} entries.  The initial
-line defines the new \code{psMetadata} entry and its name.  The
-following lines have the same format as the other metadata config file
-entries.  The sequence is terminated with a line with a single word
-\code{END}.  For example, a metadata entry may be defined as:
-\begin{verbatim}
-CELL      METADATA
- EXTNAME   STR   CCD00
- BIASSEC   STR   BSEC-00
- CHIP      STR   CHIP.00
- NCELL     S32   24
-END
-\end{verbatim}
-
-A series of test inputs is contained in
-\S\ref{sec:configtest}.
-
-\subsection{XML Functions}
-
-Within Pan-STARRS, we will use XML documents as a transport mechanism
-to carry data between programs and between IPP and other subsystems.
-Configuration information may be stored as well as XML documents, in
-addition to the text format discussed in the discussion on Metadata.
-XML is an extremely variable document format, and it is not currently
-the intention of PSLib to provide a complete PSLib version of XML
-operations.  Rather, a limited number of operations are defined to
-convert specific data structures to an appropriate XML document.  To
-maximize the simplicity of the XML APIs, we will use the convention
-that a single XML document to be parsed by PSLib shall contain only a
-single data structure.  Each of the XML APIs therefore take as input a
-reference to a complete XML document and return a PSLib data
-structure, or take a PSLib data structure and return a complete XML
-document.
-
-We start by defining a PSLib wrapper type which is a pointer to an XML
-document in memory.  We wrap the \code{libxml2} version of an XML
-document pointer for now:
-\begin{verbatim}
-typedef xmlDocPtr psXMLDoc;
-void psXMLDocFree(psXMLDoc *doc);
-\end{verbatim}
-
-The next pair of functions convert a \code{psMetadata} data structure
-to a complete \code{psXMLDoc} (in memory) and vice versa:
-\begin{verbatim}
-psXMLDoc *psMetadataToXMLDoc(const psMetadata *metadata);
-psMetadata *psXMLDocToMetadata(const psXMLDoc *doc);
-\end{verbatim}
-
-The next pair of functions loads the data in a named file into a
-complete \code{psXMLDoc} (in memory) and write out the \code{psXMLDoc}
-to a named file:
-\begin{verbatim}
-psXMLDoc *psXMLParseFile(const char *filename);
-int psXMLDocToFile(const psXMLDoc *doc, const char *filename);
-\end{verbatim}
-
-The next pair of functions accepts a block of memory and parses it
-into a complete \code{psXMLDoc} (also in memory), and vice versa:
-\begin{verbatim}
-psXMLDoc *psXMLParseMemory(const char *buffer, const int size);
-int psXMLDocToMemory(const psXMLDoc *doc, char *buffer);
-\end{verbatim}
-
-The next pair of functions read from and write to a file descriptor.
-The first converts the imcoming data to a complete \code{psXMLDoc}
-(also in memory), the second writes the \code{psXMLDoc} to the file
-descriptor:
-\begin{verbatim}
-psXMLDoc *psXMLParseFD(int fd);
-int psXMLDocToFD(const psXMLDoc *doc, int fd);
-\end{verbatim}
-
-\subsection{Database Functions}
-
-Many of the applications that PSLib will be used for will require
-access to a simple relational database.  PSLib includes generic
-database-independent interface mechanisms as part of its API set.  The
-most important aspect of PSLib's database support is to abstract as
-much database specific complexity as is feasible.  As almost all RDBMS
-provide at least a simple transactional model, commit and rollback
-support should be provided.
-
-Currently, only support for MySQL 4.1.x is required but other backends
-may be added as options in the future.  As a particular example which
-has implications for the database interaction model, support for
-SQLite may be required in the future.  Currently, the choice of
-backend database interface may be made as a compile option.  Details
-of the specified APIs in the discussion below refer to the relevant
-MySQL functions.
-
-Database errors must be trapped and placed onto the psError stack.
-The complete error message should be retrieved with the database's
-error function.
-
-\subsubsection{Managing the Database Connection}
-
-We specify a database handle which carries the information about the
-database connection:
-
-\begin{verbatim}
-    typedef struct {
-        MYSQL *mysql;
-    } psDB;
-\end{verbatim}
-
-The following collection of functions provides basic database functionality:
-
-\begin{verbatim}
-    // wraps mysql_init() & mysql_real_connect()
-    psDB *psDBInit(const char *host, const char *user, const char *passwd, const char *dbname);
-
-    // wraps mysql_close()
-    void psDBCleanup(psDB *dbh);
-
-    // wraps mysql_create_db()
-    bool psDBCreate(psDB *dbh, const char *dbname);
-
-    // wraps mysql_select_db()
-    bool psDBChange(psDB *dbh, const char *dbname);
-
-    // wraps mysql_drop_db()
-    bool psDBDrop(psDB *dbh, const char *dbname);
-\end{verbatim}
-
-For MySQL support, \code{psDBInit()} wraps \code{mysql_init()} and
-\code{mysql_real_connect()} in order to initialize a psDB structure and
-establish a database connection.  A null pointer should be returned on
-failure.
-
-When implementing support for SQLite, or other DB which is purely
-file-based, the \code{host}, \code{user}, and \code{passwd} arguments
-would be ignored while \code{dbname} would specify the path to the
-SQLite db file.
-
-\subsubsection{Interacting with Database Tables}
-
-The functions in this section perform high level interactions with the
-database tables.  All of them should behave ``atomically'' with
-respect to the state of the database.  Specifically, all interactions
-with the database should be done as a part of a transaction that is
-rolled-back on failure and committed only after all queries used by
-the API have been run.  In general, this API set attempts to treat a
-database table as a 2D matrix where columns can be represented by a
-\code{psVector} and rows as a \code{psMetadata} type.  A
-\code{psMetadata} collection is also used to define the columns of a
-table and as part of the query restrictions.
-
-\begin{verbatim}
-    bool psDBCreateTable(psDB *dbh, const char *tableName, psMetadata *md);
-\end{verbatim}
-
-This function generates and executes the SQL needed to create a table
-named \code{tableName}, with the column names and datatypes as
-described in \code{md}.  Each data item in the \code{psMetadata}
-collection represents a single table field.  The name of the field is
-given by the name of the \code{psMetadataItem} and the data type is
-give by the \code{psMetadataItem.type} and \code{psMetadataItem.ptype}
-entries.  A lookup table should be used to convert from PSLib types
-into MySQL compatible SQL data types.  For example, a
-\code{PS_META_STR} would map to an SQL99 varchar.  If the value of
-\code{type} is \code{PS_META_STR} then the \code{psMetadataItem.data}
-element is set to a string with the length for the field written as a
-text string.  The value of the \code{psMetadataItem.data} element is
-unused for the \code{PS_META_PRIMITIVE} types.  Other metadata types
-beyond \code{PS_META_STR} and \code{PS_META_PRIMITIVE} are not allowed
-in a table definition metadata collection.
-
-Database indexes can be specified setting the \code{comment} field to
-``\code{Primary Key}'' or ``\code{Key}''.  Comment are otherwise
-ignored.
-
-\begin{verbatim}
-    bool psDBDropTable(psDB *dbh, const char *tableName);
-\end{verbatim}
-
-This function deletes the specified table.
-
-\begin{verbatim}
-    psArray *psDBSelectColumn(psDB *dbh, const char *tableName, const char *col, const psU64 limit);
-    psVector *psDBSelectColumnNum(psDB *dbh, const char *tableName, const char *col, psElemType pType, const psU64 limit);
-\end{verbatim}
-
-These functions generates and executes the SQL needed to select an entire
-column from a table or up to \code{limit} rows from it.  If \code{limit} is 0,
-the entire range is returned.  The database response is processed and a
-\code{psArray} of strings is returned.  The Num version of the function returns
-the data in a \code{psVector}, data cast to \code{pType}.  It returns an error
-(NULL) if the requested field is not a numerical type.
-
-\begin{verbatim}
-    psArray *psDBSelectRows(psDB *dbh, const char *tableName, psMetadata *where, const psU64 limit);
-\end{verbatim}
-
-This function returns rows from the specified table which match
-the restrictions given by \code{where}.  The restrictions are
-specified as field / value pairs.  The \code{psMetadata} collection
-where must consist of valid database fields, though the database query
-checking functions may be used to validate the fields as part of the
-query.  If \code{where} is \code{NULL}, then there are no restrictions
-on the rows selected.  The selected rows are returned as a
-\code{psArray} of \code{psMetadata} values, one per row. 
-
-\begin{verbatim}
-    bool psDBInsertOneRow(psDB *dbh, const char *tableName, psMetadata *row);
-\end{verbatim}
-
-Insert the data from \code{row} into \code{tableName}.  It should be noted in
-the API reference that if fields are specified in \code{row} that do not exist
-in \code{tablename}, the insert will fail.
-
-\begin{verbatim}
-    bool psDBInsertRows(psDB *dbh, const char *tableName, psArray *rowSet);
-\end{verbatim}
-
-Similar to \code{psDBInsertOneRow()}, this function inserts many rows at once
-and is atomic for the complete set of rows.
-
-\begin{verbatim}
-    psArray *psDBDumpRows(psDB *dbh, const char *tableName);
-\end{verbatim}
-
-Fetch all rows as an psArray of psMetadata.
-
-\begin{verbatim}
-    psMetadata *psDBDumpCols(psDB *dbh, const char *tableName);
-\end{verbatim}
-
-Fetch all columns, as either a psVector or a psArray depnding on whether or not
-the column is numeric, and return them in a psMetadata structure where
-psMetadataItem.name contains the column's name.
-
-\begin{verbatim}
-    psS64 psDBUpdateRows(psDB *dbh, const char *tableName, psMetadata *where, psMetadata *values);
-\end{verbatim}
-
-Update the columns contained in \code{values} in the row(s) that have a field
-with the value indicated by \code{where} (note that this is only allows very
-limited use of SQL99's ``where'' semantics).  The number of rows modified is
-returned.  A negative value is return to indicate an error. If there are
-multiple psMetadataItems in \code{where} then each item should be considered as
-an additional constraint.  e.g.  ``where foo = x and where bar = y''
-
-\begin{verbatim}
-    psS64 psDBDeleteRows(psDB *dbh, const char *tableName, psMetadata *where);
-\end{verbatim}
-
-Delete the rows that are matched by \code{where} using the same semantics for
-\code{where} as in psDBUpdateRow().  A negative value is returned to indicate an
-error.
-
-\subsection{FITS I/O Functions}
-
-We need a variety of I/O functions between the disk and certain of our
-PSLib data structures.  We need the ability to access FITS headers,
-images and tables (both ASCII and Binary).  We define here the FITS
-I/O functions, all of which are currently specified as wrappers to
-functions within CFITSIO.  CFITSIO provides a wide range of utilities
-which we do not feel are particularly appropriate as part of a generic
-I/O library, such as assumptions about names which change the data
-interpretation, etc.  We are defining our calls to avoid the hidden
-'features'.  The CFITSIO functions which are wrapped should in general
-be the most basic versions.
-
-\begin{verbatim}
-typedef struct {
-    fitsfile fd;
-} psFits;
-\end{verbatim}
-We begin by defining a datatype to wrap the CFITSIO \code{fitsfile}
-structure.  This is necessary to allow repeated access to the data in
-a file without multiple open commands (which are expensive).
-
-\subsubsection{FITS File Manipulations}
-
-\begin{verbatim}
-psFits *psFitsAlloc(const char *filename);
-\end{verbatim}
-
-Opens a FITS file at positions the pointer to the PHU.
-
-\begin{verbatim}
-bool psFitsMoveExtName(psFits *fits, const char *extname);
-\end{verbatim}
-
-Positions the pointer to the beginning of the specified
-\code{extname}.  If the \code{extname} does not exist, the function
-shall fail.  
-
-\begin{verbatim}
-bool psFitsMoveExtNum(psFits* fits, int extnum, bool relative);
-\end{verbatim}
-
-Moves the pointer to the beginning of the specified HDU number.  If
-\code{relative} is TRUE, \code{extnum} represents the number of HDUs
-relative to the current HDU.  The PHU is entry number 0, while the
-extended data segments start at number 1.
-
-\begin{verbatim}
-int psFitsGetExtNum(psFits* fits);
-\end{verbatim}
-
-Returns the current HDU number (i.e., file position).  
-
-\begin{verbatim}
-int psFitsGetSize(psFits* fits);
-\end{verbatim}
-
-Returns the number of HDUs in the file.
-
-\begin{verbatim}
-psFitsType psFitsGetExtType(psFits* fits);
-\end{verbatim}
-
-Gets the current HDU's type (table or image).
-
-\subsubsection{FITS Header I/O Functions}
-
-\begin{verbatim}
-psMetadata *psFitsReadHeader(psMetadata *out, const psFits *fits);
-\end{verbatim}
-Read header data into a \code{psMetadata} structure.  The data is read
-from the current HDU pointed at by the \code{psFits *fits} entry.  If
-\code{out} is \code{NULL}, a new psMetadata is created.
-
-\begin{verbatim}
-psMetadata *psFitsReadHeaderSet (psFits *fits);
-\end{verbatim}
-Load a complete set of headers from the \code{psFits} file pointer.
-This function loads the headers from all extensions into a
-\code{psMetadata} collection, each entry of which is a pointer to a
-\code{psMetadata} structure containing the header data.  The metadata
-entry names are the \code{EXTNAME} values for each header (with the
-value of \code{PHU} for the primary header unit).  At the start of the
-operation, the file pointer is rewound to the beginning of the file.
-At the end, it is positioned where it started when the function was
-called.
-
-\begin{verbatim}
-bool psFitsWriteHeader(psMetadata *output, const psFits *fits);
-\end{verbatim}
-Write metadata into the header of a FITS image file.  The header is
-written at the current HDU.
-
-\subsubsection{FITS Image I/O Functions}
-
-\begin{verbatim}
-psImage *psFitsReadImage(psImage *output, psFits *fits, psRegion region, int z);
-\end{verbatim}
-Read an image or subimage from the \code{psFits} file pointer.  This
-function is a wrapper to the CFITSIO library function.  The input
-parameters allow a full image or a subimage to be read.  The region to
-be read is specified by \code{region}.  A negative value for either of
-\code{region.x1} or \code{region.y1} specifies the size of the region
-to be read counting down from the end of the array.  
-
-If the native image is a cube, the value of z specifies the requested
-slice of the image.  This function must call \code{psError} and return
-\code{NULL} if any of the specified parameters are out of range for
-the data in the image file, or if the image on disk is zero- or
-one-dimensional.  This function need only read images of the native
-FITS image types (\code{psU8}, \code{psS16}, \code{psS32},
-\code{psF32}, \code{psF64}).  The user is expected to convert the data
-type as needed with \code{psImageCopy}.
- 
-\begin{verbatim}
-bool psFitsUpdateImage(psFits *fits, const psImage *input, psRegion region, int z);
-\end{verbatim}
-\tbd{we have discussed this as the alternate name} 
-Write an image section to the open \code{psFits} file pointer.  This
-operation may write a portion of an image over the existing bytes of
-an existing image.  Care must be taken to interpret \code{region},
-which specified the output pixels to be written / over-written.  If
-the combination of \code{region} and the size of \code{psImage *input}
-implies writing pixels outside the existing data area of the image,
-the function shall return an error (ie, if \code{region.x0 + image.nx
->= NAXIS1}, \code{region.y0 + image.ny >= NAXIS2}, or \code{z >=
-NAXIS3}).  This function will only write images of the native FITS
-image types (\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32},
-\code{psF64}).  The user is expected to convert the data type as
-needed with \code{psImageCopy}.  The return value must be 0 for a
-successful operation and 1 for an error.
-
-\begin{verbatim}
-bool psFitsWriteImage(psFits *fits, psMetadata *header, const psImage *input, int depth);
-\end{verbatim}
-Create a new image based on the dimensions specified for the image and
-the requested depth.  The header and image data segments are written
-in the file at the current position of the \code{psFits} pointer.
-This function will only write images of the native FITS image types
-(\code{psU8}, \code{psS16}, \code{psS32}, \code{psF32}, \code{psF64}).
-The user is expected to convert the data type as needed with
-\code{psImageCopy}.  The return value must be 0 for a successful
-operation and 1 for an error.
-
-\subsubsection{FITS Table I/O Functions}
-
-\begin{verbatim}
-psMetadata *psFitsReadTableRow (psFits *fits, int row);
-\end{verbatim}
-This function reads a single row of the table in the extension pointed
-at by the \code{psFits} file pointer.  The row number to be read is
-given by \code{row}.  The result is returned as a \code{psMetadata}
-collection with elements of the apporpriate types and keys
-corresponding to the table column names.  The function must apply the
-needed byte-swapping on the data in the row based on the description
-of the table data in the table header.  \tbr{we may need to be more
-flexible here: if we call this function repeatedly, it would be more
-efficient to pass the corresponding header or keep it somewhere (and
-the file pointer location, for that matter).}
-
-\begin{verbatim}
-void *psFitsReadTableRowRaw (int *nBytes, psFits *fits, int row);
-\end{verbatim}
-This function reads a single row of the table in the extension pointed
-at by the \code{psFits} file pointer.  The row number to be read is
-given by \code{row}.  The result is returned as collection of
-\code{nBytes} bytes allocated by the function.  The function must
-apply the needed byte-swapping on the data in the row based on the
-description of the table data in the table header.  \tbr{we may need
-to be more flexible here: if we call this function repeatedly, it
-would be more efficient to pass the corresponding header or keep it
-somewhere (and the file pointer location, for that matter).}
-
-\begin{verbatim}
-psArray *psFitsReadTableColumn (psFits *fits, char *colname);
-\end{verbatim}
-This function reads a single column of the table in the extension
-pointed at by the \code{psFits} file pointer.  The column is specified
-by the FITS table column key given by \code{row}.  The result is
-returned as a \code{psArray}, with the data from one row of the table
-column per array element.
-
-\begin{verbatim}
-psVector *psFitsReadTableColumnNum (psFits *fits, char *colname);
-\end{verbatim}
-This function reads a single column of the table in the extension
-pointed at by the \code{psFits} file pointer.  The column is specified
-by the FITS table column key given by \code{row} and must be of a
-numeric data type.  The result is returned as a \code{psVector} of the
-appropriate data type, with the data from one row of the table column
-per array element.
-
-\begin{verbatim}
-psArray *psFitsReadTableRaw (int *nBytes, psFits *fits);
-\end{verbatim}
-This function reads the entire data block from a table into the a
-\code{psArray}, with one element of the array per row.  The number of
-bytes per row is returned in \code{nBytes}.  The function must apply
-the needed byte-swapping on the data in each row based on the
-description of the table data in the table header.
-
-\begin{verbatim}
-psArray *psFitsReadTable (psFits *fits);
-\end{verbatim}
-This function reads the entire data block from a table into the a
-\code{psArray}, with one element of the array per row.  Each row is
-stored as a \code{psMetadata} collection as described above for
-\code{psFitsReadTableRow}. 
-
-\begin{verbatim}
-bool psFitsWriteTable(psFits* fits, psMetadata *header, psArray* table); 
-\end{verbatim}
-Accepts a \code{psArray} of \code{psMetadata} and writes it to the
-current HDU.  If the current HDU is not a table type, this will fail
-and return FALSE.
-
-\begin{verbatim}
-bool psFitsUpdateTable(psFits* fits, psMetadata *header, psMetadata* data, int row); 
-\end{verbatim}
-Writes the \code{psMetadata} data to a FITS table at the specified row
-in the current HDU.  If the current HDU is not a table type, this will
-fail and return FALSE.  
-
-\subsection{Detector and Sky Coordinates}
+\subsection{Linear and Spherical Coordinates}
 
 Both detector and sky positions will be used extensively in the IPP.
 The first are linear coordinates which conform to Euclidean geometry
-while the second are angular coordinates for which additional care
-must often be taken.  We put these into two structures, \code{psPlane}
-and \code{psSphere}, respectively.  Partitioning these two will enable
-error-checking.
+while the second are angular coordinates which define a position on
+the sphere of the sky.  We put these into two structures,
+\code{psPlane} and \code{psSphere}, respectively.  Partitioning these
+two will enable error-checking.  An alternative representation for
+angular positions is the 3-D unit vector.  These are used in
+particular as part of spherical rotation calculations.  We define
+\code{psCube} to represent such an element.
 %
 \begin{verbatim}
@@ -4794,4 +4871,13 @@
     double dErr;                        ///< Error in Dec
 } psSphere;
+
+typedef struct {
+    double x;                           ///< cos (DEC) cos (RA) 
+    double y;                           ///< cos (DEC) sin (RA) 
+    double z;                           ///< sin (DEC)
+    double xErr;                        ///< Error in x
+    double yErr;                        ///< Error in y
+    double zErr;                        ///< Error in z
+} psCube;
 \end{verbatim}
 
@@ -4818,6 +4904,7 @@
 Constructors for these are straight-forward:
 \begin{verbatim}
-psPlane *psPlaneAlloc(void);
+psPlane  *psPlaneAlloc(void);
 psSphere *psSphereAlloc(void);
+psCube   *psCubeAlloc(void);
 \end{verbatim}
 Initialization of the structures is not necessary.
@@ -4985,224 +5072,4 @@
 \code{NULL}, the function shall generate an error and return
 \code{NULL}.
-
-
-\subsubsection{Celestial Coordinate Conversions}
-
-We need to be able to convert between ICRS, Galactic and Ecliptic
-coordinates, and potentially between arbitrary spherical coordinate
-systems.  All of these basic spherical transformations represent
-rotations of the spherical coordinate reference.  We specify a general
-transformation function which takes a structure,
-\code{psSphereTransform}, defining the transformation between two
-spherical coordinate systems (the structure contains the sines and
-cosines of the angles involved so as to minimize computation time for
-repeated transformations).  We also define a function to generate
-\code{psSphereTransform}, based on the three angles
-describing the location of the pole and the relative equatorial
-rotations of the two systems.  We also specify special functions to
-return the \code{psSphereTransform} for transformations
-between standard coordinate systems.
-
-\begin{verbatim}
-typedef struct {
-    double cosDeltaP;                 ///< Cosine of target pole latitude in the source system
-    double sinDeltaP;		      ///< Sine of target pole latitude in the source system
-    double alphaP;		      ///< Longitude of the target system pole in the source system
-    double phiP;		      ///< Longitude of the ascending node in the target system
-} psSphereTransform;
-\end{verbatim}
-
-The constructor is defined as follows:
-\begin{verbatim}
-psSphereTransform *psSphereTransformAlloc(double alphaP, double deltaP, double phiP);
-\end{verbatim}
-where \code{alphaP} and \code{deltaP} define the coordinates in the
-input system of the north pole in the output system and \code{phiP}
-defines the longitude in the input system of the equatorial
-intersection between the two systems (e.g, the first point of Ares).
-The constructor must calculate the sines and cosines above.
-
-Spherical coordinates may be transformed by providing the
-transformation and the coordinate in the input system to
-\code{psSphereTransform}:
-\begin{verbatim}
-psSphere *psSphereTransformApply(psSphere *out, 
-                                 const psSphereTransform *transform, 
-                                 const psSphere *coord);
-\end{verbatim}
-
-The following functions simply return the appropriate
-\code{psSphereTransform} to convert between predefined spherical
-coordinate systems (i.e., ICRS, Ecliptic and Galactic).  These are
-constructors as well as the above \code{psSphereTransformAlloc}.
-%
-\begin{verbatim}
-psSphereTransform *psSphereTransformICRSToEcliptic(psTime *time);
-psSphereTransform *psSphereTransformEclipticToICRS(psTime *time);
-psSphereTransform *psSphereTransformICRSToGalactic(void);
-psSphereTransform *psSphereTransformGalacticToICRS(void);
-\end{verbatim}
-
-We also require the ability to precess coordinates from one equinox to
-another.
-
-\begin{verbatim}
-psSphere *psSpherePrecess(psSphere *coords, const psTime *fromTime, const psTime *toTime);
-\end{verbatim}
-
-Given coordinates, \code{coords}, with equinox for \code{fromTime},
-the coordinates are precessed to equinox for \code{toTime}.  The
-\code{coords} are modified in-place.  Equinoxes shall be Julian
-equinoxes (as opposed to Bessellian).
-
-\subsubsection{Projections}
-
-We require functions to convert between spherical and linear
-coordinate systems based on a variety of projections.  The required
-projections include:
-\begin{itemize}
-\item TAN
-\item SIN
-\item AIT
-\item PAR
-\end{itemize}
-
-We specify the following structure \code{psProjection} to define the
-parameters of the projection:
-\begin{verbatim}
-typedef struct {
-    double R, D;                         ///< coordinates of projection center
-    double Xs, Ys;                       ///< plate-scale in X and Y directions
-    psProjectionType type;               ///< projection type
-} psProjection;
-\end{verbatim}
-
-The projection type is defined by the following enumerated type \code{psProjectionType}:
-\begin{verbatim}
-typedef enum {                          ///< type of val is:
-    PS_PROJ_TAN,                        ///< Tangent projection
-    PS_PROJ_SIN,                        ///< Sine projection
-    PS_PROJ_AIT,                        ///< Aitoff projection
-    PS_PROJ_PAR,                        ///< Par projection
-    PS_PROJ_NTYPE                       ///< Number of types; must be last
-} psProjectionType;
-\end{verbatim}
-
-The constructor is straight-forward:
-\begin{verbatim}
-psProjection *psProjectionAlloc(double R, double D, double Xs, double Ys, psProjectionType type);
-\end{verbatim}
-
-The following functions will project and deproject (respectively)
-spherical coordinates:
-
-\begin{verbatim}
-psPlane  *psProject(const psSphere *coord, const psProjection *projection);
-psSphere *psDeproject(const psPlane *coord, const psProjection *projection);
-\end{verbatim}
-
-\subsubsection{Offsets}
-We require a function to calculate the offset between two positions on
-the sky, as well as a function to apply an offset to a position.  The
-first determines the offset (RA,Dec) on the sky between two positions.
-The second applies the given offset to the coordinate.  Both an offset
-mode and an offset unit may be defined.  The mode may be either
-\code{PS_SPHERICAL}, in which case the specified offset corresponds to
-an offset in angles, or it may be \code{PS_LINEAR}, in which case the
-offset corresponds to a linear offset in a local projection.  The
-offset unit may be in one of \code{PS_ARCSEC}, \code{PS_ARCMIN},
-\code{PS_DEGREE}, and \code{PS_RADIAN}, which specifies the units of
-the offset only.
-
-\begin{verbatim}
-psSphere *psSphereGetOffset(const psSphere *position1, 
-                            const psSphere *position2, 
-                            psSphereOffsetMode mode,
-                            psSphereOffsetUnit unit);
-
-psSphere *psSphereSetOffset(const psSphere *position,
-                            const psSphere *offset,
-                            psSphereOffsetMode mode,
-                            psSphereOffsetUnit unit);
-
-typedef enum {
-    PS_SPHERICAL;                       ///< Offset on a sphere
-    PS_LINEAR;                          ///< Linear offset
-} psSphereOffsetMode;
-
-typedef enum {
-    PS_ARCSEC;                          ///< Arcseconds
-    PS_ARCMIN;                          ///< Arcminutes
-    PS_DEGREE;                          ///< Degrees
-    PS_RADIAN;                          ///< Radians
-} psSphereOffsetUnit;
-\end{verbatim}
-Note that these should propagate the errors appropriately.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%% Astronomical Images and Astrometry
-\include{psLibSDRS_Astrom}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\subsection{Pixel Lists}
-
-Usually an image mask is the best way to carry information about what
-pixels mean what.  However, in the case where the number of pixels in
-which we are interested is limited, it is more efficient to simply
-carry a list of pixels.  An example of this is in the image
-combination code, where we want to perform an operation on a
-relatively small fraction of pixels, and it is inefficient to go
-through an entire mask image checking each pixel.
-
-\begin{verbatim}
-typedef struct {
-    psVector *x;			// x coordinate
-    psVector *y;			// y coordinate
-} psPixels;
-\end{verbatim}
-
-Of course, the size of each of the vectors should match.  In the event
-that they do not match, any function which detects the problem shall
-generate a warning and use the size of the shorter of the vectors as
-the size.  The order in which the pixels are kept is not considered
-important.
-
-\begin{verbatim}
-psImage *psPixelsToMask(psImage *out, const psPixels *pixels, const psRegion *region, unsigned int maskVal);
-psPixels *psMaskToPixels(psPixels *out, const psImage *mask, unsigned int maskVal);
-\end{verbatim}
-
-\code{psPixelsToMask} shall return an image of type U8 with the
-\code{pixels} lying within the specified \code{region} set to the
-\code{maskVal}.  The \code{out} image shall be modified if supplied,
-or allocated and returned if \code{NULL}.  The size of the output
-image shall be \code{region->x1 - region->x0} by \code{region->y1 -
-region->y0}, with \code{out->x0 = region->x0} and \code{out->y0 =
-region->y0}.  In the event that either of \code{pixels} or
-\code{region} are \code{NULL}, the function shall generate an error
-and return \code{NULL}.
-
-\code{psMaskToPixels} shall return a \code{psPixels} consisting of the
-coordinates in the \code{mask} that match the \code{maskVal}.  The
-\code{out} pixel list shall be modified if supplied, or allocated and
-returned if \code{NULL}.  In hte event that \code{mask} is
-\code{NULL}, the function shall generate an error and return
-\code{NULL}.
-
-\begin{verbatim}
-psPixels *psPixelsConcatenate(psPixels *out, const psPixels *pixels);
-\end{verbatim}
-
-\code{psPixelsConcatenate} shall concatenate \code{pixels} onto
-\code{out}.  In the event that \code{out} is \code{NULL}, a new
-\code{psPixels} shall be allocated, and the contents of \code{pixels}
-simply copied in.  If \code{pixels} is \code{NULL}, the function shall
-generate an error and return \code{NULL}.  The function shall take
-care to ensure that there are no duplicate pixels in \code{out} (since
-the order in which the pixels are stored is not important, the values
-may be sorted, allowing the use of a faster algorithm than a linear
-scan).
 
 \begin{verbatim}
@@ -5228,5 +5095,446 @@
 and return \code{NULL}.
 
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{Spherical Rotations}
+
+Spherical rotations represent coordinate transformation in 3-D, as
+well as the effects of precession and nutation.  We need spherical
+rotatations to convert between ICRS, Galactic and Ecliptic
+coordinates, and to determine Alt-Az coordinates for sources.  All of
+these basic spherical transformations represent rotations of the
+spherical coordinate reference.  We specify a general transformation
+function which takes a structure, \code{psSphereRot}, defining the
+transformation between two spherical coordinate systems.  The
+structure contains the elements of a quaternion to represent the
+spherical rotational.  We define two allocators for
+\code{psSphereRot}, one which defines the rotation in terms of the
+coordinate of the pole and the rotation about that pole.  The other
+defines the rotation from the elements of the quaternion.  We also
+specify functions to manipulate \code{psSphereRot} in several useful
+way.
+
+\begin{verbatim}
+typedef struct {
+    double q0;
+    double q1;
+    double q2;
+    double q3;
+} psSphereRot;
+\end{verbatim}
+
+The constructor is defined as follows:
+\begin{verbatim}
+psSphereRot *psSphereRotAlloc(double alphaP, double deltaP, double phiP);
+\end{verbatim}
+where \code{alphaP} and \code{deltaP} define the coordinates in the
+input system of the axis of rotation (the north pole of the output
+system), while \code{phiP} defines the rotation about that pole.  This
+last angle is also equal to 270\degree - $\phi_a$, where $\phi_a$ is
+the longitude in the output system of the ascending node (equatorial
+intersection between the two systems, e.g, the first point of Ares).
+
+The \code{psSphereRot} may also be constructed by supplying the
+elements of the quaternion to the following function:
+\begin{verbatim}
+psSphereRot *psSphereRotQuat(double q0, double q1, double q2, double q3);
+\end{verbatim}
+This function normalizes the quaternion, so the input elements need
+not be normalized.
+
+Spherical coordinates may be transformed by providing the
+transformation and the coordinate in the input system to
+\code{psSphereRot}.  The output pointer may be optionally supplied, or
+if \code{NULL}, is allocated by the function.
+
+\begin{verbatim}
+psSphere *psSphereRotApply(psSphere *out, const psSphereRot *transform, const psSphere *coord);
+\end{verbatim}
+
+The following function combines two rotations, to produce a single
+rotation which is the equivallent of applying the first rotation and
+then the second.  The output rotation may be supplied, or will be
+allocated if \code{NULL}.
+
+\begin{verbatim}
+psSphereRot *psSphereRotCombine(psSphereRot *out, psSphereRot *rot1, psSphereRot *rot2)
+\end{verbatim}
+
+The following function changes the given rotation to its inverse:
+
+\begin{verbatim}
+psSphereRot *psSphereRotInvert(psSphereRot *rot)
+\end{verbatim}
+
+The 3-vector representation of the angles (\code{psCube}) is needed to
+implement these functions, and is useful in other circumstances as
+well.  Two utility functions are provided to convert between the
+angular and 3-vector representations:
+\begin{verbatim}
+psSphere *psCubeToSphere(psCube *cube);
+psCube *psSphereToCube(psSphere *sphere);
+\end{verbatim}
+
+\subsubsection{Offsets}
+We require a function to calculate the offset between two positions on
+the sky, as well as a function to apply an offset to a position.  The
+first determines the offset (RA,Dec) on the sky between two positions.
+The second applies the given offset to the coordinate.  Both an offset
+mode and an offset unit may be defined.  The mode may be either
+\code{PS_SPHERICAL}, in which case the specified offset corresponds to
+an offset in angles, or it may be \code{PS_LINEAR}, in which case the
+offset corresponds to a linear offset in a local projection.  The
+offset unit may be in one of \code{PS_ARCSEC}, \code{PS_ARCMIN},
+\code{PS_DEGREE}, and \code{PS_RADIAN}, which specifies the units of
+the offset only.
+
+\begin{verbatim}
+psSphere *psSphereGetOffset(const psSphere *position1, 
+                            const psSphere *position2, 
+                            psSphereOffsetMode mode,
+                            psSphereOffsetUnit unit);
+
+psSphere *psSphereSetOffset(const psSphere *position,
+                            const psSphere *offset,
+                            psSphereOffsetMode mode,
+                            psSphereOffsetUnit unit);
+
+typedef enum {
+    PS_SPHERICAL;                       ///< Offset on a sphere
+    PS_LINEAR;                          ///< Linear offset
+} psSphereOffsetMode;
+
+typedef enum {
+    PS_ARCSEC;                          ///< Arcseconds
+    PS_ARCMIN;                          ///< Arcminutes
+    PS_DEGREE;                          ///< Degrees
+    PS_RADIAN;                          ///< Radians
+} psSphereOffsetUnit;
+\end{verbatim}
+Note that these should propagate the errors appropriately.
+
+\subsection{Celestial Coordinate Systems}
+
+The following functions simply return the appropriate
+\code{psSphereRot} to convert between predefined spherical
+coordinate systems (i.e., ICRS, Ecliptic and Galactic).  These are
+constructors as well as the above \code{psSphereRotAlloc}.
+%
+\begin{verbatim}
+psSphereRot *psSphereRotICRSToEcliptic(psTime *time);
+psSphereRot *psSphereRotEclipticToICRS(psTime *time);
+psSphereRot *psSphereRotICRSToGalactic(void);
+psSphereRot *psSphereRotGalacticToICRS(void);
+\end{verbatim}
+
+\subsection{Earth Orientation Calculations}
+
+One of the critical sets of calculations in astronomy is the sequence
+of steps needed to convert between the celestial coordinates of an
+object and the observed coordinates of the object.  This problem is
+best divided into two major components: transformation between the
+celestial sphere and coordinates relative to the surface of the solid
+earth, excluding the effects of the atmosphere, and compensation for
+the effects of the atmosphere.  In this section, we address the first
+of these two transformations: the Earth Orientation Calculations.
+
+The Earth Orientation Calculations are further subdivided into several
+steps, illustrated in Figure~\ref{CoordinateSystems} .  Celestial
+coordinates are defined in the International Celestial Reference
+System (ICRS), which has the solar barycenter as its reference
+position and velocity.  The next coordinate system is the Geocentric
+Celestial Reference System (GCRS), which uses the earth barycenter as
+a reference.  The transformation between these two includes the
+abberation due to the Earth's velocity, the parallax of the object,
+which depends on both the Earth's position and the distance to the
+object of interest, and the general relativistic correction for the
+bending of light as it approaches the Earth.
+
+The next set of transformations compenstate for the 3-D rotation of
+the Earth on various timescales, including the effects of precession,
+nutation, and simple solid-body rotation.  These calculations can be
+performed using different amounts of information for higher levels of
+precision.  Since the Earth's rotation is constantly affected by
+stochastic processes (weather, earthquakes, etc), these conversions
+are constantly modified by observations reported by authoratative
+sources such as the US Naval Observatory.  The target of this
+transformation is the International Terrestrial Reference System
+(ITRS), which is fixed with respect to the Earth's crust.  This
+transformation is subdivided into slow precesion and nutation
+(yielding the coordinate system CIP/CEO), followed by the Earth's
+rotation (yielding the coordinate system CIP/TEO), and finally
+corrections for the short-period motion of the Earth's pole.  
+
+\subsubsection{Transformation from ICRS to GCRS}
+
+\tbd{we need a function to construct the direction and speed elements
+  given the time}.
+
+\tbd{supply the velocity as an un-normalized 3 vector?}
+
+\paragraph{Aberration}
+The following function calculates the \code{apparent} position of a
+star, given its \code{actual} position and the velocity vector of the
+observer, represented as a speed and a direction:
+\begin{verbatim}
+psAberration(psSphere *apparent, psSphere *actual, psSphere direction, double speed);
+\end{verbatim}
+The \code{actual} and \code{apparent} positions are represented as
+\code{psSphere} entries, as is the \code{direction} of motion.  The
+speed in that direction is given in units of the speed of light.
+
+\paragraph{Gravitational Deflection}
+
+\paragraph{Parallax}
+
+\begin{verbatim}
+double psEOC_ParallaxFactor(psSphere *coords, psTime *time);
+\end{verbatim}
+Calculate the parallax factor for the given position and time.
+
+\subsubsection{Transformation from GCRS to ITRS}
+
+\paragraph{Precession/Nutation}
+
+The following routine calculates the components of the rotation
+between the CEO and GCRS frames, $X$, $Y$, and $s$, using to the
+IAU2000A precession \& nutation model:
+%
+\begin{verbatim}
+psSphere *psEOC_PrecessionModel(double *s, const psTime *time)
+\end{verbatim}
+%
+The input to this function is the desired \code{time}, which may be
+represented in any format other than UT1.  This routine must give
+results identical to the IERS XYS2000A subroutine within the limits of
+machine accuracy.
+
+The following function provides interpolated corrections to $X$ and
+$Y$ from the tables provided by the IERS, just as it does for UT1 and
+polar motion.  
+
+\begin{verbatim}
+psSphere *psEOC_GetPolarCorr(const psTime *time, psTimeBulletin bulletin);
+\end{verbatim}
+
+The polar correction is applied to the $X$ and $Y$ elements of the
+rotation to provide higher accuracy.  The spherical rotation term is
+generated by providing the three elements of the rotation to the
+following function:
+\begin{verbatim}
+psSphereRot *psSphereRot_CEOtoGCRS(double s, const psSphere *pole)
+\end{verbatim}
+The retulting \code{psSphereRot} may be used to determine the rotation
+from CIP/CEO to GCRS.  This function must give results identical to
+the IERS BPN2000, within the limits of machine accuracy.
+
+\paragraph{Earth Rotation}
+
+The following routine calculates the rotation of the Earth about the CIP:
+\begin{verbatim}
+psSphereRot *psSphereRot_TEOtoCEO(const psTime *time)
+\end{verbatim}
+The IERS code to create the comparable rotation is embedded in
+T2C2000, with the Earth Rotation Angle calculated by ERA2000.
+
+\paragraph{Polar Motion}
+
+The following function provides interpolated values of the polar
+motion components, $x_p$ and $y_p$, extracted from the IERS tables.  
+\begin{verbatim}
+psSphere *psEOC_GetPoleCoords(const psTime *time, psTimeBulletin bulletin);
+\end{verbatim}
+
+The following function provides tidal corrections to the polar motion
+components, $x_p$ and $y_p$, using the Ray model of Simon et al (see
+ADD).
+\begin{verbatim}
+psSphere *psEOC_TidePolarCorr(const psTime *time);
+\end{verbatim}
+
+The following function provides the additional corrections due to nutation
+terms with periods less than or equal to two days:
+\begin{verbatim}
+psSphere *psEOC_NutationCorr(psTime *time);
+\end{verbatim}
+
+The following function should generate the \code{psSphereRot} transform from
+ITRS to CIP/TEO:
+\begin{verbatim}
+psSphereRot *psSphereRot_ITRStoTEO(psSphere pole, psTime *time);
+\end{verbatim}
+The time argument should be used to internally calculate $s'$.
+This function should give identical results to the IERS POM2000 subroutine.
+
+\subsubsection{Earth Orientation Wrappers}
+
+The following function generates the complete spherical rotation to
+account for precession between two times.  If \code{NULL} is provided
+for either time, it is assumed to have the reference equinox value of
+J2000.
+\begin{verbatim}
+psSphere *psSpherePrecess(const psTime *fromTime, const psTime *toTime, psPrecessMethod mode);
+\end{verbatim}
+The mode argument is used to specify the level of detail used in the
+calculation.
+
+\begin{verbatim}
+typedef enum {
+  PS_PRECESS_ROUGH,
+  PS_PRECESS_COMPLETE,
+  PS_PRECESS_IAU2000A,
+} psPrecessMethod;
+\end{verbatim}
+
+\subsection{Atmospheric Effects}
+
+\tbd{The ATM effects components should be deferred until we clean up
+  the refraction definitions}
+
+A-priori astrometric transformations between the telescope orientation
+(Alt/Az) and the predicted stellar coordinates above the atmosphere
+(DEC/HA) requires several pieces of information describing the current
+environmental conditions.  These quantities are consistent across an
+image, and may vary only slowly with time.  Pre-computing these
+quantities for exposures means that subsequent transformations are
+faster.  The structure below carries the environmental data of interest.
+For historical reasons, this structure is known colloquially as ``the
+Grommit''.
+
+\tbd{this structure needs to be modified to correspond to what we
+  actually need to carry around for the atmosphere functions}
+
+\tbd{provide a single Grommit to carry around all EOC + ATM
+  pre-calculated entries and a separate structure for ATM effect?}
+
+\begin{verbatim}
+typedef struct {
+    const double latitude;              ///< geodetic latitude (radians)
+    const double longitude;             ///< longitude + ... (radians)
+    const double height;                ///< height (HM)
+    const double abberationMag;         ///< magnitude of diurnal aberration vector
+    const double temperature;           ///< ambient temperature (TDK)
+    const double pressure;              ///< pressure (PMB)
+    const double humidity;              ///< relative humidity (RH)
+    const double wavelength;            ///< wavelength (WL)
+    const double lapseRate;             ///< lapse rate (TLR)
+    const double refractA, refractB;    ///< refraction constants A and B (radians)
+    const double siderealTime;          ///< local apparent sidereal time (radians)
+} psGrommit;
+\end{verbatim}
+
+The \code{psGrommit} is calculated from telescope information for the
+particular exposure, \code{exp}:
+\begin{verbatim}
+psGrommit *psGrommitAlloc(const psExposure *exp);
+\end{verbatim}
+
+\tbd{these functions probably need to take the ATM structure}
+
+We require additional functions to perform general functions which
+will be useful for astrometry.  Given coordinates on the sky, we
+need to get the airmass, the parallactic angle, and an estimate of
+the atmospheric refraction.
+
+\begin{verbatim}
+float psGetAirmass(const psSphere *coord, psTime *lst, float height);
+\end{verbatim}
+which returns the airmass for a given position and local sidereal time
+(\code{lst}).
+
+\begin{verbatim}
+float psGetParallactic(const psSphere *coord, double siderealTime);
+\end{verbatim}
+which returns the parallactic angle for a given position and sidereal time.
+
+\begin{verbatim}
+float psGetRefraction(float colour,            ///< Colour of object
+                      psPhotSystem colorPlus,  ///< Colour reference
+                      psPhotSystem colorMinus, ///< Colour reference
+                      const psExposure *exp);  ///< Telescope pointing information
+\end{verbatim}
+which provides an estimate of the atmospheric refraction, along the parallactic angle.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Fixed Pattern}
+
+The fixed pattern is a correction to the general astrometric solution
+formed by summing the residuals from many observations.  The intent is
+to correct for higher-order distortions in the camera system on a
+coarse grid (larger than individual pixels, but smaller than a single
+cell).  Hence, in addition to the offsets, we need to specify the size
+and scale of the grid in $x$ and $y$, as well as the origin of the
+grid.
+
+\begin{verbatim}
+typedef struct {
+    int nX, nY;                         ///< Number of elements in x and y
+    double x0, y0;                      ///< Position of 0,0 corner on focal plane
+    double xScale, yScale;              ///< Scale of the grid
+    double **x, **y;                    ///< The grid of offsets in x and y
+} psFixedPattern;
+\end{verbatim}
+
+The constructor for \code{psFixedPattern} shall be:
+\begin{verbatim}
+psFixedPattern *psFixedPatternAlloc(double x0,        double y0, 
+                                    double xScale,    double yScale,
+                                    const psImage *x, const psImage *y);
+\end{verbatim}
+Here, \code{x0}, \code{y0}, \code{xScale} and \code{yScale} have the
+same meaning as in the \code{psFixedPattern} structure.  Note that the
+values of the fixed pattern offsets are specified as images, the
+values from which need to be copied into the \code{double **x} and
+\code{double **y} of \code{psFixedPattern}, and that the number of
+elements may be derived from the size of the images.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
+
+\subsection{Projections}
+
+We require functions to convert between spherical and linear
+coordinate systems based on a variety of projections.  The required
+projections include:
+\begin{itemize}
+\item TAN
+\item SIN
+\item AIT
+\item PAR
+\end{itemize}
+
+We specify the following structure \code{psProjection} to define the
+parameters of the projection:
+\begin{verbatim}
+typedef struct {
+    double R, D;                         ///< coordinates of projection center
+    double Xs, Ys;                       ///< plate-scale in X and Y directions
+    psProjectionType type;               ///< projection type
+} psProjection;
+\end{verbatim}
+
+The projection type is defined by the following enumerated type \code{psProjectionType}:
+\begin{verbatim}
+typedef enum {                          ///< type of val is:
+    PS_PROJ_TAN,                        ///< Tangent projection
+    PS_PROJ_SIN,                        ///< Sine projection
+    PS_PROJ_AIT,                        ///< Aitoff projection
+    PS_PROJ_PAR,                        ///< Par projection
+    PS_PROJ_NTYPE                       ///< Number of types; must be last
+} psProjectionType;
+\end{verbatim}
+
+The constructor is straight-forward:
+\begin{verbatim}
+psProjection *psProjectionAlloc(double R, double D, double Xs, double Ys, psProjectionType type);
+\end{verbatim}
+
+The following functions will project and deproject (respectively)
+spherical coordinates:
+
+\begin{verbatim}
+psPlane  *psProject(const psSphere *coord, const psProjection *projection);
+psSphere *psDeproject(const psPlane *coord, const psProjection *projection);
+\end{verbatim}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
 
 \subsection{Photometry}
@@ -5298,5 +5606,8 @@
 M_{\rm pM} - pA, M_{\rm sP} - M_{\rm sM} - sA)$.
 
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Astronomical Images and Astrometry
+\include{psLibSDRS_Astrom}
 
 \subsection{Astronomical objects}
@@ -5329,4 +5640,5 @@
 \appendix
 
+\pagebreak
 \section{Configuration File Test Inputs}
 \label{sec:configtest}
