Index: /trunk/Ohana/src/imregister/imreg/ConfigPID.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/ConfigPID.c	(revision 69)
+++ /trunk/Ohana/src/imregister/imreg/ConfigPID.c	(revision 69)
@@ -0,0 +1,78 @@
+# include ".h"
+
+static char *PIDMaster = (char *) NULL;
+
+ConfigPID (char *pidfile) {
+
+  pid_t pid;
+  char *username, machine[256];
+  FILE *f;
+
+  ALLOCATE (username, char, 256);
+  if (!LoadPID (pidfile, &pid, username, machine)) {
+    /* no PID file, make new one */
+
+    pid = getpid ();
+
+    free (username);
+    username = getenv ("USER");
+    if (username == (char *) NULL) {
+      fprintf (stderr, "error getting username\n");
+      exit (2);
+    }
+    bzero (machine, 256);
+    if (gethostname (machine, 256)) {
+      fprintf (stderr, "error getting hostname\n");
+      exit (2);
+    }
+
+    f = fopen (pidfile, "w");
+    if (f == (FILE *) NULL) { 
+      fprintf (stderr, "can't write to PID file %s\n", pidfile);
+      exit (2);
+    }
+
+    fprintf (f, "PID:     %d\n", pid);
+    fprintf (f, "USER:    %-s\n", username);
+    fprintf (f, "MACHINE: %-s\n", machine);
+    fclose (f);
+
+    PIDMaster = pidfile;
+    return (TRUE); 
+  }
+
+  /* PID file exists, warn & exit */
+  fprintf (stderr, "elixir is apparently running:\n\n");
+  fprintf (stderr, "  machine: %s\n", machine);
+  fprintf (stderr, "  user: %s\n", username);
+  fprintf (stderr, "  PID: %d\n", pid);
+  fprintf (stderr, "  remove %s if elixir has died unexpectedly\n", pidfile);
+  Shutdown (1);
+}
+
+void RemovePID () {
+  
+  if (PIDMaster == (char *) NULL) 
+    return;
+  
+  if (unlink (PIDMaster)) {
+    fprintf (stderr, "error deleting PID File %s\n", PIDMaster);
+  }   
+}
+
+int LoadPID (char *file, pid_t *pid, char *username, char *machine) {
+
+  FILE *f;
+
+  f = fopen (file, "r");
+  if (f == (FILE *) NULL) { 
+    return (FALSE);
+  }
+
+  fscanf (f, "%*s %d", pid);
+  fscanf (f, "%*s %s", username);
+  fscanf (f, "%*s %s", machine);
+  fclose (f);
+
+  return (TRUE);
+}
Index: /trunk/Ohana/src/imregister/imreg/SetSignals.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/SetSignals.c	(revision 69)
+++ /trunk/Ohana/src/imregister/imreg/SetSignals.c	(revision 69)
@@ -0,0 +1,166 @@
+# include "controller.h"
+
+void SIG_DIE (int sig) {
+  fprintf (stderr, "trapped signal %d, exiting\n", sig);
+  Shutdown (1);
+}
+
+void SIG_PIPE (int sig) {
+  fprintf (stderr, "pipe signal\n", sig);
+}
+
+SetSignals () {
+
+  /* use default settings */
+  signal (SIGKILL,   SIG_DFL);    
+  signal (SIGCONT,   SIG_DFL);    
+  signal (SIGSTOP,   SIG_DFL);    
+  signal (SIGUNUSED, SIG_DFL);  
+
+  /* exit on these signals */
+  signal (SIGILL,    SIG_DIE);     
+  signal (SIGABRT,   SIG_DIE);    
+  signal (SIGFPE,    SIG_DIE);     
+  signal (SIGSEGV,   SIG_DIE);    
+  signal (SIGTERM,   SIG_DIE);    
+  signal (SIGBUS,    SIG_DIE);     
+  signal (SIGTRAP,   SIG_DIE);    
+  signal (SIGXCPU,   SIG_DIE);    
+  signal (SIGXFSZ,   SIG_DIE);    
+  signal (SIGIOT,    SIG_DIE);     
+  signal (SIGPWR,    SIG_DIE);     
+  signal (SIGHUP,    SIG_IGN);
+  signal (SIGINT,    SIG_DIE);
+  signal (SIGQUIT,   SIG_IGN);
+  signal (SIGPIPE,   SIG_PIPE);    
+  signal (SIGALRM,   SIG_IGN);    
+  signal (SIGUSR1,   SIG_IGN);    
+  signal (SIGUSR2,   SIG_IGN);    
+  signal (SIGCHLD,   SIG_IGN);    
+  signal (SIGTSTP,   SIG_IGN);    
+  signal (SIGTTIN,   SIG_IGN);    
+  signal (SIGTTOU,   SIG_IGN);    
+  signal (SIGPOLL,   SIG_IGN);    
+  signal (SIGPROF,   SIG_IGN);    
+  signal (SIGURG,    SIG_IGN);     
+  signal (SIGVTALRM, SIG_IGN);  
+  signal (SIGIO,     SIG_IGN);      
+  signal (SIGWINCH,  SIG_IGN);   
+
+  /* signals which are not always defined */
+# ifdef SIGSYS
+  signal (SIGSYS,    SIG_DIE);     
+# endif
+# ifdef SIGEMT
+ signal (SIGEMT,    SIG_DIE); 
+# endif
+# ifdef SIGSTKFLT
+  signal (SIGSTKFLT, SIG_DIE);  
+# endif
+# ifdef SIGINFO
+ signal (SIGINFO,   SIG_DIE); 
+# endif
+# ifdef SIGCLD
+  signal (SIGCLD,    SIG_IGN);     
+# endif
+# ifdef SIGLOST
+  signal (SIGLOST,   SIG_IGN); 
+# endif
+# ifdef SIGUNUSED
+  signal (SIGUNUSED,   SIG_IGN); 
+# endif
+
+}
+
+KillProcess (char *pidfile) {
+  
+  pid_t pid;
+  char username[256], machine[256];
+  char line[512];
+  int i, status, wsock, rsock;
+  struct stat filestat;
+
+  if (!LoadPID (pidfile, &pid, username, machine)) {
+    fprintf (stderr, "imstatreg is not running\n");
+    exit (0);
+  }
+
+  /* send signal to remote machine */
+  if (!rconnect (machine, "/usr/bin/rsh", &rsock, &wsock)) {
+    fprintf (stderr, "can't make connection to machine %s to kill process %d\n", machine, pid);
+    exit (1);
+  }
+  sprintf (line, "kill -TERM %d\n", pid);
+  write (wsock, line, strlen (line));
+
+  for (i = 0; i < 100; i++) {
+    if (stat (pidfile, &filestat) == -1) exit (0);
+    usleep (100000);
+  }
+  fprintf (stderr, "imstatreg is still running\n");
+  exit (2);
+}
+
+StatusProcess (char *pidfile, char *msgfile) {
+  
+  pid_t pid;
+  char username[256], machine[256];
+
+  if (!LoadPID (pidfile, &pid, username, machine)) {
+    fprintf (stderr, "imstatreg is not running\n");
+    exit (0);
+  }
+
+  /* PID file exists, warn & exit */
+  fprintf (stderr, "imstatreg is apparently running:\n\n");
+  fprintf (stderr, "  machine: %s\n", machine);
+  fprintf (stderr, "  user: %s\n", username);
+  fprintf (stderr, "  PID: %d\n", pid);
+  fprintf (stderr, "  remove %s if imstatreg has died unexpectedly\n", pidfile);
+
+  exit (0);
+}
+
+/*
+
+  SIGHUP             1        A      Hangup detected on controlling terminal
+                                     or death of controlling process
+  SIGINT             2        A      Interrupt from keyboard
+  SIGQUIT            3        C      Quit from keyboard
+  SIGILL             4        C      Illegal Instruction
+  SIGABRT            6        C      Abort signal from abort(3)
+  SIGFPE             8        C      Floating point exception
+  SIGKILL            9       AEF     Kill signal
+  SIGSEGV           11        C      Invalid memory reference
+  SIGPIPE           13        A      Broken pipe: write to pipe with no readers
+  SIGALRM           14        A      Timer signal from alarm(2)
+  SIGTERM           15        A      Termination signal
+  SIGUSR1        30,10,16     A      User-defined signal 1
+  SIGUSR2        31,12,17     A      User-defined signal 2
+  SIGCHLD        20,17,18     B      Child stopped or terminated
+  SIGCONT        19,18,25            Continue if stopped
+  SIGSTOP        17,19,23    DEF     Stop process
+  SIGTSTP        18,20,24     D      Stop typed at tty
+  SIGTTIN        21,21,26     D      tty input for background process
+  SIGTTOU        22,22,27     D      tty output for background process
+  SIGBUS         10,7,10      C      Bus error (bad memory access)
+  SIGPOLL                     A      Pollable event (Sys V). Synonym of SIGIO
+  SIGPROF        27,27,29     A      Profiling timer expired
+  SIGSYS         12,-,12      C      Bad argument to routine (SVID)
+  SIGTRAP           5         C      Trace/breakpoint trap
+  SIGURG         16,23,21     B      Urgent condition on socket (4.2 BSD)
+  SIGVTALRM      26,26,28     A      Virtual alarm clock (4.2 BSD)
+  SIGXCPU        24,24,30     C      CPU time limit exceeded (4.2 BSD)
+  SIGXFSZ        25,25,31     C      File size limit exceeded (4.2 BSD)
+  SIGIOT            6         C      IOT trap. A synonym for SIGABRT
+  SIGEMT          7,-,7
+  SIGSTKFLT       -,16,-      A      Stack fault on coprocessor
+  SIGIO          23,29,22     A      I/O now possible (4.2 BSD)
+  SIGCLD          -,-,18             A synonym for SIGCHLD
+  SIGPWR         29,30,19     A      Power failure (System V)
+  SIGINFO         29,-,-             A synonym for SIGPWR
+  SIGLOST         -,-,-       A      File lock lost
+  SIGWINCH       28,28,20     B      Window resize signal (4.3 BSD, Sun)
+  SIGUNUSED       -,31,-      A      Unused signal (will be SIGSYS)
+*/
+
Index: /trunk/Ohana/src/imregister/imreg/cadc.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/cadc.c	(revision 69)
+++ /trunk/Ohana/src/imregister/imreg/cadc.c	(revision 69)
@@ -0,0 +1,303 @@
+# include "imregister.h"
+# include "imreg.h"
+
+static int REFCCD;
+
+void DumpCADCTable (char *filename, RegImage *image, int *match, int Nmatch) {
+  
+  int i, Obsid, Nobsid, Nsubset, ref;
+  char *datestr, *line, hdrname[99];
+  unsigned long tsecond;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  RegImage *row;
+  int *index, *entry, *obsid;
+  MosaicLayout *layout;
+  int *subset;
+  double left, right, center, outer, top, bottom;
+  double iqx, iqy, iqr, iqf, iqo;
+  FILE *p;
+
+  /* set REFCCD for use in GetREFIQ */
+  REFCCD = MatchCCDName (SeeingREFCCD);
+  if (REFCCD == -1) { 
+    fprintf (stderr, "ERROR: can't get reference ccd\n");
+    exit (1);
+  }
+
+  /* assign relevant mosaic layout structure */
+  layout = (MosaicLayout *) NULL;
+  if (!strcasecmp (Camera, "CFH12K"))  layout = CreateCFH12K ();
+  if (!strcasecmp (Camera, "MegaCam")) layout = CreateMegaCam ();
+  if (layout == (MosaicLayout *) NULL) {
+    fprintf (stderr, "ERROR: invalid camera for CADC Table\n");
+    exit (1);
+  }
+
+  /* create primary header */
+  fits_init_header (&header);    
+  header.extend = TRUE;
+  fits_create_header (&header);
+  fits_create_matrix (&header, &matrix);
+  fits_print (&header, "NEXTEND", "%d", 1, 1);
+  
+  /* create table header */
+  fits_create_table_header (&theader, "TABLE", "CADC_RAW_IMAGES");
+      
+  /* add current date/time to header */
+  str_to_time ("now", &tsecond);
+  datestr = sec_to_date (tsecond);
+  fits_modify (&header,  "DATE", "%s", 1, datestr);
+  fits_modify (&theader, "DATE", "%s", 1, datestr);
+
+  /* define table layout */
+  fits_define_table_column (&theader, "A99",   "FILENAME",       "filename in db",                  "",               1.0, 0.0);
+  fits_define_table_column (&theader, "A99",   "HDR_FILENAME",   "image header filename",           "",               1.0, 0.0);
+  fits_define_table_column (&theader, "I10",   "OBSID",          "image ID number",                 "",               1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.2",  "OBS_IQ_REFCCD",  "image quality on reference chip", "arcsec",         1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.2",  "OBS_IQ_CENTER",  "image quality center region",     "arcsec",         1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.2",  "OBS_IQ_R_RATIO", "IQ ratio (outer / center)",       "",               1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.2",  "OBS_IQ_X_RATIO", "IQ ratio (left / right)",         "",               1.0, 0.0); 
+  fits_define_table_column (&theader, "F5.2",  "OBS_IQ_Y_RATIO", "IQ ratio (top / bottom)",         "",               1.0, 0.0); 
+  fits_define_table_column (&theader, "F9.3",  "OBS_BG_VAL",     "background level",                "counts / pixel", 1.0, 0.0); 
+
+  /* define TNULL, TNVAL values */
+  fits_modify (&theader, "TNULL1",  "%s", 1, "NULL");  /* FILENAME       */
+  fits_modify (&theader, "TNULL2",  "%s", 1, "NULL");  /* HDR_FILENAME   */
+  fits_modify (&theader, "TNULL3",  "%s", 1, "0");     /* OBSID          */
+  fits_modify (&theader, "TNULL4",  "%s", 1, "0.00");  /* OBS_IQ_REFCCD  */
+  fits_modify (&theader, "TNULL5",  "%s", 1, "0.00");  /* OBS_IQ_CENTER  */
+  fits_modify (&theader, "TNULL6",  "%s", 1, "0.00");  /* OBS_IQ_R_RATIO */
+  fits_modify (&theader, "TNULL7",  "%s", 1, "0.00");  /* OBS_IQ_X_RATIO */
+  fits_modify (&theader, "TNULL8",  "%s", 1, "0.00");  /* OBS_IQ_Y_RATIO */
+  fits_modify (&theader, "TNULL9",  "%s", 1, "0.00");  /* OBS_BG_VAL     */
+
+  fits_modify (&theader, "TNVAL1",  "%s", 1, "NA");    /* FILENAME     */
+  fits_modify (&theader, "TNVAL2",  "%s", 1, "NA");    /* HDR_FILENAME */
+  fits_modify (&theader, "TNVAL3",  "%s", 1, "-1");    /* OBSID        */
+  fits_modify (&theader, "TNVAL4",  "%s", 1, "-1.00"); /* OBS_IQ_REFCCD  */
+  fits_modify (&theader, "TNVAL5",  "%s", 1, "-1.00"); /* OBS_IQ_CENTER  */
+  fits_modify (&theader, "TNVAL6",  "%s", 1, "-1.00"); /* OBS_IQ_R_RATIO */
+  fits_modify (&theader, "TNVAL7",  "%s", 1, "-1.00"); /* OBS_IQ_X_RATIO */
+  fits_modify (&theader, "TNVAL8",  "%s", 1, "-1.00"); /* OBS_IQ_Y_RATIO */
+  fits_modify (&theader, "TNVAL9",  "%s", 1, "-1.00"); /* OBS_BG_VAL   */
+
+  /* create table, add data values */
+  fits_create_table (&theader, &table);
+  
+  /* prepare indicies to handle table data */
+  GetObsIDIndex (image, match, Nmatch, &index, &entry);
+  obsid = GetUniqueObsID (image, index, entry, Nmatch, &Nobsid);
+
+  for (i = 0; i < Nobsid; i++) {
+    ref = GetREFCCD (image, index, entry, Nmatch, obsid[i]);
+    row = &image[ref];
+    Obsid = index[obsid[i]];
+    sprintf (hdrname, "%s.hdr", row[0].filename);
+
+    subset = GetObsIDSubset (image, obsid[i], index, entry, Nmatch, &Nsubset);
+    center = MosaicIQStats (image, subset, Nsubset, &layout[0].center);
+    outer  = MosaicIQStats (image, subset, Nsubset, &layout[0].outer );
+    top    = MosaicIQStats (image, subset, Nsubset, &layout[0].top   );
+    bottom = MosaicIQStats (image, subset, Nsubset, &layout[0].bottom);
+    left   = MosaicIQStats (image, subset, Nsubset, &layout[0].left  );
+    right  = MosaicIQStats (image, subset, Nsubset, &layout[0].right );
+    free (subset);
+
+    iqx = (left   == 0) ? 0 : (right / left);
+    iqy = (bottom == 0) ? 0 : (top / bottom);
+    iqr = (center == 0) ? 0 : (outer / center);
+    iqf = center * ARCSEC_PIXEL;
+    iqo = row[0].fwhm*ARCSEC_PIXEL;
+    line = fits_table_print (&table, row[0].filename, hdrname, Obsid, iqo, iqf, iqr, iqx, iqy, row[0].sky);
+
+    fits_add_rows (&table, line, 1, strlen(line));
+    free (line);
+  }
+  free (obsid);
+  free (index);
+  free (entry);
+
+  fits_write_header  (filename, &header);
+  fits_write_matrix  (filename, &matrix);
+  fits_write_Theader (filename, &theader);
+  fits_write_table   (filename, &table);
+  exit (0);
+}
+
+int *GetObsIDSubset (RegImage *image, int start, int *index, int *entry, int Nindex, int *Nsubset) {
+
+  int i, N, NSUBSET;
+  int *subset;
+
+  /* create output index */
+  N = 0;
+  NSUBSET = 64;
+  ALLOCATE (subset, int, NSUBSET);
+
+  /* find unique sequences */
+  for (i = start; (i < Nindex) && (index[i] == index[start]); i++) {
+    subset[N] = entry[i];
+    N++;
+    if (N == NSUBSET) {
+      NSUBSET += 64;
+      REALLOCATE (subset, int, NSUBSET);
+    }
+  }
+
+  *Nsubset = N;
+  return (subset);
+}
+
+/* return an index list of unique obs id entries at start of sequence */
+int *GetUniqueObsID (RegImage *image, int *index, int *entry, int Nindex, int *Nmatch) {
+  
+  int i, j, k, m, N, NMATCH, REFCCD;
+  int *match;
+
+  /* create output index */
+  N = 0;
+  NMATCH = 1000;
+  ALLOCATE (match, int, NMATCH);
+
+  /* find unique sequences */
+  for (i = 0; i < Nindex; ) {
+    for (j = i + 1; (j < Nindex) && (index[i] == index[j]); j++);
+
+    /* add unique entry to output list */
+    match[N] = i;
+    N ++;
+    if (N == NMATCH) {
+      NMATCH += 1000;
+      REALLOCATE (match, int, NMATCH);
+    }
+
+    /* j always points to the next entry */
+    i = j;
+  }
+  *Nmatch = N;
+  return (match);
+}
+
+/* return seeing for ccd == REFCCD */
+int GetREFCCD (RegImage *image, int *index, int *entry, int Nindex, int start) {
+  
+  int i, j, k, m, N, NMATCH;
+  int *match;
+
+  /* create output index */
+  N = 0;
+  NMATCH = 1000;
+  ALLOCATE (match, int, NMATCH);
+
+  /* find unique sequences */
+  for (i = start; (i < Nindex) && (index[i] == index[start]); i++) {
+    if (image[entry[i]].ccd == REFCCD) return (entry[i]);
+  }
+  return (start);
+}
+
+void GetObsIDIndex (RegImage *image, int *match, int Nmatch, int **Index, int **Entry) {
+
+  int i;
+  int *index, *entry;
+
+  /* index = OBSID */
+  ALLOCATE (index, int, Nmatch);
+  ALLOCATE (entry, int, Nmatch);
+  for (i = 0; i < Nmatch; i++) {
+    index[i] = atoi (image[match[i]].filename);
+    if (index[i] < 400000) fprintf (stderr, "warning: derived obsid < 400000\n");
+    entry[i] = match[i];
+  }
+  sortpair (index, entry, Nmatch);
+  *Index = index;
+  *Entry = entry;
+}
+
+/* match is a list of image entries with the same obsid */
+double MosaicIQStats (RegImage *image, int *match, int Nmatch, MosaicRegion *region) {
+
+  int i, j, N, Nccd;
+  double *list, value;
+
+  Nccd = region[0].Nccd;
+  ALLOCATE (list, double, Nccd);
+
+  N = 0;
+  for (i = 0; i < Nccd; i++) {
+    for (j = 0; j < Nmatch; j++) {
+      if (image[match[j]].ccd == region[0].ccd[i]) {
+	list[N] = image[match[j]].fwhm;
+	N++;
+	break;
+      }
+    }
+  }
+
+  value = SigmaClipList (list, N);
+  free (list);
+  return (value);
+}
+
+double SigmaClipList (double *list, int N) {
+
+  int i, n;
+  double median, sigma3, m1, m2;
+
+  if (N == 0) return (0.0);
+  if (N == 1) return (list[0]);
+  
+  dsort (list, N);
+  median = list[(int)(0.5*N)];
+  
+  m1 = m2 = 0;
+  for (i = 0; i < N; i++) { m1 += list[i]; m2 += SQ(list[i]); }
+  sigma3 = 3*sqrt (m2/N - m1*m1/N/N);
+  
+  m1 = n = 0;
+  for (i = 0; i < N; i++) { 
+    if (abs(list[i] - median) > sigma3) continue;
+    m1 += list[i];
+    n ++;
+  }
+
+  m2 = m1 / n;
+  return (m2);
+}
+  
+
+/* the CADC table is special: we need to report specfic IQ stats 
+   which represent the variations in focus across the mosaic. 
+   this representation is explicitly dependent on the mosaic,
+   and does not make sense for other camera types 
+   CADC table option cannot be combined with CCD filtering options
+   CADC table forces -unique, needed to make calculation
+*/
+
+/* derived CADC parameters:
+   OBS_IQ_CENTER - sigma-clip mean value of center region
+   OBS_IQ_X      - ratio of left to right regions
+   OBS_IQ_Y      - ratio of top to bottom regions
+   OBS_IQ_R      - ratio of center to edge regions
+*/
+
+/* cfh12k:
+
+   00 01 02 03 04 05
+   06 07 08 09 10 11
+
+   center: 02,03,08,09
+   outer:  00,01,04,05,06,07,10,11
+   top;    00-05
+   bottom: 06-11
+   right:  00,01,02,06,07,08
+   left:   03,04,05,09,10,11
+
+   for each region, calculate median, sigma, reject >3sigma, calculate mean
+*/
+
+/* we are guaranteed a unique set of filename / ccd values */
+/* index = OBSID = atoi (filename) */
+
Index: /trunk/Ohana/src/imregister/imreg/imregclient.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/imregclient.c	(revision 69)
+++ /trunk/Ohana/src/imregister/imreg/imregclient.c	(revision 69)
@@ -0,0 +1,74 @@
+# include "imregister.h"
+# include "imreg.h"
+
+int imregclient (char *fitsfile, char *statfile, char *datfile) {
+
+  FILE *f;
+  RegImage *image;
+  char *TempDB;
+  int i, Nentry, Nslice, status;
+  float *dtime;
+
+  ALLOCATE (TempDB, char, strlen (ImageDB) + 10);
+  sprintf (TempDB, "%s.bfr", ImageDB);
+
+  image = iminfo (fitsfile);
+  
+  /* if images is MEF or SPLIT/SINGLE, load stats file */
+  /* get stats file (has sky, bias, etc) */
+  switch (image[0].mode) {
+  case MODE_MEF:
+  case MODE_SPLIT:
+    f = fopen (statfile, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file.stats\n");
+      exit (1);
+    }
+    fscanf (f, "%f %f", &image[0].sky, &image[0].bias);
+    fclose (f);
+    image[0].fwhm = get_fwhm (datfile);
+    Nentry = 1;
+    break;
+  case MODE_SINGLE:
+    f = fopen (statfile, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file.stats\n");
+      exit (1);
+    }
+    status = fscanf (f, "%d %f %f", &image[0].ccd, &image[0].sky, &image[0].fwhm);
+    fclose (f);
+    Nentry = 1;
+    break;
+  case MODE_CUBE:
+    f = fopen (statfile, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't open file.stats\n");
+      exit (1);
+    }
+    status = 3;
+    Nslice = image[0].ccd;
+    Nentry = Nslice + 1;
+    REALLOCATE (image, RegImage, Nentry);
+    dtime = (float *)&image[0].junk[0];
+    for (i = 0; i < Nentry; i++) {
+      image[i] = image[0];
+      status = fscanf (f, "%d %f %f", &image[i].ccd, &image[i].sky, &image[i].fwhm);
+      if (image[i].ccd == Nslice) continue;
+      image[i].obstime += *dtime*image[i].ccd;
+    }
+    fclose (f);
+    Nentry = i;
+    break;
+  }
+  if (NoReg) dump_data (image, Nentry);
+
+  set_db (TempDB);
+
+  status = load_db ();
+  if (!status) {
+    create_db ();
+  }
+  append_db (image, Nentry);
+  fprintf (stderr, "SUCCESS: wrote temp image data\n");
+  exit (0);
+}
Index: /trunk/Ohana/src/imregister/imreg/mosaics.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/mosaics.c	(revision 69)
+++ /trunk/Ohana/src/imregister/imreg/mosaics.c	(revision 69)
@@ -0,0 +1,163 @@
+# include "imregister.h"
+# include "imreg.h"
+
+MosaicLayout *CreateCFH12K () {
+
+  MosaicLayout *layout;
+
+  ALLOCATE (layout, MosaicLayout, 1);
+
+  layout[0].center.Nccd = 4;
+  ALLOCATE (layout[0].center.ccd, int, layout[0].center.Nccd);
+  layout[0].center.ccd[0] = 2;
+  layout[0].center.ccd[1] = 3;
+  layout[0].center.ccd[2] = 8;
+  layout[0].center.ccd[3] = 9;
+
+  layout[0].outer.Nccd = 8;
+  ALLOCATE (layout[0].outer.ccd, int, layout[0].outer.Nccd);
+  layout[0].outer.ccd[0] = 0;
+  layout[0].outer.ccd[1] = 1;
+  layout[0].outer.ccd[2] = 4;
+  layout[0].outer.ccd[3] = 5;
+  layout[0].outer.ccd[4] = 6;
+  layout[0].outer.ccd[5] = 7;
+  layout[0].outer.ccd[6] = 10;
+  layout[0].outer.ccd[7] = 11;
+
+  layout[0].top.Nccd = 6;
+  ALLOCATE (layout[0].top.ccd, int, layout[0].top.Nccd);
+  layout[0].top.ccd[0] = 0;
+  layout[0].top.ccd[1] = 1;
+  layout[0].top.ccd[2] = 2;
+  layout[0].top.ccd[3] = 3;
+  layout[0].top.ccd[4] = 4;
+  layout[0].top.ccd[5] = 5;
+
+  layout[0].bottom.Nccd = 6;
+  ALLOCATE (layout[0].bottom.ccd, int, layout[0].bottom.Nccd);
+  layout[0].bottom.ccd[0] = 6;
+  layout[0].bottom.ccd[1] = 7;
+  layout[0].bottom.ccd[2] = 8;
+  layout[0].bottom.ccd[3] = 9;
+  layout[0].bottom.ccd[4] = 10;
+  layout[0].bottom.ccd[5] = 11;
+
+  layout[0].left.Nccd = 6;
+  ALLOCATE (layout[0].left.ccd, int, layout[0].left.Nccd);
+  layout[0].left.ccd[0] = 0;
+  layout[0].left.ccd[1] = 1;
+  layout[0].left.ccd[2] = 2;
+  layout[0].left.ccd[3] = 6;
+  layout[0].left.ccd[4] = 7;
+  layout[0].left.ccd[5] = 8;
+
+  layout[0].right.Nccd = 6;
+  ALLOCATE (layout[0].right.ccd, int, layout[0].right.Nccd);
+  layout[0].right.ccd[0] = 3;
+  layout[0].right.ccd[1] = 4;
+  layout[0].right.ccd[2] = 5;
+  layout[0].right.ccd[3] = 9;
+  layout[0].right.ccd[4] = 10;
+  layout[0].right.ccd[5] = 11;
+
+  return (layout);
+}
+
+MosaicLayout *CreateMegaCam () {
+
+  MosaicLayout *layout;
+
+  ALLOCATE (layout, MosaicLayout, 1);
+
+  layout[0].center.Nccd = 10;
+  ALLOCATE (layout[0].center.ccd, int, layout[0].center.Nccd);
+  layout[0].center.ccd[0] = 11;
+  layout[0].center.ccd[1] = 12;
+  layout[0].center.ccd[2] = 13;
+  layout[0].center.ccd[3] = 14;
+  layout[0].center.ccd[4] = 15;
+  layout[0].center.ccd[5] = 20;
+  layout[0].center.ccd[6] = 21;
+  layout[0].center.ccd[7] = 22;
+  layout[0].center.ccd[8] = 23;
+  layout[0].center.ccd[9] = 24;
+
+  layout[0].outer.Nccd = 26;
+  ALLOCATE (layout[0].outer.ccd, int, layout[0].outer.Nccd);
+  layout[0].outer.ccd[0] = 0;
+  layout[0].outer.ccd[1] = 1;
+  layout[0].outer.ccd[2] = 2;
+  layout[0].outer.ccd[3] = 3;
+  layout[0].outer.ccd[4] = 4;
+  layout[0].outer.ccd[5] = 5;
+  layout[0].outer.ccd[6] = 6;
+  layout[0].outer.ccd[7] = 7;
+  layout[0].outer.ccd[8] = 8;
+  layout[0].outer.ccd[9] = 9;
+  layout[0].outer.ccd[10] = 10;
+  layout[0].outer.ccd[11] = 16;
+  layout[0].outer.ccd[12] = 17;
+  layout[0].outer.ccd[13] = 18;
+  layout[0].outer.ccd[14] = 19;
+  layout[0].outer.ccd[15] = 25;
+  layout[0].outer.ccd[16] = 26;
+  layout[0].outer.ccd[17] = 27;
+  layout[0].outer.ccd[18] = 28;
+  layout[0].outer.ccd[19] = 29;
+  layout[0].outer.ccd[20] = 30;
+  layout[0].outer.ccd[21] = 31;
+  layout[0].outer.ccd[22] = 32;
+  layout[0].outer.ccd[23] = 33;
+  layout[0].outer.ccd[24] = 34;
+  layout[0].outer.ccd[25] = 35;
+
+  layout[0].top.Nccd = 9;
+  ALLOCATE (layout[0].top.ccd, int, layout[0].top.Nccd);
+  layout[0].top.ccd[0] = 0;
+  layout[0].top.ccd[1] = 1;
+  layout[0].top.ccd[2] = 2;
+  layout[0].top.ccd[3] = 3;
+  layout[0].top.ccd[4] = 4;
+  layout[0].top.ccd[5] = 5;
+  layout[0].top.ccd[6] = 6;
+  layout[0].top.ccd[7] = 7;
+  layout[0].top.ccd[8] = 8;
+
+  layout[0].bottom.Nccd = 9;
+  ALLOCATE (layout[0].bottom.ccd, int, layout[0].bottom.Nccd);
+  layout[0].bottom.ccd[0] = 27;
+  layout[0].bottom.ccd[1] = 28;
+  layout[0].bottom.ccd[2] = 29;
+  layout[0].bottom.ccd[3] = 30;
+  layout[0].bottom.ccd[4] = 31;
+  layout[0].bottom.ccd[5] = 32;
+  layout[0].bottom.ccd[6] = 33;
+  layout[0].bottom.ccd[7] = 34;
+  layout[0].bottom.ccd[8] = 35;
+
+  layout[0].left.Nccd = 8;
+  ALLOCATE (layout[0].left.ccd, int, layout[0].left.Nccd);
+  layout[0].left.ccd[0] = 0;
+  layout[0].left.ccd[1] = 1;
+  layout[0].left.ccd[2] = 9;
+  layout[0].left.ccd[3] = 10;
+  layout[0].left.ccd[4] = 18;
+  layout[0].left.ccd[5] = 19;
+  layout[0].left.ccd[6] = 27;
+  layout[0].left.ccd[7] = 28;
+
+  layout[0].right.Nccd = 8;
+  ALLOCATE (layout[0].right.ccd, int, layout[0].right.Nccd);
+  layout[0].right.ccd[0] = 7;
+  layout[0].right.ccd[1] = 8;
+  layout[0].right.ccd[2] = 16;
+  layout[0].right.ccd[3] = 17;
+  layout[0].right.ccd[4] = 25;
+  layout[0].right.ccd[5] = 26;
+  layout[0].right.ccd[6] = 34;
+  layout[0].right.ccd[7] = 35;
+
+  return (layout);
+}
+
Index: /trunk/Ohana/src/imregister/imreg/unique.c
===================================================================
--- /trunk/Ohana/src/imregister/imreg/unique.c	(revision 69)
+++ /trunk/Ohana/src/imregister/imreg/unique.c	(revision 69)
@@ -0,0 +1,68 @@
+# include "imregister.h"
+# include "imreg.h"
+
+/* input is a subset index of image list, output is a new subset */
+int *unique_entries (int *subset, int *Nmatch) {
+
+  int i, j, k, m, Nimage, Nsubset;
+  int N, NMATCH;
+  int *match, *entry;
+  int reject;
+  RegImage *image;
+  char idxline[128];
+  char **index;
+
+  if (!output.unique) return (subset);
+
+  /* create output index */
+  N = 0;
+  NMATCH = 1000;
+  ALLOCATE (match, int, NMATCH);
+
+  Nsubset = *Nmatch;
+  image = get_images (&Nimage);
+
+  /* index = filename.ccd */
+  ALLOCATE (index, char *, Nsubset);
+  ALLOCATE (entry, int, Nsubset);
+  for (i = 0; i < Nsubset; i++) {
+    sprintf (idxline, "%s.%02d", image[subset[i]].filename, image[subset[i]].ccd);
+    index[i] = strcreate (idxline);
+    entry[i] = subset[i];
+  }
+  sortstr (index, entry, Nsubset);
+
+  /* find unique sequences */
+  for (i = 0; i < Nsubset; ) {
+    for (j = i + 1; (j < Nsubset) && (!strcmp (index[i], index[j])); j++);
+
+    /* find first entry with bias != 0, else entry i */
+    m = i;
+    for (k = i; k < j; k++) {
+      if (image[entry[k]].bias != 0) {
+	m = k;
+	break;
+      }
+    }
+    
+    /* add unique entry to output list */
+    match[N] = entry[m];
+    N ++;
+    if (N == NMATCH) {
+      NMATCH += 1000;
+      REALLOCATE (match, int, NMATCH);
+    }
+
+    /* j always points to the next entry */
+    i = j;
+  }
+
+  for (i = 0; i < Nsubset; i++) free (index[i]);
+  free (index);
+  free (entry);
+  free (subset);
+
+  *Nmatch = N;
+  return (match);
+}
+
Index: /trunk/Ohana/src/perl/src/elixir.export
===================================================================
--- /trunk/Ohana/src/perl/src/elixir.export	(revision 69)
+++ /trunk/Ohana/src/perl/src/elixir.export	(revision 69)
@@ -0,0 +1,88 @@
+#!/usr/bin/env perl
+
+if (@ARGV != 3) { die "ERROR: usage: elixir.export (rawfile) (datfile) (mode)\n"; }
+
+$datdir = `gconfig DATDIR`; chop $datdir;
+$logdir = `gconfig LOGDIR`; chop $logdir;
+$config = "$datdir/export.conf";
+
+$rawfile = $ARGV[0];
+$datfile = $ARGV[1];
+$MODE    = $ARGV[2];
+
+if (! -e $config) { die "ERROR: config file $config missing\n"; }
+
+open (FILE, $config);
+while ($line = <FILE>) {
+    if ($line =~ /^\s*$/) { next; } # skip empty lines
+    if ($line =~ /^\s*\#/) { next; } # skip commented lines
+    $Nlist = ($id, $runids, $filters, $modes, $outdir) = split (" ", $line);
+    if ($Nlist != 6) { die "ERROR in config file: $line\n"; }
+    push @id, $id;
+    $runids{$id}  = $runids;
+    $filters{$id} = $filters;
+    $modes{$id}   = $modes;
+    $outdir{$id}  = $outdir;
+}
+close (FILE);
+
+($tmp, $RUNID) = split (" ", `echo $rawfile | fields RUNID`);
+($tmp, $FILTER) = split (" ", `echo $rawfile | fields FILTER`);
+
+$FILTER = `filtnames $FILTER`; chop $FILTER;
+
+open (LOG, ">>$logdir/export.log");
+
+if ($MODE eq "any") { goto wanted; }
+
+foreach $id (@id) {
+
+    if (!findword ($MODE, $modes{$id})) { next; }
+    if (!findword ($RUNID, $runids{$id})) { next; }
+    if (!findword ($FILTER, $filters{$id})) { next; }
+
+    # success, copy datfile to outdir:
+
+    system ("cp $datfile $outdir{$id}\n");
+    if ($?) { die "ERROR: can't write $datfile to $outdir{$id}\n"; }
+
+    open (FILE, ">>$outdir/export.tbl");
+    print FILE "$datfile\n";
+    close (FILE);
+
+    print LOG "export $datfile to $outdir for $id\n";
+}
+close (LOG);
+
+print STDERR "SUCCESS: export $datfile to $outdir for $id\n";
+exit 0;
+
+wanted:
+foreach $id (@id) {
+
+    if (!findword ($RUNID, $runids{$id})) { next; }
+    if (!findword ($FILTER, $filters{$id})) { next; }
+
+    print LOG "export $datfile is wanted, process\n";
+    close (LOG);
+    print STDERR "SUCCESS: $datfile is wanted\n";
+    exit 0;
+}
+
+print LOG "export $datfile is not wanted, skip\n";
+close (LOG);
+print STDERR "ERROR: $datfile is not wanted\n";
+exit 1;
+
+sub findword {
+    # findword $WORD $list
+    $WORD = "\U$_[0]\E";
+    $list = $_[1];
+
+    @word = split (",", $list);
+    foreach $word (@word) {
+	$word = "\U$word\E";
+	if ($word eq $WORD) { return 1; }
+    }
+    return 0;
+}
Index: /trunk/Ohana/src/perl/src/gastro.raw
===================================================================
--- /trunk/Ohana/src/perl/src/gastro.raw	(revision 69)
+++ /trunk/Ohana/src/perl/src/gastro.raw	(revision 69)
@@ -0,0 +1,79 @@
+#!/usr/bin/env perl
+
+$config = "";
+@tARGV = ();
+for (; @ARGV > 0; ) {
+    if ($ARGV[0] eq "-C") {
+        $config = "-C $ARGV[1]";
+        shift; shift; next;
+    }
+    if ($ARGV[0] eq "-c") {
+        $config = "-c $ARGV[1]";
+        shift; shift; next;
+    }
+    if ($ARGV[0] eq "-D") {
+        $config = "-D $ARGV[1] $ARGV[2]";
+        shift; shift; shift; next;
+    }
+    @tARGV = (@tARGV, $ARGV[0]);
+    shift;
+}
+@ARGV = @tARGV;
+
+if (@ARGV != 1) { die "USAGE: gastro.raw (filename)\n"; }
+
+if (! -e $ARGV[0]) { die "ERROR: file $ARGV[0] missing\n"; }
+
+($tmp, $RA, $DEC, $EXT) = split (" ", `echo $ARGV[0] | fields RA DEC EXTNAME`);
+
+if ($RA  eq "") { die "ERROR: missing RA in header\n"; }
+if ($DEC eq "") { die "ERROR: missing DEC in header\n"; }
+if ($EXT eq "") { die "ERROR: missing EXTNAME in header\n"; }
+
+while ($RA  =~ s|\:| |) { }
+while ($DEC =~ s|\:| |) { }
+
+($ra, $dec) = split (" ", `echo $RA $DEC | radec -hms`);
+
+@ccdx = split (" ", `cameraconfig $config -xoff`);
+@ccdy = split (" ", `cameraconfig $config -yoff`);
+@dx   = split (" ", `cameraconfig $config -xflip`);
+@dy   = split (" ", `cameraconfig $config -yflip`);
+
+$DX = `cameraconfig $config -axis0`; chop $DX;
+$DY = `cameraconfig $config -axis1`; chop $DY;
+$NX = `cameraconfig $config -mosaicx`; chop $NX;
+$NY = `cameraconfig $config -mosaicy`; chop $NY;
+
+$N = `cameraconfig $config -N $EXT`; chop $N;
+
+$Ro = $ra  - ($ccdx[$N] - $NX/2)*$DX*0.187/3600;
+$Do = $dec + ($ccdy[$N] - $NY/2)*$DY*0.187/3600;
+$Theta = 4;
+$P1 = -1;
+$P2 =  1;
+if ($dx[$N] == 1) {
+    $P1 =  1;
+    $Theta = $Theta * -1;
+}
+if ($dy[$N] == 1) {
+    $P2 =  -1;
+    $Theta = $Theta * -1;
+}
+
+vsystem ("gastro -v $config $ARGV[0] -coords $Ro $Do -D CCD_PC1_1 $P1 -D CCD_PC2_2 $P2 -D ROT_ZERO $Theta");
+exit 0;
+
+############
+
+sub vsystem {
+    print STDERR "@_\n";
+    $status = system ("@_");
+    $status;
+}
+
+sub goodbye {
+    print STDERR "ending execution\n";
+    die "@_";
+}
+
Index: /trunk/Ohana/src/perl/src/megacenter
===================================================================
--- /trunk/Ohana/src/perl/src/megacenter	(revision 69)
+++ /trunk/Ohana/src/perl/src/megacenter	(revision 69)
@@ -0,0 +1,82 @@
+#!/usr/bin/env perl
+
+if (@ARGV != 1) { die "USAGE: megacenter (filename)\n"; }
+$ENV{'PATH'} = "$ENV{'PATH'}:/apps/elixir/bin";
+
+# currently we keep things hardwired:
+
+$input = $ARGV[0];
+$ccd   = "amp44";
+$Xref  = 973;
+$Yref  = 4560;
+
+$temp = `mktemp /tmp/center.XXXXXX`; chop ($temp);
+
+# loop over cube planes:
+open (MANA, "|mana --norc >& /dev/null");
+
+print MANA "\$CCDKEYWORD = EXTNAME\n";
+print MANA "macro go\n";
+print MANA " rd a $input -n $ccd\n";
+print MANA " wd a $temp.fits\n";
+print MANA " exec gosexphot $temp.fits $temp.sx >& /dev/null\n";
+print MANA " exec imclean -sex $temp.fits $temp.sx $temp.smp >& /dev/null\n";
+print MANA " exec gastro $temp.smp >& /dev/null\n";
+print MANA " header a -w $temp.smp\n";
+print MANA " coords a -p $Xref $Yref\n";
+print MANA " exec echo \$RA \$DEC > $temp.coords\n";
+print MANA " exit 0\n";
+print MANA "end\n";
+
+print MANA "go\n";
+print MANA "exit 1\n";
+close (MANA);
+
+($Robs, $Dobs) = split (" ", `cat $temp.coords`);
+($tmp, $Rreq, $Dreq) = split (" ", `echo $input | fields RA_DEG DEC_DEG`);
+
+($tmp, $Nastro, $Cerror) = split (" ", `echo $temp.smp | fields NASTRO CERROR`);
+
+if ($Robs < 0.0)   { $Robs += 360.0 }
+if ($Robs > 360.0) { $Robs -= 360.0 }
+
+if ($Rreq < 0.0)   { $Rreq += 360.0 }
+if ($Rreq > 360.0) { $Rreq -= 360.0 }
+
+$dR = 3600.0 * ($Rreq - $Robs) * cos ($Dobs*3.141592643589/180.0);
+$dD = 3600.0 * ($Dreq - $Dobs);
+
+$obscoords = `echo $Rreq $Dreq | radec -hh`; chop $obscoords;
+$reqcoords = `echo $Robs $Dobs | radec -hh`; chop $reqcoords;
+
+print "\n";
+printf STDOUT "$Nastro stars used in astrometry, astrometry error: %.2f\n", $Cerror;
+
+printf STDOUT "REQ COORDS: %10.6f %10.6f ($reqcoords )\n", $Rreq, $Dreq;
+printf STDOUT "OBS COORDS: %10.6f %10.6f ($obscoords )\n", $Robs, $Dobs;
+printf STDOUT "OFFSET IS: %.2f %.2f (arcsec)\n", $dR, $dD;
+
+if ($Nastro == 0) { 
+    print "No Astrometry solution was found! please try again\n";
+    goto escape;
+}
+
+if ($Cerror > 2.5) { print "WARNING: astrometry error is surprisingly high\n"; }
+if ($dR > 3600.0)  { print "WARNING: RA offset > 1 degree! is this correct?\n"; }
+if ($dD > 3600.0)  { print "WARNING: DEC offset > 1 degree! is this correct?\n"; }
+
+print STDOUT "apply this offset? y/[n] ";
+$answer = <STDIN>; chop $answer;
+$answer = "\U$answer\E";
+
+if ($answer ne "Y") { 
+    print STDOUT "offset not applied\n";
+    goto escape;
+}
+
+system ("ocoords rel t $dR $dD\n");
+system ("tcs.offset\n");
+
+escape:
+system ("rm -f $temp $temp.fits $temp.sx $temp.smp $temp.coords");
+exit 0;
Index: /trunk/Ohana/src/perl/src/mkscat
===================================================================
--- /trunk/Ohana/src/perl/src/mkscat	(revision 69)
+++ /trunk/Ohana/src/perl/src/mkscat	(revision 69)
@@ -0,0 +1,72 @@
+#!/usr/bin/env perl
+
+# warning: this function currently uses a fixed temporary name 'fix.NN.fits' 
+# for the intermediate product.  If we add this to elixir, convert to mktemp
+
+# need to assimilate the -c -C -D cmd line options -> env
+
+# check the usage
+if ($ARGV[0] eq "-h") { &usage (); }
+if ($ARGV[0] eq "-help") { &usage (); }
+if (@ARGV != 5) { &usage (); }
+
+# find the appropriate script file
+$confdir = `gconfig -q CONFDIR`; chop ($confdir);
+$script  = "$confdir/mana/scatter.pro";
+
+# run mana script:
+open (MANA, "|mana --norc");
+print MANA "input $script\n";
+print MANA "mkscat $ARGV[0] $ARGV[1] $ARGV[2] $ARGV[3] $ARGV[4]\n";
+print MANA "exit 1\n";
+close (MANA);
+print STDERR "exit statue: $?\n";
+if ($? == 2 * 256) { 
+    print STDERR "no scattered light term available\n"; 
+    exit 2;
+}
+if ($?) { die "ERROR problem with fixscat\n"; }
+
+print STDOUT "SUCCESS: finished with fixscat\n";
+exit 0;
+
+sub vsystem {
+    print STDERR "@_\n";
+    $status = system ("@_");
+    $status;
+}
+
+sub goodbye {
+    die "@_\n";
+}
+
+sub usage {
+    print "USAGE: mkscat (mosiac) (start) (stop) (filter) (ID)\n";
+    exit 1;
+}
+
+# mana within perl:  we embed the mana functions within a macro to trap the 
+# exit status.  If mana has an error with one of the steps, it will exit the macros and 
+# the second exit will be called. Otherwise, the "go" macro will perform the exit 0
+# and mana will exit with status 0
+
+# there are two possible flat-field photometric corrections: additive
+# and multiplicative:  
+# The correction images constructed by examining
+# the *difference* between dome-flats with and without the petals
+# covered is additive:  FLAT_new = (FLAT_old - SCAT) * A
+# (A is set to maintain the original normalization of chip 04)
+# 
+# The correction images constructed by examining stellar magnitude
+# difference is multiplicative: FLAT_new = (FLAT_old * SCAT) * A
+# (A is set to maintain the original normalization of chip 04)
+
+# there is a different scattered light image for each filter.
+# (these images are the same file for the additive version)
+
+# there should be no arbitrary normalization in the scattered frames
+# in the database. (we used to multiply the scattered light image by a
+# value of 10.0).  
+
+# images of the first class will be identified with the label scatter-A.0
+# images of the second class will be identified with the label scatter-B.0
