Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/Makefile
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/Makefile	(revision 34115)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/Makefile	(revision 34116)
@@ -20,6 +20,8 @@
 dvomerge_client : $(BIN)/dvomerge_client.$(ARCH)
 dvoconvert      : $(BIN)/dvoconvert.$(ARCH)
+dvoverify       : $(BIN)/dvoverify.$(ARCH)
+dvoverify_client : $(BIN)/dvoverify_client.$(ARCH)
 
-all: dvomerge dvomerge_client dvoconvert dvosecfilt
+all: dvomerge dvomerge_client dvoconvert dvosecfilt dvoverify dvoverify_client
 
 #  $(SRC)/dvomergeContinue.$(ARCH).o
@@ -49,5 +51,4 @@
 
 $(DVOMERGE)  : $(INC)/dvomerge.h
-
 $(BIN)/dvomerge.$(ARCH) : $(DVOMERGE)
 
@@ -72,5 +73,4 @@
 
 $(DVOMERGE_CLIENT) : $(INC)/dvomerge.h
-
 $(BIN)/dvomerge_client.$(ARCH) : $(DVOMERGE_CLIENT)
 
@@ -87,5 +87,4 @@
 
 $(DVOCONVERT)  : $(INC)/dvomerge.h
-
 $(BIN)/dvoconvert.$(ARCH) : $(DVOCONVERT)
 
@@ -99,5 +98,4 @@
 
 $(DVOSECFILT)  : $(INC)/dvomerge.h
-
 $(BIN)/dvosecfilt.$(ARCH) : $(DVOSECFILT)
 
@@ -116,15 +114,25 @@
 
 $(DVOREPAIR)  : $(INC)/dvomerge.h
-
 $(BIN)/dvorepair.$(ARCH) : $(DVOREPAIR)
 
 DVOVERIFY = \
-$(SRC)/dvoverify.$(ARCH).o
+$(SRC)/dvoverify.$(ARCH).o \
+$(SRC)/dvoverify_args.$(ARCH).o \
+$(SRC)/dvoverify_catalogs.$(ARCH).o \
+$(SRC)/dvoverify_utils.$(ARCH).o
 
-$(DVOVERIFY)  : $(INC)/dvomerge.h
-
+$(DVOVERIFY)  : $(INC)/dvoverify.h
 $(BIN)/dvoverify.$(ARCH) : $(DVOVERIFY)
 
-INSTALL = dvomerge dvomerge_client dvoconvert dvosecfilt dvorepair dvoverify
+DVOVERIFY_CLIENT = \
+$(SRC)/dvoverify_client.$(ARCH).o \
+$(SRC)/dvoverify_args.$(ARCH).o \
+$(SRC)/dvoverify_catalogs.$(ARCH).o \
+$(SRC)/dvoverify_utils.$(ARCH).o
+
+$(DVOVERIFY_CLIENT) : $(INC)/dvoverify.h
+$(BIN)/dvoverify_client.$(ARCH) : $(DVOVERIFY_CLIENT)
+
+INSTALL = dvomerge dvomerge_client dvoconvert dvosecfilt dvorepair dvoverify dvoverify_client
 
 # dependancy rules for binary code #########################
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/include/dvomerge.h	(revision 34115)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/include/dvomerge.h	(revision 34116)
@@ -17,6 +17,4 @@
 # include <glob.h>
 
-# define DVO_MAX_PATH 1024
-
 int    PARALLEL;
 int    PARALLEL_MANUAL;
@@ -25,5 +23,4 @@
 int    HOST_ID;
 char  *HOSTDIR;
-
 
 int    VERBOSE;
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/include/dvoverify.h
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/include/dvoverify.h	(revision 34116)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/include/dvoverify.h	(revision 34116)
@@ -0,0 +1,49 @@
+# include <ohana.h>
+# include <dvo.h>
+# include <signal.h>
+# include <sys/time.h>
+# include <time.h>
+# include <zlib.h>
+
+/* solaris requires both of these instead of ip.h:
+   # include <sys/socket.h>
+   # include <netinet/in.h>
+*/
+
+/* linux is happy with this, not solaris */
+# include <netinet/ip.h>
+# include <netdb.h>
+# include <arpa/inet.h>
+# include <glob.h>
+
+# define DEBUG 0
+
+int    PARALLEL;
+int    PARALLEL_MANUAL;
+int    PARALLEL_SERIAL;
+
+char  *CATDIR;
+
+int    HOST_ID;
+char  *HOSTDIR;
+
+char  *RESULTS;
+
+int    CHECKSORTED;
+int    VERBOSE;
+int    NNotSorted;
+int    CHECK_TOPLEVEL;
+
+SkyRegion UserPatch;
+
+int dvoverify_args (int *argc, char **argv);
+int dvoverify_client_args (int *argc, char **argv);
+
+int dvoverify_catalogs (SkyList *skylist, int *Nbad);
+int dvoverify_parallel (SkyList *skylist, int *Nbad);
+
+int dvoverify_single (char *filename);
+
+int VerifyTableFile (char *filename);
+int CheckCatalogIndexes (char *filename,  SkyRegion *region);
+
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/args.c
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/args.c	(revision 34115)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/args.c	(revision 34116)
@@ -50,6 +50,4 @@
   }
 
-  // XXX for the moment, make this selection manual.  it needs to be automatic 
-  // based on the state of the SkyTable
   PARALLEL = FALSE;
   if ((N = get_argument (*argc, argv, "-parallel"))) {
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify.c
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify.c	(revision 34115)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify.c	(revision 34116)
@@ -1,3 +1,3 @@
-# include "dvomerge.h"
+# include "dvoverify.h"
 
 /* things we can verify easily:
@@ -8,108 +8,21 @@
 */
 
-int VerifyTableFile (char *filename);
-int CheckCatalogIndexes (char *catdir, char *filename,  SkyRegion *region);
-
-# define DEBUG 0
-
-int VERBOSE = FALSE;
-int NNotSorted = 0;
-
 int main (int argc, char **argv) {
 
-  char filename[1024];
+  SkyTable *sky;
+  SkyList *skylist;
 
-  int N, Nbad;
-  off_t i;
-  SkyTable *insky;
-  SkyList *inlist;
-  SkyRegion UserPatch;
-  // Catalog catalog;
+  // check various options
+  dvoverify_args (&argc, argv);
+  CATDIR = argv[1];
 
-  int CHECKSORTED;
-
-  if ((N = get_argument (argc, argv, "-v"))) {
-    VERBOSE = TRUE;
-    remove_argument (N, &argc, argv);
-  }
-  if ((N = get_argument (argc, argv, "-verbose"))) {
-    VERBOSE = TRUE;
-    remove_argument (N, &argc, argv);
-  }
-  if ((N = get_argument (argc, argv, "-s"))) {
-    CHECKSORTED = TRUE;
-    remove_argument (N, &argc, argv);
-  }
-  if ((N = get_argument (argc, argv, "-sorted"))) {
-    CHECKSORTED = TRUE;
-    remove_argument (N, &argc, argv);
-  }
-
-  if ((N = get_argument (argc, argv, "-cpt"))) {
-    remove_argument (N, &argc, argv);
-    char *filename = strcreate (argv[N]);
-    remove_argument (N, &argc, argv);
-
-    int isBad = FALSE;
-
-    if (!VerifyTableFile (filename)) {
-      fprintf (stderr, "bad average table %s\n", filename);
-      isBad = TRUE;
-    }
-
-    // change last 't' to 's':
-    int Nlast;
-    Nlast = strlen(filename) - 1;
-    filename[Nlast] = 's';
-    if (!VerifyTableFile (filename)) {
-      fprintf (stderr, "bad secfilt table %s\n", filename);
-      isBad = TRUE;
-    }
-
-    // change last 't' to 's':
-    Nlast = strlen(filename) - 1;
-    filename[Nlast] = 'm';
-    if (!VerifyTableFile (filename)) {
-      fprintf (stderr, "bad measure table %s\n", filename);
-      isBad = TRUE;
-    }
-
-    if (isBad) exit (1);
-    exit (0);
-  }
-
-  // restrict to a portion of the sky
-  UserPatch.Rmin = 0;
-  UserPatch.Rmax = 360;
-  UserPatch.Dmin = -90;
-  UserPatch.Dmax = +90;
-  if ((N = get_argument (argc, argv, "-region"))) {
-    remove_argument (N, &argc, argv);
-    UserPatch.Rmin = atof (argv[N]);
-    remove_argument (N, &argc, argv);
-    UserPatch.Rmax = atof (argv[N]);
-    remove_argument (N, &argc, argv);
-    UserPatch.Dmin = atof (argv[N]);
-    remove_argument (N, &argc, argv);
-    UserPatch.Dmax = atof (argv[N]);
-    remove_argument (N, &argc, argv);
-  }
-
-  if (argc != 2) {
-    fprintf (stderr, "USAGE: dvoverify (catdir) [-region Rmin Rmax Dmin Dmax] [-v] [-s]\n\n");
-    fprintf (stderr, "  -v : VERBOSE\n");
-    fprintf (stderr, "  -s : checks if sorted, return error if not\n");
-    fprintf (stderr, "  (catdir) : database of interest\n");
-    exit (2);
-  }
-
-  char *catdir = argv[1];
-
-  Nbad = 0;
+  int Nbad = 0;
 
   // XXX make this step optional
-  if (1) {
+  if (CHECK_TOPLEVEL) {
+    char filename[DVO_MAX_PATH];
+
     // check the photcode table
-    sprintf (filename, "%s/Photcodes.dat", catdir);
+    sprintf (filename, "%s/Photcodes.dat", CATDIR);
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -117,5 +30,5 @@
 
     // check the skytable
-    char *skyfile = SkyTableFilename (catdir);
+    char *skyfile = SkyTableFilename (CATDIR);
     if (!VerifyTableFile (skyfile)) {
       Nbad ++;
@@ -123,5 +36,5 @@
 
     // check the image table
-    sprintf (filename, "%s/Images.dat", catdir);
+    sprintf (filename, "%s/Images.dat", CATDIR);
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -130,39 +43,10 @@
 
   // load the sky table for the existing database
-  insky = SkyTableLoadOptimal (catdir, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
-  myAssert(insky, "can't read SkyTable");
-  SkyTableSetFilenames (insky, catdir, "cpt");
-  inlist = SkyListByPatch (insky, -1, &UserPatch);
+  sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(sky, "can't read SkyTable");
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
   
-  // loop over all catalogs, save to output catalogs
-  for (i = 0; i < inlist[0].Nregions; i++) {
-    if (!inlist[0].regions[i][0].table) continue;
-    if (i % 1000 == 0) fprintf (stderr, ".");
-
-    // sprintf (filename, "%s/%s.cpt", catdir, inlist[0].regions[i][0].name);
-    if (!VerifyTableFile (inlist[0].filename[i])) {
-      Nbad ++;
-    }
-
-    sprintf (filename, "%s/%s.cps", catdir, inlist[0].regions[i][0].name);
-    if (!VerifyTableFile (filename)) {
-      Nbad ++;
-    }
-
-    sprintf (filename, "%s/%s.cpm", catdir, inlist[0].regions[i][0].name);
-    if (!VerifyTableFile (filename)) {
-      Nbad ++;
-    }
-
-    if (!CheckCatalogIndexes(catdir, inlist[0].filename[i], inlist[0].regions[i])){
-      Nbad ++;
-    }
-
-    // exit immediately if any file are unsorted and we require sorted tables
-    if (CHECKSORTED && NNotSorted) {
-      fprintf (stderr, "ERROR: files are not sorted\n");
-      exit (1);
-    }
-  }
+  dvoverify_catalogs (skylist, &Nbad);
 
   if (Nbad > 0) {
@@ -178,237 +62,2 @@
 }
 
-// is this file a consistent FITS file?
-int VerifyTableFile (char *filename) {
-
-  int status, Next;
-  off_t Nbytes;
-  Header header;
-
-  struct stat fileStats;
-  FILE *file;
-
-  // does the file exist?
-  status = stat (filename, &fileStats);
-  if (status) {
-    // some error accessing the file.  there is only one acceptable error: file not found
-    switch (errno) {
-      case ENOENT:
-	if (DEBUG) fprintf (stderr, "file does not exist, skipping %s\n", filename);
-	return TRUE;
-      case ENOMEM:
-	fprintf (stderr, "Out of memory: %s\n", filename);
-	return TRUE;
-      case EACCES:
-	fprintf (stderr, "Permission error on %s\n", filename);
-	return FALSE;
-      case EFAULT:
-	fprintf (stderr, "Bad address: %s\n", filename);
-	return FALSE;
-      case ELOOP:
-	fprintf (stderr, "Too many symbolic links encountered while traversing the path: %s\n", filename);
-	return FALSE;
-      case ENAMETOOLONG:
-	fprintf (stderr, "File name too long: %s\n", filename);
-	return FALSE;
-      case ENOTDIR:
-	fprintf (stderr, "A component of the path is not a directory: %s\n", filename);
-	return FALSE;
-      case EOVERFLOW:
-	fprintf (stderr, "file too large for program version: %s\n", filename);
-	return FALSE;
-      default:
-	fprintf (stderr, "unknown error: %s\n", filename);
-	return FALSE;
-    }
-  }
-
-  // does it have any data?
-  if (fileStats.st_size == 0) {
-    fprintf (stderr, "file is empty: %s\n", filename);
-    return FALSE;
-  }
-
-  // can we open it?
-  file = fopen(filename, "r");
-  if (!file) {
-    fprintf (stderr, "unable to open valid file: %s\n", filename);
-    return FALSE;
-  }
-
-  // scan all extentions
-  Nbytes = 0;
-  Next = -1;
-  if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
-  while (Nbytes < fileStats.st_size) {
-
-    // Check on the PHU
-    if (!gfits_fread_header (file, &header)) {
-      if (Next == -1) {
-	fprintf (stderr, "unable to read PHU header for %s\n", filename);
-      } else {
-	fprintf (stderr, "unable to read header for %s, extension %d (or file has excess bytes)\n", filename, Next);
-      }
-      fclose(file);
-      return (FALSE);
-    }
-
-    // move to TBL header
-    Nbytes += header.datasize + gfits_data_size (&header);
-    if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
-    if (Nbytes > fileStats.st_size) {
-      fprintf (stderr, "file is short ("OFF_T_FMT" vs "OFF_T_FMT"): %s\n", Nbytes, fileStats.st_size, filename);
-      gfits_free_header(&header);
-      fclose (file);
-      return FALSE;
-    }
-    gfits_free_header(&header);
-
-    status = fseeko (file, Nbytes, SEEK_SET);
-    if (status) {
-      switch (errno) {
-	case EBADF:
-	  fprintf (stderr, "something wrong with file handle: %s\n", filename);
-	  fclose (file);
-	  return FALSE;
-	case EINVAL:
-	  fprintf (stderr, "invalid offset: %s\n", filename);
-	  fclose (file);
-	  return FALSE;
-	default:
-	  fprintf (stderr, "other error in fseeko: %s\n", filename);
-	  fclose (file);
-	  return FALSE;
-      }
-    }
-    Next ++;
-  }
-  if (DEBUG) fprintf (stderr, "file is good: %s\n", filename);
-  fclose (file);
-  return TRUE;
-}
-
-// CheckCatalogIndexes(catdir, inlist[0].regions[i][0].name);
-
-int CheckCatalogIndexes (char *catdir, char *filename,  SkyRegion *region) {
-
-  Catalog catalog;
-  int i, j, m, status;
-
-  status = TRUE;
-
-  // set the parameters which guide catalog open/load/create
-  catalog.filename  = filename;
-  catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
-  catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
-  catalog.catflags  = LOAD_AVES | LOAD_MEAS;
-  catalog.Nsecfilt  = 0;
-  
-  // an error exit status here is a significant error (disk I/O or file access)
-  if (!dvo_catalog_open (&catalog, region, VERBOSE, "r")) {
-    fprintf (stderr, "ERROR: failure to open catalog file %s\n", catalog.filename);
-    return FALSE;
-  }
-
-  // Naves_disk == 0 implies an empty catalog file, skip empty catalogs
-  if (catalog.Naves_disk == 0) {
-    dvo_catalog_unlock (&catalog);
-    dvo_catalog_free (&catalog);
-    return TRUE;
-  }
-
-  // if the table is SORTED, then the following can be checked
-  // check the following:
-  // measure[j].averef -> average[averef]
-  // measure[j].objID = average[averef].objID
-  // measure[j].catID = average[averef].catID
-  // measure[j].measureOffset < Nmeasure
-  // \sum average[].Nmeasure = Nmeasure
-
-  // if the table is NOT SORTED, we have a subset of checks we can make
-  if (!catalog.sorted) {
-    fprintf (stderr, "!");
-    dvo_catalog_unlock (&catalog);
-    dvo_catalog_free (&catalog);
-    NNotSorted++;
-    if (VERBOSE) fprintf (stderr, "file is not sorted: %s\n", filename);
-    return TRUE;
-  }
-
-  int NmeasureTotal = 0;
-  int measureOffsetOK = TRUE;
-  for (i = 0; i < catalog.Naverage; i++) {
-    NmeasureTotal += catalog.average[i].Nmeasure;
-    if (VERBOSE && !(NmeasureTotal <= catalog.Nmeasure)) {
-      fprintf (stderr, "NmeasureTotal > catalog.Nmeasure: %d %d %d\n", i, catalog.average[i].Nmeasure, (int) catalog.Nmeasure);
-    }
-    measureOffsetOK &= (catalog.average[i].measureOffset < catalog.Nmeasure);
-    if (VERBOSE && !(catalog.average[i].measureOffset < catalog.Nmeasure)) {
-      fprintf (stderr, "measureOffset >= catalog.Nmeasure: %d %d %d\n", i, catalog.average[i].measureOffset, (int) catalog.Nmeasure);
-    }
-    measureOffsetOK &= (catalog.average[i].measureOffset + catalog.average[i].Nmeasure <= catalog.Nmeasure);
-    if (VERBOSE && !(catalog.average[i].measureOffset + catalog.average[i].Nmeasure <= catalog.Nmeasure)) {
-      fprintf (stderr, "measureOffset + Nmeasure > catalog.Nmeasure : %d %d %d\n", i, catalog.average[i].Nmeasure, (int) catalog.Nmeasure);
-    }
-  }
-
-  if (!measureOffsetOK) {
-    fprintf (stderr, "ERROR: catalog %s has an invalid measureOffset\n", catalog.filename);
-    status = FALSE;
-  }
-
-  if (NmeasureTotal != catalog.Nmeasure) {
-    fprintf (stderr, "ERROR: catalog %s has an invalid Nmeasure\n", catalog.filename);
-    status = FALSE;
-  }
-
-  if (!status) {
-    dvo_catalog_unlock (&catalog);
-    dvo_catalog_free (&catalog);
-    return (status);
-  }
-
-  int objIDsOK = TRUE;
-  int catIDsOK = TRUE;
-  int averefOK = TRUE;
-
-  for (i = 0; i < catalog.Naverage; i++) {
-    m = catalog.average[i].measureOffset;
-    for (j = 0; j < catalog.average[i].Nmeasure; j++) {
-      objIDsOK &= (catalog.average[i].objID == catalog.measure[m+j].objID);
-      catIDsOK &= (catalog.average[i].catID == catalog.measure[m+j].catID);
-      averefOK &= (catalog.measure[m+j].averef == i);
-    }
-  }
-    
-  if (!objIDsOK) {
-    fprintf (stderr, "ERROR: catalog %s has invalid obj IDs\n", catalog.filename);
-    status = FALSE;
-  }
-  if (!catIDsOK) {
-    fprintf (stderr, "ERROR: catalog %s has invalid cat IDs\n", catalog.filename);
-    status = FALSE;
-  }
-  if (!averefOK) {
-    fprintf (stderr, "ERROR: catalog %s has invalid averef values\n", catalog.filename);
-    status = FALSE;
-  }
-
-//  for (i = 0; i < catalog.Naverage; i++) {
-//    m = catalog.average[i].measureOffset;
-//    for (j = 0; i < catalog.Nmeasure; i++) {
-//      objIDsOK &= (catalog.average[i].objID == catalog.measure[m+j].objID);
-//      catIDsOK &= (catalog.average[i].catID == catalog.measure[m+j].catID);
-//      averefOK &= (catalog.measure[m+j].averef = i);
-//    }
-//  }
-
-  dvo_catalog_unlock (&catalog);
-  dvo_catalog_free (&catalog);
-
-  return status;
-}
-
-// gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
-// gfits_scan(&cpmHeaderTBL, "NAXIS2", "%d", 1, &Nrows);
-    
-  
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_args.c
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_args.c	(revision 34116)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_args.c	(revision 34116)
@@ -0,0 +1,180 @@
+# include "dvoverify.h"
+
+int dvoverify_args (int *argc, char **argv) {
+
+  int N;
+
+  VERBOSE = FALSE;
+  CHECKSORTED = FALSE;
+  NNotSorted = 0;
+
+  if ((N = get_argument (*argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-verbose"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-s"))) {
+    CHECKSORTED = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-sorted"))) {
+    CHECKSORTED = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  if ((N = get_argument (*argc, argv, "-cpt"))) {
+    remove_argument (N, argc, argv);
+    char *filename = strcreate (argv[N]);
+    remove_argument (N, argc, argv);
+
+    if (*argc != 1) {
+      fprintf (stderr, "USAGE: dvoverify -cpt filename.cpt\n");
+      fprintf (stderr, "OPTIONS: -v -verbose -s -sorted\n");
+      fprintf (stderr, "NOTE: -parallel and other options not allowed for -cpt mode\n");
+      exit (2);
+    }
+
+    int status = dvoverify_single (filename);
+    exit (!status);
+  }
+
+  CHECK_TOPLEVEL = TRUE;
+  if ((N = get_argument (*argc, argv, "-skip-toplevel"))) {
+    CHECK_TOPLEVEL = FALSE;
+    remove_argument (N, argc, argv);
+  }
+
+  // restrict to a portion of the sky
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (*argc, argv, "-region"))) {
+    remove_argument (N, argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  HOST_ID = 0;
+  HOSTDIR = NULL;
+
+  PARALLEL = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel"))) {
+    PARALLEL = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  // this is a test mode : rather than launching the remote jobs and waiting for completion,
+  // relphot will simply list the remote command and wait for the user to signal completion
+  PARALLEL_MANUAL = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel-manual"))) {
+    PARALLEL = TRUE; // -parallel-manual implies -parallel
+    PARALLEL_MANUAL = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  // this is a test mode : rather than launching the relphot_client jobs remotely, they are 
+  // run in serial via 'system'
+  PARALLEL_SERIAL = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel-serial"))) {
+    if (PARALLEL_MANUAL) {
+      fprintf (stderr, "ERROR: cannot mix -parallel-manual and -parallel-serial\n");
+      exit (1);
+    }
+    PARALLEL = TRUE; // -parallel-serial implies -parallel
+    PARALLEL_SERIAL = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  if (*argc != 2) {
+    fprintf (stderr, "USAGE: dvoverify (catdir) [-region Rmin Rmax Dmin Dmax] [-v] [-s]\n\n");
+    fprintf (stderr, "  (catdir) : database of interest\n");
+    fprintf (stderr, "  -v : VERBOSE\n");
+    fprintf (stderr, "  -s : checks if sorted, return error if not\n");
+    fprintf (stderr, "  -region : limit checks to specified region\n");
+    fprintf (stderr, "  -parallel : run in parallel across cluster\n");
+    fprintf (stderr, "  -skip-toplevel : do not check top-level files (Images, Photcodes, etc)\n\n");
+    fprintf (stderr, "  OR : -cpt (filename)\n");
+    exit (2);
+  }
+
+  return TRUE;
+}
+
+int dvoverify_client_args (int *argc, char **argv) {
+
+  int N;
+
+  VERBOSE = FALSE;
+  CHECKSORTED = FALSE;
+  NNotSorted = 0;
+
+  if ((N = get_argument (*argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-s"))) {
+    CHECKSORTED = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  // restrict to a portion of the sky
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (*argc, argv, "-region"))) {
+    remove_argument (N, argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  // by definition, the client is not parallel 
+  PARALLEL = FALSE;
+  PARALLEL_MANUAL = FALSE;
+  PARALLEL_SERIAL = FALSE;
+
+  HOST_ID = 0;
+  if ((N = get_argument (*argc, argv, "-hostID"))) {
+    remove_argument (N, argc, argv);
+    HOST_ID = atoi (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  HOSTDIR = NULL;
+  if ((N = get_argument (*argc, argv, "-hostdir"))) {
+    remove_argument (N, argc, argv);
+    HOSTDIR = strcreate (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  RESULTS = NULL;
+  if ((N = get_argument (*argc, argv, "-results"))) {
+    remove_argument (N, argc, argv);
+    RESULTS = strcreate (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  if (!HOST_ID || !HOSTDIR || (*argc != 2)) {
+    fprintf (stderr, "USAGE: dvoverify_client (catdir) -results (file) -hostID ID -hostdir DIR [-region Rmin Rmax Dmin Dmax] [-v] [-s]\n\n");
+    fprintf (stderr, "  (catdir) : database of interest\n");
+    fprintf (stderr, "  -v : VERBOSE\n");
+    fprintf (stderr, "  -s : checks if sorted, return error if not\n");
+    exit (2);
+  }
+
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_catalogs.c
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_catalogs.c	(revision 34116)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_catalogs.c	(revision 34116)
@@ -0,0 +1,141 @@
+# include "dvoverify.h"
+
+int dvoverify_catalogs (SkyList *skylist, int *nbad) {
+
+  int i;
+  char filename[DVO_MAX_PATH];
+
+  if (PARALLEL && !HOST_ID) {
+    int status = dvoverify_parallel (skylist, nbad);
+    return status;
+  }
+
+  int Nbad = *nbad;
+
+  char *mycatdir = HOST_ID ? HOSTDIR : CATDIR;
+
+  // loop over all catalogs, save to output catalogs
+  for (i = 0; i < skylist[0].Nregions; i++) {
+    if (!skylist[0].regions[i][0].table) continue;
+    if (i % 1000 == 0) fprintf (stderr, ".");
+
+    int skipIndexCheck = FALSE;
+
+    // does this host ID match the desired location for the table?
+    if (!HostTableTestHost(skylist[0].regions[i], HOST_ID)) continue;
+
+    sprintf (filename, "%s/%s.cpt", mycatdir, skylist[0].regions[i][0].name);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+      skipIndexCheck = TRUE;
+    }
+
+    sprintf (filename, "%s/%s.cps", mycatdir, skylist[0].regions[i][0].name);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+
+    sprintf (filename, "%s/%s.cpm", mycatdir, skylist[0].regions[i][0].name);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+      skipIndexCheck = TRUE;
+    }
+
+    sprintf (filename, "%s/%s.cpt", mycatdir, skylist[0].regions[i][0].name);
+    if (!skipIndexCheck) {
+      if (!CheckCatalogIndexes(filename, skylist[0].regions[i])){
+	Nbad ++;
+      }
+    }
+
+    // exit immediately if any file are unsorted and we require sorted tables
+    // this probably goes elsewhere...
+    if (CHECKSORTED && NNotSorted) {
+      fprintf (stderr, "ERROR: files are not sorted\n");
+      return FALSE;
+    }
+  }
+
+  *nbad = Nbad;
+
+  return TRUE;
+}
+
+// launch the dvoverify_client jobs to the parallel hosts
+int dvoverify_parallel (SkyList *skylist, int *Nbad) {
+
+  // ensure that the paths are absolute path names
+  char *abscatdir = abspath (CATDIR, DVO_MAX_PATH);
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (CATDIR, skylist->hosts);
+  if (!table) {
+    fprintf (stderr, "ERROR: failure reading Host Table %s for database %s\n", skylist->hosts, CATDIR);
+    exit (1);
+  }    
+
+  int i;
+  for (i = 0; i < table->Nhosts; i++) {
+
+    // ensure that the paths are absolute path names
+    char *tmppath = abspath (table->hosts[i].pathname, DVO_MAX_PATH);
+    free (table->hosts[i].pathname);
+    table->hosts[i].pathname = tmppath;
+
+    ALLOCATE (table->hosts[i].results, char, 1024);
+    snprintf (table->hosts[i].results, 1024, "%s/dvoverify.dat", table->hosts[i].pathname);
+
+    // options / arguments that can affect relastro_client -update-objects:
+    char command[DVO_MAX_PATH];
+    snprintf (command, DVO_MAX_PATH, "dvoverify_client %s -results %s -hostID %d -hostdir %s -region %f %f %f %f", 
+	      abscatdir, table->hosts[i].results, table->hosts[i].hostID, table->hosts[i].pathname, 
+	      UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax
+      );
+
+    char tmpline[DVO_MAX_PATH];
+    if (VERBOSE)     { snprintf (tmpline, DVO_MAX_PATH, "%s -v", command); strcpy (command, tmpline); }
+    if (CHECKSORTED) { snprintf (tmpline, DVO_MAX_PATH, "%s -s", command); strcpy (command, tmpline); }
+
+    fprintf (stderr, "command: %s\n", command);
+
+    if (PARALLEL_MANUAL) continue;
+
+    if (PARALLEL_SERIAL) {
+      int status = system (command);
+      if (status) {
+	fprintf (stderr, "ERROR running photdbc_client\n");
+	exit (2);
+      }
+    } else {
+      // launch the job on the remote machine (no handshake)
+      int errorInfo = 0;
+      int pid = rconnect ("ssh", table->hosts[i].hostname, command, table->hosts[i].stdio, &errorInfo, FALSE);
+      if (!pid) {
+	if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", table->hosts[i].hostname, errorInfo);
+	exit (1);
+      }
+      table->hosts[i].pid = pid; // save for future reference
+    }
+  }
+
+  if (PARALLEL_MANUAL) {
+    fprintf (stderr, "run the photdbc_client commands above.  when these are done, hit return\n");
+    getchar();
+  }
+  if (!PARALLEL_MANUAL && !PARALLEL_SERIAL) {
+    HostTableWaitJobsGetIO (table, __FILE__, __LINE__, VERBOSE);
+  }
+
+  int NbadHost = 0;
+  int NNotSortedHost = 0;
+  for (i = 0; i < table->Nhosts; i++) {
+    FILE *results = fopen (table->hosts[i].results, "r");
+    myAssert (results, "cannot read result?");
+    fscanf (results, "%*s %d %*s %d", &NbadHost, &NNotSortedHost);
+    *Nbad += NbadHost;
+    NNotSorted += NNotSortedHost;
+    fclose (results);
+  }
+
+  return TRUE;
+}      
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_client.c
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_client.c	(revision 34116)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_client.c	(revision 34116)
@@ -0,0 +1,40 @@
+# include "dvoverify.h"
+
+int main (int argc, char **argv) {
+
+  int Nbad;
+  SkyTable *sky;
+  SkyList *skylist;
+
+  // check various options
+  dvoverify_client_args (&argc, argv);
+  CATDIR = argv[1];
+
+  Nbad = 0;
+
+  // load the sky table for the existing database
+  sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(sky, "can't read SkyTable");
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
+  
+  dvoverify_catalogs (skylist, &Nbad);
+
+  FILE *results = fopen (RESULTS, "w");
+  fprintf (results, "Nbad: %d NNotSorted: %d\n", Nbad, NNotSorted);
+  fclose (results);
+
+  // write result to file
+
+  if (Nbad > 0) {
+    fprintf (stderr, "ERROR: %d files are bad\n", Nbad);
+    exit (1);
+  }
+
+  fprintf (stderr, "SUCCESS on %d: no files are bad\n", HOST_ID);
+  if (NNotSorted) {
+    fprintf (stderr, "NOTE: %d files are not sorted\n", NNotSorted);
+  }
+  exit (0);
+}
+
Index: /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_utils.c
===================================================================
--- /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_utils.c	(revision 34116)
+++ /branches/eam_branches/ipp-20120627/Ohana/src/dvomerge/src/dvoverify_utils.c	(revision 34116)
@@ -0,0 +1,263 @@
+# include "dvoverify.h"
+
+int dvoverify_single (char *filename) {
+
+  int isBad = FALSE;
+
+  if (!VerifyTableFile (filename)) {
+    fprintf (stderr, "bad average table %s\n", filename);
+    isBad = TRUE;
+  }
+
+  // change last 't' to 's':
+  int Nlast;
+  Nlast = strlen(filename) - 1;
+  filename[Nlast] = 's';
+  if (!VerifyTableFile (filename)) {
+    fprintf (stderr, "bad secfilt table %s\n", filename);
+    isBad = TRUE;
+  }
+
+  // change last 't' to 's':
+  Nlast = strlen(filename) - 1;
+  filename[Nlast] = 'm';
+  if (!VerifyTableFile (filename)) {
+    fprintf (stderr, "bad measure table %s\n", filename);
+    isBad = TRUE;
+  }
+  return (isBad);
+}
+
+// is this file a consistent FITS file?
+int VerifyTableFile (char *filename) {
+
+  int status, Next;
+  off_t Nbytes;
+  Header header;
+
+  struct stat fileStats;
+  FILE *file;
+
+  // does the file exist?
+  status = stat (filename, &fileStats);
+  if (status) {
+    // some error accessing the file.  there is only one acceptable error: file not found
+    switch (errno) {
+      case ENOENT:
+	if (DEBUG) fprintf (stderr, "file does not exist, skipping %s\n", filename);
+	return TRUE;
+      case ENOMEM:
+	fprintf (stderr, "Out of memory: %s\n", filename);
+	return TRUE;
+      case EACCES:
+	fprintf (stderr, "Permission error on %s\n", filename);
+	return FALSE;
+      case EFAULT:
+	fprintf (stderr, "Bad address: %s\n", filename);
+	return FALSE;
+      case ELOOP:
+	fprintf (stderr, "Too many symbolic links encountered while traversing the path: %s\n", filename);
+	return FALSE;
+      case ENAMETOOLONG:
+	fprintf (stderr, "File name too long: %s\n", filename);
+	return FALSE;
+      case ENOTDIR:
+	fprintf (stderr, "A component of the path is not a directory: %s\n", filename);
+	return FALSE;
+      case EOVERFLOW:
+	fprintf (stderr, "file too large for program version: %s\n", filename);
+	return FALSE;
+      default:
+	fprintf (stderr, "unknown error: %s\n", filename);
+	return FALSE;
+    }
+  }
+
+  // does it have any data?
+  if (fileStats.st_size == 0) {
+    fprintf (stderr, "file is empty: %s\n", filename);
+    return FALSE;
+  }
+
+  // can we open it?
+  file = fopen(filename, "r");
+  if (!file) {
+    fprintf (stderr, "unable to open valid file: %s\n", filename);
+    return FALSE;
+  }
+
+  // scan all extentions
+  Nbytes = 0;
+  Next = -1;
+  if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
+  while (Nbytes < fileStats.st_size) {
+
+    // Check on the PHU
+    if (!gfits_fread_header (file, &header)) {
+      if (Next == -1) {
+	fprintf (stderr, "unable to read PHU header for %s\n", filename);
+      } else {
+	fprintf (stderr, "unable to read header for %s, extension %d (or file has excess bytes)\n", filename, Next);
+      }
+      fclose(file);
+      return (FALSE);
+    }
+
+    // move to TBL header
+    Nbytes += header.datasize + gfits_data_size (&header);
+    if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
+    if (Nbytes > fileStats.st_size) {
+      fprintf (stderr, "file is short ("OFF_T_FMT" vs "OFF_T_FMT"): %s\n", Nbytes, fileStats.st_size, filename);
+      gfits_free_header(&header);
+      fclose (file);
+      return FALSE;
+    }
+    gfits_free_header(&header);
+
+    status = fseeko (file, Nbytes, SEEK_SET);
+    if (status) {
+      switch (errno) {
+	case EBADF:
+	  fprintf (stderr, "something wrong with file handle: %s\n", filename);
+	  fclose (file);
+	  return FALSE;
+	case EINVAL:
+	  fprintf (stderr, "invalid offset: %s\n", filename);
+	  fclose (file);
+	  return FALSE;
+	default:
+	  fprintf (stderr, "other error in fseeko: %s\n", filename);
+	  fclose (file);
+	  return FALSE;
+      }
+    }
+    Next ++;
+  }
+  if (DEBUG) fprintf (stderr, "file is good: %s\n", filename);
+  fclose (file);
+  return TRUE;
+}
+
+int CheckCatalogIndexes (char *filename,  SkyRegion *region) {
+
+  Catalog catalog;
+  int i, j, m, status;
+
+  status = TRUE;
+
+  // set the parameters which guide catalog open/load/create
+  catalog.filename  = filename;
+  catalog.catformat = DVO_FORMAT_UNDEF; // read-only,do not set the catformat
+  catalog.catmode   = DVO_MODE_UNDEF; // read-only, do not set the catmode
+  catalog.catflags  = LOAD_AVES | LOAD_MEAS;
+  catalog.Nsecfilt  = 0;
+  
+  // an error exit status here is a significant error (disk I/O or file access)
+  if (!dvo_catalog_open (&catalog, region, VERBOSE, "r")) {
+    fprintf (stderr, "ERROR: failure to open catalog file %s\n", catalog.filename);
+    return FALSE;
+  }
+
+  // Naves_disk == 0 implies an empty catalog file, skip empty catalogs
+  if (catalog.Naves_disk == 0) {
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+    return TRUE;
+  }
+
+  // if the table is SORTED, then the following can be checked
+  // check the following:
+  // measure[j].averef -> average[averef]
+  // measure[j].objID = average[averef].objID
+  // measure[j].catID = average[averef].catID
+  // measure[j].measureOffset < Nmeasure
+  // \sum average[].Nmeasure = Nmeasure
+
+  // if the table is NOT SORTED, we have a subset of checks we can make
+  if (!catalog.sorted) {
+    fprintf (stderr, "!");
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+    NNotSorted++;
+    if (VERBOSE) fprintf (stderr, "file is not sorted: %s\n", filename);
+    return TRUE;
+  }
+
+  int NmeasureTotal = 0;
+  int measureOffsetOK = TRUE;
+  for (i = 0; i < catalog.Naverage; i++) {
+    NmeasureTotal += catalog.average[i].Nmeasure;
+    if (VERBOSE && !(NmeasureTotal <= catalog.Nmeasure)) {
+      fprintf (stderr, "NmeasureTotal > catalog.Nmeasure: %d %d %d\n", i, catalog.average[i].Nmeasure, (int) catalog.Nmeasure);
+    }
+    measureOffsetOK &= (catalog.average[i].measureOffset < catalog.Nmeasure);
+    if (VERBOSE && !(catalog.average[i].measureOffset < catalog.Nmeasure)) {
+      fprintf (stderr, "measureOffset >= catalog.Nmeasure: %d %d %d\n", i, catalog.average[i].measureOffset, (int) catalog.Nmeasure);
+    }
+    measureOffsetOK &= (catalog.average[i].measureOffset + catalog.average[i].Nmeasure <= catalog.Nmeasure);
+    if (VERBOSE && !(catalog.average[i].measureOffset + catalog.average[i].Nmeasure <= catalog.Nmeasure)) {
+      fprintf (stderr, "measureOffset + Nmeasure > catalog.Nmeasure : %d %d %d\n", i, catalog.average[i].Nmeasure, (int) catalog.Nmeasure);
+    }
+  }
+
+  if (!measureOffsetOK) {
+    fprintf (stderr, "ERROR: catalog %s has an invalid measureOffset\n", catalog.filename);
+    status = FALSE;
+  }
+
+  if (NmeasureTotal != catalog.Nmeasure) {
+    fprintf (stderr, "ERROR: catalog %s has an invalid Nmeasure\n", catalog.filename);
+    status = FALSE;
+  }
+
+  if (!status) {
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+    return (status);
+  }
+
+  int objIDsOK = TRUE;
+  int catIDsOK = TRUE;
+  int averefOK = TRUE;
+
+  for (i = 0; i < catalog.Naverage; i++) {
+    m = catalog.average[i].measureOffset;
+    for (j = 0; j < catalog.average[i].Nmeasure; j++) {
+      objIDsOK &= (catalog.average[i].objID == catalog.measure[m+j].objID);
+      catIDsOK &= (catalog.average[i].catID == catalog.measure[m+j].catID);
+      averefOK &= (catalog.measure[m+j].averef == i);
+    }
+  }
+    
+  if (!objIDsOK) {
+    fprintf (stderr, "ERROR: catalog %s has invalid obj IDs\n", catalog.filename);
+    status = FALSE;
+  }
+  if (!catIDsOK) {
+    fprintf (stderr, "ERROR: catalog %s has invalid cat IDs\n", catalog.filename);
+    status = FALSE;
+  }
+  if (!averefOK) {
+    fprintf (stderr, "ERROR: catalog %s has invalid averef values\n", catalog.filename);
+    status = FALSE;
+  }
+
+//  for (i = 0; i < catalog.Naverage; i++) {
+//    m = catalog.average[i].measureOffset;
+//    for (j = 0; i < catalog.Nmeasure; i++) {
+//      objIDsOK &= (catalog.average[i].objID == catalog.measure[m+j].objID);
+//      catIDsOK &= (catalog.average[i].catID == catalog.measure[m+j].catID);
+//      averefOK &= (catalog.measure[m+j].averef = i);
+//    }
+//  }
+
+  dvo_catalog_unlock (&catalog);
+  dvo_catalog_free (&catalog);
+
+  return status;
+}
+
+// gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
+// gfits_scan(&cpmHeaderTBL, "NAXIS2", "%d", 1, &Nrows);
+    
+  
