Index: /trunk/Ohana/src/addusno/Makefile
===================================================================
--- /trunk/Ohana/src/addusno/Makefile	(revision 2490)
+++ /trunk/Ohana/src/addusno/Makefile	(revision 2490)
@@ -0,0 +1,65 @@
+include ../../Configure
+CC      =       gcc -g  # override this for now for minimal test
+HOME 	=	$(ROOT)/src/addusno
+CONFIG  =	$(ROOT)/config
+PROGRAM =       addusno
+
+fix: addusno needs to be brought up-to-date with other addstar/addrefs functions
+install: fix
+
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC) -I$(LINC)/$(ARCH)
+LIBS	= 	-L$(LLIB) -lFITS -lohana -lm 
+CFLAGS	=	-o $*.$(ARCH).o $(INCS)
+CCFLAGS	=	$(INCS) $(LIBS) 
+
+ADDUSNO = \
+$(SRC)/addusno.$(ARCH).o 	$(SRC)/gcatalog.$(ARCH).o   \
+$(SRC)/gcatstats.$(ARCH).o 	$(SRC)/getusno.$(ARCH).o    \
+$(SRC)/find_matches.$(ARCH).o 	$(SRC)/wcatalog.$(ARCH).o   \
+$(SRC)/sort_lists.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o 	\
+$(SRC)/check_lockfile.$(ARCH).o \
+$(SRC)/find_proper.$(ARCH).o 	$(SRC)/reset_catalog.$(ARCH).o 	\
+$(SRC)/check_permissions.$(ARCH).o
+
+OBJ = $(ADDUSNO)
+
+default: $(PROGRAM)
+
+$(ADDUSNO): $(INC)/addusno.h
+
+# dependancy rules for binary code ##########################
+$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+
+$(BIN)/$(PROGRAM).$(ARCH): $(OBJ)
+	$(CC) $(OBJ) -o $(BIN)/$(PROGRAM).$(ARCH) $(CCFLAGS)
+
+install: $(DESTBIN)/$(PROGRAM)
+
+$(DESTBIN)/$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+	rm -f $(DESTBIN)/$(PROGRAM)
+	cp $(BIN)/$(PROGRAM).$(ARCH) $(DESTBIN)/$(PROGRAM)
+
+# utilities #################################################
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+.SUFFIXES: .$(ARCH).o
+
+.c.$(ARCH).o:
+	$(CC) $(CFLAGS) -c $<
+
+
Index: /trunk/Ohana/src/addusno/include/addstar.h
===================================================================
--- /trunk/Ohana/src/addusno/include/addstar.h	(revision 2490)
+++ /trunk/Ohana/src/addusno/include/addstar.h	(revision 2490)
@@ -0,0 +1,14 @@
+# include <ohana.h>
+# include <loneos.h>
+
+/* global variables set in parameter file */
+char   ImageCat[256];
+char   ImageTemplate[256];
+char   CatTemplate[256];
+char   GSCFILE[256];
+char   CATDIR[256];
+double NSIGMA;
+double ALPHA;
+int    VERBOSE;
+int    XOVERSCAN, YOVERSCAN;
+int    NEWPHOTCODE, PHOTCODE;
Index: /trunk/Ohana/src/addusno/include/addusno.h
===================================================================
--- /trunk/Ohana/src/addusno/include/addusno.h	(revision 2490)
+++ /trunk/Ohana/src/addusno/include/addusno.h	(revision 2490)
@@ -0,0 +1,46 @@
+# include <ohana.h>
+# include <loneos.h>
+
+/* global variables set in parameter file */
+char   CATDIR[256];
+int    VERBOSE;
+int    RESET;
+double RADIUS;
+double PROPER;
+int    USNO_RED;
+int    USNO_BLUE;
+char   CDROM[256];
+int    FORCE_RUN;
+char   PhotCodeFile[256];
+
+typedef struct {
+  double X;
+  double Y;
+  double R;
+  double D;
+  double M, dM;
+  char   dophot;
+  double sky;
+  double fx, fy, df;
+  double Mgal, Map;
+  int found;
+} Stars;
+
+typedef struct {
+  Coords coords;
+  float *X, *Y;
+  int *N;
+  double RA[2], DEC[2];
+  double Area, density, spacing;
+} CatStats;
+
+typedef struct {
+  double R, D;
+  double r, b;
+} USNOdata;
+
+typedef struct {
+  int *match;
+  float *X, *Y;
+  int *N;
+} USNOstats;
Index: /trunk/Ohana/src/addusno/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/addusno/src/ConfigInit.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/ConfigInit.c	(revision 2490)
@@ -0,0 +1,25 @@
+# include "addusno.h"
+
+ConfigInit (int argc, char **argv) {
+
+  char *config, *file;
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (&argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (0);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+  ScanConfig (config, "PHOTCODE_FILE",         "%s",  0, PhotCodeFile);
+  ScanConfig (config, "USNO_RADIUS",           "%lf", 0, &RADIUS);
+  ScanConfig (config, "USNO_PROPER",           "%lf", 0, &PROPER);
+  ScanConfig (config, "USNO_CDROM",            "%s",  0, CDROM);
+  ScanConfig (config, "CATDIR",                "%s",  0, CATDIR);
+
+  free (config);
+  free (file);
+}
Index: /trunk/Ohana/src/addusno/src/addusno.c
===================================================================
--- /trunk/Ohana/src/addusno/src/addusno.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/addusno.c	(revision 2490)
@@ -0,0 +1,77 @@
+# include "addusno.h"
+
+main (int argc, char **argv) {
+
+  int i, N, Nusno;
+  Catalog catalog;
+  CatStats catstats;
+  USNOstats usnostats;
+  USNOdata *usno, *getusno();
+  struct timeval now, then;  
+  PhotCodeData photcodes;
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  FORCE_RUN = FALSE;
+  if ((i = get_argument (argc, argv, "-f"))) {
+    FORCE_RUN = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  RESET = FALSE;
+  if ((i = get_argument (argc, argv, "-reset"))) {
+    RESET = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: addusno (region)\n");
+    exit (0);
+  }
+
+  if (!LoadPhotcodes (PhotCodeFile)) {
+    fprintf (stderr, "error loading photcodes\n");
+    exit (0);
+  }
+  
+  USNO_RED = GetPhotcodebyName ("USNO_RED");
+  if (!USNO_RED) {
+    fprintf (stderr, "ERROR: USNO_RED photcode not found in photcode table\n");
+    exit (0);
+  }
+  USNO_BLUE = GetPhotcodebyName ("USNO_BLUE");
+  if (!USNO_BLUE) {
+    fprintf (stderr, "ERROR: USNO_BLUE photcode not found in photcode table\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile (); 
+  check_permissions (argv[1]);
+
+  gcatalog (argv[1], &catalog);
+
+  if (RESET) reset_catalog (&catalog);
+
+  gcatstats (&catalog, &catstats);
+
+  usno = getusno (&usnostats, &catstats, &Nusno);
+
+  find_matches (&catstats, &catalog, &usnostats, usno, Nusno);
+
+  find_proper (&catstats, &catalog, &usnostats, usno, Nusno);
+
+  wcatalog (argv[1], &catalog);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+}
Index: /trunk/Ohana/src/addusno/src/check_lockfile.c
===================================================================
--- /trunk/Ohana/src/addusno/src/check_lockfile.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/check_lockfile.c	(revision 2490)
@@ -0,0 +1,39 @@
+# include "addusno.h"
+
+check_lockfile ()
+{
+  
+  FILE *f;
+  char filename[128];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    fprintf (stderr, "ERROR: catalog %s is locked, try again later\n", CATDIR);
+    exit (0);
+  }
+
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock file %s\n", filename);
+    exit (0);
+  }
+  fclose (f);
+
+}
+
+clear_lockfile ()
+{
+  
+  char filename[128], line[256];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    sprintf (line, "rm %s\0", filename);
+    system (line);
+  } else {
+    fprintf (stderr, "can't remove lockfile, why not?\n");
+  }
+
+}
Index: /trunk/Ohana/src/addusno/src/check_permissions.c
===================================================================
--- /trunk/Ohana/src/addusno/src/check_permissions.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/check_permissions.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "addusno.h"
+
+check_permissions (char *basefile) {
+  
+  FILE *f;
+  char *c, dir[256], filename[256];
+  struct stat filestat;
+  uid_t fuid, uid;
+  gid_t fgid, gid;
+  int status;
+
+  uid = getuid();
+  gid = getgid();
+
+  /* check permission to write to directory */
+  sprintf (filename, "%s\0", basefile);
+  c = strrchr (filename, '/');
+  if (c == (char *) NULL) {
+    strcpy (dir, ".");
+  } else {
+    *c = 0;
+    strcpy (dir, filename);
+  }
+  status = stat (dir, &filestat);
+  if (status == -1) {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  } 
+  if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRWXU)) ||
+      ((gid == filestat.st_gid) && (filestat.st_mode & S_IRWXG)) || 
+      (filestat.st_mode & S_IRWXO)) {
+  } else {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  }
+  
+  /* check permission to write to file */
+  sprintf (filename, "%s\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+  /* check permission to write to backup file */
+  sprintf (filename, "%s~\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+}
Index: /trunk/Ohana/src/addusno/src/config.c
===================================================================
--- /trunk/Ohana/src/addusno/src/config.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/config.c	(revision 2490)
@@ -0,0 +1,110 @@
+# include <ohana.h>
+# define D_NBYTES 4096
+
+char *LoadConfigFile (filename) 
+char *filename; 
+{
+  
+  FILE *f;
+  int i, done, Nbytes, NBYTES, size;
+  char *config;
+  
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "couldn't find %s\n", filename);
+    return ((char *) NULL);
+  }
+ 
+  NBYTES = D_NBYTES;
+  ALLOCATE (config, char, NBYTES);
+ 
+  size = 0;
+  done = FALSE;
+  for (i = 0; !done; i++) {
+    Nbytes = Fread (&config[i*D_NBYTES], sizeof(char), D_NBYTES, f, "char");
+    size += Nbytes;
+    if (Nbytes < D_NBYTES) 
+      done = TRUE;
+    else {
+      NBYTES += D_NBYTES;
+      REALLOCATE (config, char, NBYTES);
+    }
+  }
+  
+  config[size] = '\n';
+  config[size+1] = 0;
+  REALLOCATE (config, char, size + 2);
+ 
+  fclose (f);
+
+  return (config);
+}
+
+int ScanConfig /* we expect one more field: the pointer to the value requested */
+# ifndef ANSI
+(config, field, mode, va_alist) 
+ char *config; char *field, *mode; va_dcl
+# else
+(char       config[],
+ char       field[],
+ char       mode[],...)
+# endif
+{
+ 
+  int i, j;
+  char *p, *p2, tmp[256];
+  va_list argp;
+  double value;
+  
+# ifndef ANSI
+  va_start (argp);
+# else
+  va_start (argp, N);
+# endif
+  
+  /* find the correct line with field */
+  p2 = config;
+  for (i = 0; ; i++) {
+    if (!strncmp (field, p2, strlen(field))) {
+      p = p2 + strlen (field);
+      break;
+    }
+    else {
+      p2 = strchr (p2, '\n');
+      if (p2 == (char *) NULL) {
+	fprintf (stderr, "entry %s not found in config file\n", field);
+	return (FALSE);
+      }
+      else p2++;
+    }
+  }
+  if (!strcmp (mode, "%s")) {
+    p2 = strchr (p, '\n');
+    if (p2 == (char *) NULL)
+      p2 = config + strlen(config);
+    bcopy (p, tmp, (p2-p));
+    tmp[(p2-p)] = 0;
+    stripwhite (tmp);
+    p2 = va_arg (argp, char *);
+    strcpy (p2, tmp);
+  }
+  else {
+ 
+    /* try to get a numerical value from the field */
+    value = strtod (p, &p2);
+    if ((*p2 == 'd') || (*p2 == 'D')) 
+      value *= pow (10.0, atof (p2 + 1));
+    
+    if (!strcmp (mode, "%d"))  *va_arg (argp, int *)       = value;
+    if (!strcmp (mode, "%u"))  *va_arg (argp, unsigned *)  = value;
+    if (!strcmp (mode, "%ld")) *va_arg (argp, long *)      = value;
+    if (!strcmp (mode, "%hd")) *va_arg (argp, short *)     = value;
+    if (!strcmp (mode, "%f"))  *va_arg (argp, float *)     = value;
+    if (!strcmp (mode, "%lf")) *va_arg (argp, double *)    = value;
+    
+  }
+ 
+  va_end (argp);
+  return (TRUE);
+  
+}
Index: /trunk/Ohana/src/addusno/src/coordops.c
===================================================================
--- /trunk/Ohana/src/addusno/src/coordops.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/coordops.c	(revision 2490)
@@ -0,0 +1,342 @@
+# include "addstar.h"
+
+XY_to_RD (ra, dec, x, y, coords)
+double *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+# if 1
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+# else
+  {
+# endif
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN")) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+fXY_to_RD (ra, dec, x, y, coords)
+float *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+RD_to_XY (x, y, ra, dec, coords)
+double *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    /* fprintf (stderr, "approximate to polynomial TAN plane fit\n");  */
+  }
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+fRD_to_XY (x, y, ra, dec, coords)
+float *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+
+GetCoords (coords, header) 
+Coords coords[];
+Header header[];
+{
+
+  int status;
+  double rotate;
+
+  rotate = 0.0;
+  coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+  coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+  coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+  coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+  strcpy (coords[0].ctype, "NONE");
+
+  status = TRUE; 
+  if (fits_scan (header, "CTYPE2", "%s", 1, coords[0].ctype)) {
+    status  = fits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+    status &= fits_scan (header, "CRPIX1", "%lf", 1, &coords[0].crpix1);
+    status &= fits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+    status &= fits_scan (header, "CRPIX2", "%lf", 1, &coords[0].crpix2);
+    if (fits_scan (header, "CDELT1", "%lf", 1, &coords[0].cdelt1)) {
+      status &= fits_scan (header, "CDELT2", "%lf", 1, &coords[0].cdelt2);
+      if (fits_scan (header, "CROTA2", "%lf", 1, &rotate)) {
+	coords[0].pc1_1 =  cos(rotate*RAD_DEG);
+	coords[0].pc1_2 = -sin(rotate*RAD_DEG);
+	coords[0].pc2_1 =  sin(rotate*RAD_DEG);
+	coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+      }
+      if (fits_scan (header, "PC001001", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "PC001002", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "PC002001", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "PC002002", "%lf", 1, &coords[0].pc2_2);
+      }
+    }
+    else {
+      if (fits_scan (header, "CD1_1", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "CD1_2", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "CD2_1", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "CD2_2", "%lf", 1, &coords[0].pc2_2);
+	coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      }
+      else {
+	status = FALSE;
+      }
+    }
+  }
+  else {
+    if (fits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1)) {
+      status  = fits_scan (header, "RA_X", "%lf", 1, &coords[0].pc1_1);
+      status &= fits_scan (header, "RA_Y", "%lf", 1, &coords[0].pc1_2);
+      status &= fits_scan (header, "DEC_O", "%lf", 1, &coords[0].crval2);  
+      status &= fits_scan (header, "DEC_X", "%lf", 1, &coords[0].pc2_1);
+      status &= fits_scan (header, "DEC_Y", "%lf", 1, &coords[0].pc2_2);
+      coords[0].crpix1 = coords[0].crpix2 = 0.0;
+      coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      strcpy (coords[0].ctype, "GENE");
+    }
+  }
+  if (!status) {
+    fprintf (stderr, "error getting all elements for coordinate mode %d\n", coords[0].ctype);
+    coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+    coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+    coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+    coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+    strcpy (coords[0].ctype, "NONE");
+  }
+}
+
+
+  /* -PLY projection is an extrapolation of the -TAN projection. 
+     In addition to the usual linear terms of CRPIXi, PC00i00j, there are 
+     higher order polynomial terms (up to 3rd order):
+     Axis 1 terms:
+     PCA1X2Y0 = coords.polyterm[0][0] = x^2                                             
+     PCA1X1Y1 = coords.polyterm[1][0] = xy                                          
+     PCA1X0Y2 = coords.polyterm[2][0] = y^2                                             
+     PCA1X3Y0 = coords.polyterm[3][0] = x^3                                             
+     PCA1X2Y1 = coords.polyterm[4][0] = x^2 y                                             
+     PCA1X1Y2 = coords.polyterm[5][0] = x y^2                                             
+     PCA1X0Y3 = coords.polyterm[6][0] = y^2                                              
+     Axis 2 terms:
+     PCA2X2Y0 = coords.polyterm[0][1] = x^2                                               
+     PCA2X1Y1 = coords.polyterm[1][1] = xy                                                
+     PCA2X0Y2 = coords.polyterm[2][1] = y^2                                               
+     PCA2X3Y0 = coords.polyterm[3][1] = x^3                                               
+     PCA2X2Y1 = coords.polyterm[4][1] = x^2 y                                             
+     PCA2X1Y2 = coords.polyterm[5][1] = x y^2                                             
+     PCA2X0Y3 = coords.polyterm[6][1] = y^2                                               
+  */
Index: /trunk/Ohana/src/addusno/src/dumpcat.c
===================================================================
--- /trunk/Ohana/src/addusno/src/dumpcat.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/dumpcat.c	(revision 2490)
@@ -0,0 +1,60 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  int i, j, Nstars, Nimage, Nregions;
+  Average *average;
+  Measure *measure;
+  Missing *missing;
+  Catalog catalog;
+  GSCRegion region;
+  FILE *f;
+  
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: dumpcat catalog output mode(0,1,2,3)\n");
+    exit (0);
+  }
+
+  strcpy (region.filename, argv[1]);
+
+  gcatalog (&region, &catalog);
+
+  f = fopen (argv[2], "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "failed to open file %s for write\n", argv[2]);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  average = catalog.average;
+  for (i = 0; i < catalog.Naverage; i++) {
+    fprintf (f, "%10.6f %10.6f %7.3f %3d %3d %8d %d\n", average[i].R, average[i].D, 
+	     0.001*average[i].M, average[i].Nm, average[i].Nn, average[i].offset, catalog.measure[average[i].offset].t);
+    if ((atof(argv[3]) == 1) || (atof(argv[3]) == 3)) {
+      measure = &catalog.measure[average[i].offset];
+      for (j = 0; j < average[i].Nm; j++) {
+	fprintf (f, "  %d %d %f %f %d\n", measure[j].dR, measure[j].dD, 0.001*measure[j].M, 
+		  measure[j].t, measure[j].average);
+      }
+    }
+    if ((atof(argv[3]) == 2) || (atof(argv[3]) == 3)) {
+      if (average[i].Nn > 0) {
+	missing = &catalog.missing[average[i].missing];
+	for (j = 0; j < average[i].Nn; j++) {
+	  fprintf (f, "  %f\n", missing[j].t);
+	}
+      } else { 
+	fprintf (f, "no missing obs\n");
+      }
+    }
+  }
+
+    
+
+  fclose (f);
+    
+
+}
Index: /trunk/Ohana/src/addusno/src/dumpusno.c
===================================================================
--- /trunk/Ohana/src/addusno/src/dumpusno.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/dumpusno.c	(revision 2490)
@@ -0,0 +1,144 @@
+# include <stdio.h>
+# include <math.h>
+
+# define NZONE 24
+
+int SPDzone[] = {
+  0, 75, 450, 375, 1500, 1650, 300, 1425, 1725, 525, 1275, 225, 
+  675, 150, 600, 1575, 750, 975, 900, 1050, 1125, 1200, 825, 1350};
+
+int USNOdisk[] = {
+  1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10};
+
+# ifndef ALLOCATE
+# define ALLOCATE(X,T,S)  \
+  X=(T *)malloc((unsigned) ((S)*sizeof(T)));\
+  if(X==NULL) \
+    { \
+      fprintf(stderr,"failed to malloc X\n");\
+        exit(0);\
+    } 
+# define REALLOCATE(X,T,S) \
+  X=(T *)realloc(X,(unsigned) ((S)*sizeof(T))); \
+  if(X==NULL) \
+    { \
+       fprintf(stderr,"failed to realloc X\n"); \
+       exit(0); \
+    }
+# endif /* ALLOCATE */
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  long int offset;
+  int i, bin, first, last, Nstars, nitems, Nitems, Nbins;
+  float hours[100];
+  int start[100], number[100], *buffer, *buf;
+  char filename[128], c;
+  FILE *f;
+  float r, b;
+  double RA0, DEC0, RA1, DEC1, tmp;
+  int iDEC0, iDEC1, iRA0, iRA1;
+  int spd, spd_start, spd_end, disk;
+  double atof();
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: addusno RA DEC dRA dDEC (mnt)\n");
+    exit (0);
+  }
+
+  RA0 = atof (argv[1]);
+  DEC0 = atof (argv[2]);
+  RA1 = RA0 + atof (argv[3]);
+  DEC1 = DEC0 + atof (argv[4]);
+  iRA0 = RA0 * 360000.0;
+  iRA1 = RA1 * 360000.0;
+  iDEC0 = (DEC0 + 90.0) * 360000.0;
+  iDEC1 = (DEC1 + 90.0) * 360000.0;
+  
+  spd_start = (int)((DEC0 + 90) / 7.5) * 75.0;
+  tmp = (DEC1 + 90) / 7.5;
+  if (tmp > (int)(tmp)) {
+    spd_end =   (int)(1 + (DEC1 + 90) / 7.5) * 75.0;
+  } else {
+    spd_end =   (int)(0 + (DEC1 + 90) / 7.5) * 75.0;
+  }
+
+  for (spd = spd_start; spd < spd_end; spd += 75) {
+    disk = -1;
+    for (i = 0; i < NZONE; i++) {
+      if (spd == SPDzone[i]) 
+	disk = USNOdisk[i];
+    }
+    if (disk < 0) {
+      fprintf (stderr, "ERROR: can't find cdrom for spd %d\n",  spd);
+      exit (0);
+    }
+    
+    /* load accelerator file */
+    sprintf (filename, "%s/zone%04d.acc\0", argv[5], spd);
+    fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "can't open file %s, is cdrom %d in drive?\n", filename, disk);
+      fprintf (stderr, "press return when ready to continue: ");
+      fscanf (stdin, "%c", &c);
+      fprintf (stderr, "trying again...\n");
+      f = fopen (filename, "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "still can't open file %s, is cdrom %d in drive?\n", filename, disk);
+	exit (0);  
+      }
+    }
+    for (i = 0; fscanf (f, "%f %d %d", &hours[i], &start[i], &number[i]) != EOF; i++);
+    Nbins = i;
+    fclose (f);
+    
+    first = RA0 / 3.75;
+    last  = RA1 / 3.75;
+    if ((first >= Nbins) || (last >= Nbins)) {
+      fprintf (stderr, "RA out of range\n");
+      exit (0);
+    }
+    
+    /* open data file */
+    sprintf (filename, "%s/zone%04d.cat\0", argv[5], spd);
+    fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "can't open file %s\n", filename);
+      exit (0);
+    }
+    /* advance file pointer to first slice */
+    offset = 3*sizeof(int)*(start[first] - 1);
+    fseek (f, offset, SEEK_SET);
+    /* on each loop, load data from an RA slice of the catalog */
+    for (bin = first; bin < last + 1; bin++) {
+      Nitems = 3*number[bin];
+      ALLOCATE (buffer, int, Nitems);
+      nitems = Fread (buffer, sizeof(int), Nitems, f, "int");
+      if (nitems != Nitems) {
+	fprintf (stderr, "error reading data from file %s (%d, %d, %d)\n", 
+		 filename, start[bin], number[bin], nitems);
+	exit (0);
+      }
+      buf = buffer;
+      /* print out data from slice within RA and DEC range */
+      for (i = 0; i < number[bin]; i++, buf+=3) {
+	if ((buf[0] > iRA0) && (buf[0] < iRA1) &&
+	    (buf[1] > iDEC0) && (buf[1] < iDEC1)) {
+	  r = 0.1*(buf[2] - 1000*((int)(buf[2]/1000)));
+	  b = 0.1*((int)(buf[2] - 1000000*((int)(buf[2]/1000000))) / 1000);
+	  fprintf (stdout, "%f %f %d %f %f\n", 
+		   buf[0]/360000.0, buf[1]/360000.0 - 90.0, buf[2], r, b);
+	}
+      }
+      free (buffer);
+    }
+    fclose (f);
+  }
+}
+
+
Index: /trunk/Ohana/src/addusno/src/find_matches.c
===================================================================
--- /trunk/Ohana/src/addusno/src/find_matches.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/find_matches.c	(revision 2490)
@@ -0,0 +1,157 @@
+# include "addusno.h"
+
+find_matches (catstats, catalog, usnostats, usno, Nusno)
+CatStats catstats[];
+Catalog catalog[];
+USNOstats usnostats[];
+USNOdata usno[];
+int Nusno;
+{
+
+  int i, j, k, n, m, N, first_j;
+  double RADIUS2;
+  float *X1, *Y1, *X2, *Y2, *usnodist;
+  float dX, dY, dR;
+  int *N1, *N2,  *next, last, *catmatch;
+  int Nave, Nmeas, NMEAS, Nmatch;
+  unsigned int flags;
+  Measure *tmpmeasure;
+  Coords *tcoords;
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  N1 = catstats[0].N;
+  Nave = catalog[0].Naverage;
+
+  X2 = usnostats[0].X;
+  Y2 = usnostats[0].Y;
+  N2 = usnostats[0].N;
+
+  ALLOCATE (usnodist, float, Nave);
+  ALLOCATE (catmatch, int, Nave);
+  bzero (usnodist, Nave*sizeof(float));
+  bzero (catmatch, Nave*sizeof(int));
+
+  /* set up link listed pointers for new measurements */
+  Nmatch = 0;
+  Nmeas = catalog[0].Nmeasure;
+  NMEAS = Nmeas + 1000;
+  ALLOCATE (next, int, NMEAS);
+  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+  /* set up pointers for linked list of measurements */
+  for (i = 0; i < Nmeas - 1; i++) {
+    next[i] = i+1;
+  }
+  next[i] = -1;
+  last = i;
+  
+  /* choose a radius for matches */
+  /* 0.02 corrects cerror to arcsec from storage units */
+  RADIUS2 = RADIUS*RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nave) && (j < Nusno); ) {
+    if (catalog[0].average[N1[i]].code & ID_MOVING) { 
+      /* this is not a star, skip */
+      i++;
+      continue;
+    }
+    dX = X1[i] - X2[j];
+    if (dX <= -2*RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*RADIUS) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*RADIUS) && (j < Nusno); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < RADIUS2) {  /* new measurement of this star */
+	/** insert star in measurement list */
+	n = N1[i];  /* N1 refers to the average[] list */
+	N = N2[j];  /* N2 refers to the usno[] list */
+	if ((catalog[0].average[n].code & ID_USNO) && (usnodist[i] < dR)) {
+	  /* existing USNO match is closer than this new one, skip this one */
+	  continue;
+	}
+	if (catalog[0].average[n].code & ID_USNO) {
+	  /* this USNO match is closer than previous one, fix usno[N].match */
+	  /* old one isn't a match, unset it */
+	  usnostats[0].match[catmatch[i]] = -1;
+	  continue;
+	}
+	usnodist[i] = dR;
+	m = catalog[0].average[n].offset;  /* first measurement of this star */
+	for (k = 0; k < catalog[0].average[n].Nm - 1; k++)
+	  m = next[m];
+	next[Nmeas+1] = next[m]; /* insert 2 measurements in linked list */
+	next[Nmeas] = Nmeas + 1;
+	next[m] = Nmeas;
+	if (next[Nmeas+1] == -1) { /* last just was moved */
+	  last = Nmeas+1;
+	}
+	Nmatch ++;
+	
+	/** add measurements for this star **/
+	catalog[0].measure[Nmeas].dR  = 360000.0*(catalog[0].average[n].R - usno[N].R);
+	catalog[0].measure[Nmeas].dD  = 360000.0*(catalog[0].average[n].D - usno[N].D);
+	catalog[0].measure[Nmeas].M   = 1000.0*fabs(usno[N].r);
+	catalog[0].measure[Nmeas].Mcal= 0;    /* above measurement is exact */
+	catalog[0].measure[Nmeas].dM  = 100;  /* error in input files stored in thousandths of mag */
+	catalog[0].measure[Nmeas].t   = 0;    /* a flag: if 0, image is not in database */
+	catalog[0].measure[Nmeas].averef  = n;
+	catalog[0].measure[Nmeas].source = USNO_RED; 
+	catalog[0].measure[Nmeas].dophot = 0; 
+	catalog[0].measure[Nmeas+1].dR  = catalog[0].measure[Nmeas].dR;
+	catalog[0].measure[Nmeas+1].dD  = catalog[0].measure[Nmeas].dD;
+	catalog[0].measure[Nmeas+1].M   = 1000.0*fabs(usno[N].b);
+	catalog[0].measure[Nmeas+1].Mcal= 0;    /* above measurement is exact */
+	catalog[0].measure[Nmeas+1].dM  = 100;  /* error in input files stored in thousandths of mag */
+	catalog[0].measure[Nmeas+1].t   = 0;    /* a flag: if 0, image is not in database */
+	catalog[0].measure[Nmeas+1].averef  = n;
+	catalog[0].measure[Nmeas+1].source = USNO_BLUE; 
+	catalog[0].measure[Nmeas+1].dophot = 0; 
+	/* add flag in average to mark as matched with the USNO catalog */
+	catalog[0].average[n].code |= ID_USNO;
+	/* add matched value to usno list, to keep track for next round */
+	usnostats[0].match[N] = i;
+	catmatch[i] = N;
+	/* we add two measurement for each star: 1 in r, 1 in b */
+	catalog[0].average[n].Nm +=2;
+	Nmeas +=2;  
+	if (Nmeas == NMEAS - 2) {  /* just to be safe... */
+	  NMEAS = Nmeas + 1000;
+	  REALLOCATE (next, int, NMEAS);
+	  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  REALLOCATE (catalog[0].measure, Measure, Nmeas);
+
+  /* fix order of Measure (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmeasure, Measure, Nmeas);
+  for (i = 0; i < Nave; i++) {
+    n = catalog[0].average[i].offset;
+    catalog[0].average[i].offset = N;
+    for (k = 0; k < catalog[0].average[i].Nm; k++, N++) {
+      tmpmeasure[N] = catalog[0].measure[n]; 
+      n = next[n];
+    }
+  }
+  free (catalog[0].measure);
+  catalog[0].measure = tmpmeasure;
+    
+  catalog[0].Nmeasure = Nmeas;
+  if (VERBOSE) fprintf (stderr, "Nusno, Nave, Nmeas: %d %d %d, (%d matches)\n", Nusno, Nave, Nmeas, Nmatch);
+}
+
Index: /trunk/Ohana/src/addusno/src/find_proper.c
===================================================================
--- /trunk/Ohana/src/addusno/src/find_proper.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/find_proper.c	(revision 2490)
@@ -0,0 +1,158 @@
+# include "addusno.h"
+
+find_proper (catstats, catalog, usnostats, usno, Nusno)
+CatStats catstats[];
+Catalog catalog[];
+USNOstats usnostats[];
+USNOdata usno[];
+int Nusno;
+{
+
+  int i, j, k, n, m, N, first_j;
+  double RADIUS2, PROPER2;
+  float *X1, *Y1, *X2, *Y2, *usnodist;
+  float dX, dY, dR, dR2;
+  int *N1, *N2,  *next, last;
+  int Nave, Nmeas, NMEAS, Nmatch;
+  unsigned int flags;
+  Measure *tmpmeasure;
+  Coords *tcoords;
+  int already_matched, far_enough;
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  N1 = catstats[0].N;
+  Nave = catalog[0].Naverage;
+
+  /* no need to do this twice!! */
+  ALLOCATE (usnodist, float, Nave);
+  bzero (usnodist, Nave*sizeof(float));
+
+  X2 = usnostats[0].X;
+  Y2 = usnostats[0].Y;
+  N2 = usnostats[0].N;
+
+ /* set up link listed pointers for new measurements */
+  Nmatch = 0;
+  Nmeas = catalog[0].Nmeasure;
+  NMEAS = Nmeas + 1000;
+  ALLOCATE (next, int, NMEAS);
+  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+  /* set up pointers for linked list of measurements */
+  for (i = 0; i < Nmeas - 1; i++) {
+    next[i] = i+1;
+  }
+  next[i] = -1;
+  last = i;
+  
+  /* choose a radius for matches */
+  PROPER2 = PROPER*PROPER;
+  RADIUS2 = RADIUS*RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nave) && (j < Nusno); ) {
+    if (catalog[0].average[N1[i]].code & ID_MOVING) { 
+      /* this is not a star, skip */
+      i++;
+      continue;
+    }
+    if (catalog[0].average[N1[i]].Nm < 3) { 
+      /* may just be a noise spike, skip */
+      i++;
+      continue;
+    }
+    if (catalog[0].average[N1[i]].code & ID_USNO) {
+      /* already matched with USNO, skip this one */
+      i++;
+      continue;
+    }
+    dX = X1[i] - X2[j];
+    if (dX <= -2*PROPER) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*PROPER) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*PROPER) && (j < Nusno); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < PROPER2) {  
+	n = N1[i];  /* N1 refers to the average[] list */
+	N = N2[j];  /* N2 refers to the usno[] list */
+	if (usnostats[0].match[N] > -1) 
+	  continue;
+	if ((catalog[0].average[n].code & ID_USNO) && (usnodist[i] < dR)) {
+	  /* existing USNO match is closer than this new one, skip this one */
+	  continue;
+	}
+	usnodist[i] = dR;
+	m = catalog[0].average[n].offset;  /* first measurement of this star */
+	for (k = 0; k < catalog[0].average[n].Nm - 1; k++)
+	  m = next[m];
+	next[Nmeas+1] = next[m]; /* insert 2 measurements in linked list */
+	next[Nmeas] = Nmeas + 1;
+	next[m] = Nmeas;
+	if (next[Nmeas+1] == -1) { /* last just was moved */
+	  last = Nmeas+1;
+	}
+	Nmatch ++;
+	
+	/** add measurements for this star **/
+	catalog[0].measure[Nmeas].dR  = 360000.0*(catalog[0].average[n].R - usno[N].R);
+	catalog[0].measure[Nmeas].dD  = 360000.0*(catalog[0].average[n].D - usno[N].D);
+	catalog[0].measure[Nmeas].M   = 1000.0*fabs(usno[N].r);
+	catalog[0].measure[Nmeas].Mcal= 0;    /* above measurement is exact */
+	catalog[0].measure[Nmeas].dM  = 100;  /* error in input files stored in thousandths of mag */
+	catalog[0].measure[Nmeas].t   = 0;    /* a flag: if 0, image is not in database */
+	catalog[0].measure[Nmeas].averef  = n;
+	catalog[0].measure[Nmeas].source = USNO_RED; 
+	catalog[0].measure[Nmeas+1].dR  = catalog[0].measure[Nmeas].dR;
+	catalog[0].measure[Nmeas+1].dD  = catalog[0].measure[Nmeas].dD;
+	catalog[0].measure[Nmeas+1].M   = 1000.0*fabs(usno[N].b);
+	catalog[0].measure[Nmeas+1].Mcal= 0;    /* above measurement is exact */
+	catalog[0].measure[Nmeas+1].dM  = 100;  /* error in input files stored in thousandths of mag */
+	catalog[0].measure[Nmeas+1].t   = 0;    /* a flag: if 0, image is not in database */
+	catalog[0].measure[Nmeas+1].averef  = n;
+	catalog[0].measure[Nmeas+1].source = USNO_BLUE; 
+	/* add flag in average to mark as matched with the USNO catalog */
+	catalog[0].average[n].code |= (ID_PROPER | ID_USNO);
+	
+	/* we add two measurement for each star: 1 in r, 1 in b */
+	catalog[0].average[n].Nm +=2;
+	Nmeas +=2;  
+	if (Nmeas == NMEAS - 2) {  /* just to be safe... */
+	  NMEAS = Nmeas + 1000;
+	  REALLOCATE (next, int, NMEAS);
+	  REALLOCATE (catalog[0].measure, Measure, NMEAS);
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  REALLOCATE (catalog[0].measure, Measure, Nmeas);
+
+  /* fix order of Measure (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmeasure, Measure, Nmeas);
+  for (i = 0; i < Nave; i++) {
+    n = catalog[0].average[i].offset;
+    catalog[0].average[i].offset = N;
+    for (k = 0; k < catalog[0].average[i].Nm; k++, N++) {
+      tmpmeasure[N] = catalog[0].measure[n]; 
+      n = next[n];
+    }
+  }
+  free (catalog[0].measure);
+  catalog[0].measure = tmpmeasure;
+    
+  catalog[0].Nmeasure = Nmeas;
+  if (VERBOSE) fprintf (stderr, "Nusno, Nave, Nmeas: %d %d %d, (%d matches)\n", Nusno, Nave, Nmeas, Nmatch);
+}
+
Index: /trunk/Ohana/src/addusno/src/gcatalog.c
===================================================================
--- /trunk/Ohana/src/addusno/src/gcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/gcatalog.c	(revision 2490)
@@ -0,0 +1,100 @@
+# include "addusno.h"
+
+gcatalog (catname, catalog)
+char *catname;
+Catalog catalog[];
+{
+  
+  char filename[128];
+  int Nitems, nitems;
+  int i, Nmeas, Nmiss, done;
+  FILE *f;
+  struct tm *local;
+  struct timeval now;
+
+
+  sprintf (filename, "%s/%s\0", CATDIR, catname);
+
+  /* read catalog header */
+  if (!fits_read_header (filename, &catalog[0].header)) {
+    fprintf (stderr, "ERROR: can't open catalog file: %s\n", filename);
+    exit (0);
+  }
+
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open catalog file: %s\n", filename);
+    exit (0);
+  }
+  fseek (f, catalog[0].header.size, SEEK_SET); 
+
+  /** find number of stars, measurements **/
+  catalog[0].Nmissing = catalog[0].Naverage = catalog[0].Nmeasure = 0;
+  fits_scan (&catalog[0].header, "NSTARS", "%d", 1, &catalog[0].Naverage);
+  fits_scan (&catalog[0].header, "NMEAS", "%d", 1, &catalog[0].Nmeasure);
+  fits_scan (&catalog[0].header, "NMISS", "%d", 1, &catalog[0].Nmissing);
+  ALLOCATE (catalog[0].average, Average, MAX (catalog[0].Naverage, 1));
+  ALLOCATE (catalog[0].measure, Measure, MAX (catalog[0].Nmeasure, 1));
+  ALLOCATE (catalog[0].missing, Missing, MAX (catalog[0].Nmissing, 1));
+
+  done = FALSE;
+  fits_scan (&catalog[0].header, "ADDUSNO", "%t", 1, &done);
+  if (done && !FORCE_RUN) {
+    if (VERBOSE) fprintf (stderr, "SUCCESS: file already up-to-date %s\n", filename);
+    fclose (f);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  if (catalog[0].Naverage == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars yet in catalog %s\n", filename);
+    clear_lockfile ();
+    fclose (f);
+    exit (0);
+  }
+
+  /* read average values */
+  Nitems = catalog[0].Naverage;
+  nitems = Fread (catalog[0].average, sizeof(Average), Nitems, f, "average");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (1)\n", filename);
+    fclose (f);
+    exit (0);
+  }
+  
+  /* read measurements */
+  Nitems = catalog[0].Nmeasure;
+  nitems = Fread (catalog[0].measure, sizeof(Measure), Nitems, f, "measure");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (2)\n", filename);
+    fclose (f);
+    exit (0);
+  }
+  
+  /* read missing */
+  Nitems = catalog[0].Nmissing;
+  nitems = Fread (catalog[0].missing, sizeof(Missing), Nitems, f, "missing");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (3)\n", filename);
+    fclose (f);
+    exit (0);
+  }
+  
+  if (VERBOSE) fprintf (stderr, "read %d stars from catalog file %s (%d measurements, %d missing)\n", 
+	   catalog[0].Naverage, filename, catalog[0].Nmeasure, catalog[0].Nmissing);
+
+  for (i = Nmeas = Nmiss = 0; i < catalog[0].Naverage; i++) {
+    Nmeas += catalog[0].average[i].Nm; 
+    Nmiss += catalog[0].average[i].Nn; 
+  }
+  if ((Nmeas != catalog[0].Nmeasure) || (Nmiss != catalog[0].Nmissing)) {
+    fprintf (stderr, "ERROR: data in catalog %s is corrupt, sums don't check\n");
+    fprintf (stderr, "ERROR: Nmeas: %d, %d\n", Nmeas, catalog[0].Nmeasure);
+    fprintf (stderr, "ERROR: Nmiss: %d, %d\n", Nmiss, catalog[0].Nmissing);
+    exit (0);
+  }
+
+  fclose (f);
+
+}
+
Index: /trunk/Ohana/src/addusno/src/gcatstats.c
===================================================================
--- /trunk/Ohana/src/addusno/src/gcatstats.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/gcatstats.c	(revision 2490)
@@ -0,0 +1,64 @@
+# include "addusno.h"
+
+gcatstats (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i;
+  double RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  int *N1;
+  Coords *tcoords;
+  
+  fits_scan (&catalog[0].header, "RA0", "%lf", 1, &MinRA);
+  fits_scan (&catalog[0].header, "RA1", "%lf", 1, &MaxRA);
+  fits_scan (&catalog[0].header, "DEC0", "%lf", 1, &MinDEC);
+  fits_scan (&catalog[0].header, "DEC1", "%lf", 1, &MaxDEC);
+
+  /* 
+  MinRA = MaxRA = catalog[0].average[0].R;
+  MinDEC = MaxDEC = catalog[0].average[0].D;
+  for (i = 0; i < catalog[0].Naverage; i++) {
+    MinRA =  MIN (catalog[0].average[i].R, MinRA);
+    MaxRA =  MAX (catalog[0].average[i].R, MaxRA);
+    MinDEC =  MIN (catalog[0].average[i].D, MinDEC);
+    MaxDEC =  MAX (catalog[0].average[i].D, MaxDEC);
+  }
+  */
+  /* double check on region RA and DEC ranges */
+  DecCenter = 0.5*(MinDEC + MaxDEC);
+  RaCenter = 0.5*(MinRA + MaxRA);
+
+  catstats[0].RA[0] = MinRA;
+  catstats[0].RA[1] = MaxRA;
+  catstats[0].DEC[0] = MinDEC;
+  catstats[0].DEC[1] = MaxDEC;
+
+  /** allocate local arrays **/
+  ALLOCATE (catstats[0].X, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].Y, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].N, int,   catalog[0].Naverage);
+
+  /* project onto rectilinear grid with 1 arcsec pixels, sort by X */
+  /* reference for coords is center of field  */
+  catstats[0].coords.crval1 = RaCenter;
+  catstats[0].coords.crval2 = DecCenter;
+  catstats[0].coords.crpix1 = catstats[0].coords.crpix2 = 0.0;
+  catstats[0].coords.cdelt1 = catstats[0].coords.cdelt2 = 1.0 / 3600.0;
+  catstats[0].coords.pc1_1 = catstats[0].coords.pc2_2 = 1.0;
+  catstats[0].coords.pc1_2 = catstats[0].coords.pc2_1 = 0.0;
+  strcpy (catstats[0].coords.ctype, "RA---TAN");
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < catalog[0].Naverage; i++, X1++, Y1++) {
+    fRD_to_XY (X1, Y1, catalog[0].average[i].R, catalog[0].average[i].D, tcoords);
+    catstats[0].N[i] = i;
+  }
+  if (catalog[0].Naverage > 1) sort_lists (catstats[0].X, catstats[0].Y, catstats[0].N, catalog[0].Naverage);
+  
+}
+
Index: /trunk/Ohana/src/addusno/src/getusno.c
===================================================================
--- /trunk/Ohana/src/addusno/src/getusno.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/getusno.c	(revision 2490)
@@ -0,0 +1,156 @@
+# include "addusno.h"
+# define NZONE 24
+
+int SPDzone[] = {
+  0, 75, 450, 375, 1500, 1650, 300, 1425, 1725, 525, 1275, 225, 
+  675, 150, 600, 1575, 750, 975, 900, 1050, 1125, 1200, 825, 1350};
+
+int USNOdisk[] = {
+  1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10};
+
+USNOdata *getusno (usnostats, catstats, Nusno)
+CatStats catstats[];
+USNOstats usnostats[];
+int *Nusno;
+{
+
+  long int offset;
+  int i, bin, first, last, Nstars, nitems, Nitems, Nbins, *N1;
+  float hours[100];
+  int start[100], number[100], *buffer, *buf;
+  char filename[128], c;
+  FILE *f;
+  float r, b, *X1, *Y1;
+  double RA0, DEC0, RA1, DEC1;
+  int iDEC0, iDEC1, iRA0, iRA1;
+  int spd, spd_start, spd_end, disk;
+  int NUSNO, nusno;
+  USNOdata *usno;
+  Coords *tcoords;
+
+  iRA0 = catstats[0].RA[0] * 360000.0;
+  iRA1 = catstats[0].RA[1] * 360000.0;
+  iDEC0 = (catstats[0].DEC[0] + 90.0) * 360000.0;
+  iDEC1 = (catstats[0].DEC[1] + 90.0) * 360000.0;
+  
+  spd_start = (int)(    (catstats[0].DEC[0] + 90) / 7.5) * 75.0;
+  DEC1 = (catstats[0].DEC[1] + 90) / 7.5;
+  if (DEC1 > (int)(DEC1)) {
+    spd_end =   (int)(1 + (catstats[0].DEC[1] + 90) / 7.5) * 75.0;
+  } else {
+    spd_end =   (int)(0 + (catstats[0].DEC[1] + 90) / 7.5) * 75.0;
+  }
+
+  NUSNO = 5000;
+  ALLOCATE (usno, USNOdata, NUSNO);
+  nusno = 0;
+
+  for (spd = spd_start; spd < spd_end; spd += 75) {
+    disk = -1;
+    for (i = 0; i < NZONE; i++) {
+      if (spd == SPDzone[i]) 
+	disk = USNOdisk[i];
+    }
+    if (disk < 0) {
+      fprintf (stderr, "ERROR: can't find cdrom for spd %d\n",  spd);
+      exit (0);
+    }
+    
+    /* load accelerator file */
+    sprintf (filename, "%s/zone%04d.acc\0", CDROM, spd); 
+    fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "can't open file %s, is cdrom %d in drive?\n", filename, disk);
+      fprintf (stderr, "press return when ready to continue: ");
+      fscanf (stdin, "%c", &c);
+      fprintf (stderr, "trying again...\n");
+      f = fopen (filename, "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "still can't open file %s, is cdrom %d in drive?\n", filename, disk);
+	exit (0);  
+      }
+    }
+    for (i = 0; fscanf (f, "%f %d %d", &hours[i], &start[i], &number[i]) != EOF; i++);
+    Nbins = i;
+    fclose (f);
+    
+    first = catstats[0].RA[0] / 3.75;
+    if ((catstats[0].RA[1] / 3.75) == (int) (catstats[0].RA[1] / 3.75)) 
+      last  = catstats[0].RA[1] / 3.75;
+    else 
+      last  = 1 + catstats[0].RA[1] / 3.75;
+
+    if ((first > Nbins) || (last > Nbins)) {
+      fprintf (stderr, "RA out of range\n");
+      exit (0);
+    }
+    
+    /* open data file */
+    sprintf (filename, "%s/zone%04d.cat\0", CDROM, spd);
+    fprintf (stderr, "reading from %s\n", filename);
+    f = fopen (filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "can't open file %s\n", filename);
+      exit (0);
+    }
+    /* advance file pointer to first slice */
+    offset = 3*sizeof(int)*(start[first] - 1);
+    fseek (f, offset, SEEK_SET);
+    /* on each loop, load data from an RA slice of the catalog */
+    for (bin = first; bin < last; bin++) {
+      Nitems = 3*number[bin];
+      ALLOCATE (buffer, int, Nitems);
+      nitems = Fread (buffer, sizeof(int), Nitems, f, "int");
+      if (nitems != Nitems) {
+	fprintf (stderr, "error reading data from file %s (%d, %d, %d)\n", 
+		 filename, start[bin], number[bin], nitems);
+	exit (0);
+      }
+      buf = buffer;
+      /* print out data from slice within RA and DEC range */
+      for (i = 0; i < number[bin]; i++, buf+=3) {
+	if ((buf[0] > iRA0) && (buf[0] < iRA1) &&
+	    (buf[1] > iDEC0) && (buf[1] < iDEC1)) {
+	  usno[nusno].R = buf[0]/360000.0;
+	  usno[nusno].D = buf[1]/360000.0 - 90.0;
+	  usno[nusno].r = 0.1*(buf[2] - 1000*((int)(buf[2]/1000)));
+	  usno[nusno].b = 0.1*((int)(buf[2] - 1000000*((int)(buf[2]/1000000))) / 1000);
+	  nusno ++;
+	  if (nusno == NUSNO - 1) {
+	    NUSNO += 5000;
+	    REALLOCATE (usno, USNOdata, NUSNO);
+	  }	  
+	}
+      }
+      free (buffer);
+    }
+    fclose (f);
+  }
+
+  ALLOCATE (usnostats[0].X, float, nusno);
+  ALLOCATE (usnostats[0].Y, float, nusno);
+  ALLOCATE (usnostats[0].N, int, nusno);
+  ALLOCATE (usnostats[0].match, int, nusno);
+
+  X1 = usnostats[0].X;
+  Y1 = usnostats[0].Y;
+  N1 = usnostats[0].N;
+
+  /* project onto rectilinear grid with 1 arcsec pixels, sort by X */
+  /* reference for coords is center of field */
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < nusno; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], usno[i].R, usno[i].D, tcoords);
+    N1[i] = i;
+    usnostats[0].match[i] = -1;
+  }
+  if (nusno > 1) sort_lists (X1, Y1, N1, nusno);
+
+  REALLOCATE (usno, USNOdata, MAX (nusno, 1));
+  *Nusno = nusno;
+  return (usno);
+
+}
+
+
Index: /trunk/Ohana/src/addusno/src/old/add_unfound.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/add_unfound.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/add_unfound.c	(revision 2490)
@@ -0,0 +1,35 @@
+  /* incorporate unmatched image stars -- after all catalogs searched... */
+  for (i = 0; i < Nstars; i++) {
+    if (!found[i]) {
+      catalog[0].average[Nave].R = stars[N1[i]].R;
+      catalog[0].average[Nave].D = stars[N1[i]].D;
+      catalog[0].average[Nave].M = 1000.0*stars[N1[i]].M;
+      catalog[0].average[Nave].Nm = 1;
+      catalog[0].average[Nave].Xp = catalog[0].average[Nave].Xm = 0.0;
+      catalog[0].average[Nave].offset = Nmeas;
+      catalog[0].measure[Nmeas].dR  = 0.0;
+      catalog[0].measure[Nmeas].dD  = 0.0;
+      catalog[0].measure[Nmeas].M   = 1000.0*stars[N1[i]].M;
+      catalog[0].measure[Nmeas].dM  = stars[N1[i]].dM;
+      catalog[0].measure[Nmeas].t  = 3600.0 + stars[N1[i]].Y*0.1;
+      catalog[0].measure[Nmeas].average = (0x00ffffff & Nave);
+      /* time of star = time of image + offset + Y*rate */
+      Nave ++;
+      if (Nave == 0x1000000) {
+	fprintf (stderr, "too many stars in catalog\n");
+	clear_lockfile ();
+	exit (0);
+      }
+      if (Nave == NAVE) {
+	NAVE = Nave + 1000;
+	REALLOCATE (next, int, NAVE);
+	REALLOCATE (catalog[0].average, Average, NAVE);
+      }
+      Nmeas ++;
+      if (Nmeas == NMEAS) {
+	NMEAS = Nmeas + 1000;
+	REALLOCATE (next, int, NMEAS);
+	REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      }
+    }
+  }
Index: /trunk/Ohana/src/addusno/src/old/addstar.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/addstar.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/addstar.c	(revision 2490)
@@ -0,0 +1,77 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, N, Nstars, Nimage, Nregions, Nmissed;
+  Stars *stars, *gstars();
+  Image image, *pimage, *gimages();
+  Catalog catalog;
+  GSCRegion *region, *gregions();
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  NEWPHOTCODE = FALSE;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    NEWPHOTCODE = TRUE;
+    remove_argument (N, &argc, argv);
+    PHOTCODE = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: addstar filename\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile ();
+
+  stars = gstars (argv[1], &Nstars, &image);
+
+  pimage = gimages (&image, &Nimage);
+  region = gregions (&image, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    gcatalog (&region[i], &catalog);
+    find_matches (&region[i], stars, Nstars, &catalog, &image, pimage, Nimage);
+    wcatalog (&region[i], &catalog);
+  }
+  
+  for (Nmissed = i = 0; i < Nstars; i++) {
+    if (stars[i].found == -1) {
+      fprintf (stderr, "%d %f %f %f %f\n", i, stars[i].R, stars[i].D, stars[i].M, stars[i].dM);
+      Nmissed ++;
+    }
+  }
+  if (Nmissed) fprintf (stderr, "WARNING: %d stars in image were missed!\n", Nmissed);
+
+  wimage (argv[1], &image, Nstars);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile ();
+  fprintf (stderr, "SUCCESS\n");
+}
+
+
+  /* stars within a file are not all within 1 region file:
+     1) check if unfound stars are in current region 
+     2) if not, keep unfound for next pass */
+
+
+/* input star lists should be adjusted so 1 e/sec is mag 25.000 */ 
+
+
Index: /trunk/Ohana/src/addusno/src/old/aregion.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/aregion.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/aregion.c	(revision 2490)
@@ -0,0 +1,188 @@
+# include "addstar.h"
+
+double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+			 52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+			 0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+			 -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+		       "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+		       "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+		       "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			"n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			"s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			"s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		"disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		"disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+                   0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+/* find region file which contains ra, dec */
+aregion (region, f, ra, dec) 
+GSCRegion region[];
+FILE *f;
+double ra, dec;
+{
+  
+  
+  char buffer[28800], temp[50], file[50];
+  double dr, dd;
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done, nregion;
+  
+  while (ra < 0) {
+    ra += 360.0;
+  }
+    
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt\0", CATDIR);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] = -180.0;
+    region[0].RA[1] =  540.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+# ifdef DEBUG
+    fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+# ifdef DEBUG
+      fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+# ifdef DEBUG
+    fprintf (stderr, "%f %f %f  %f %f %f  %s\n", DEC0, dec, DEC1, RA0, ra, RA1, temp);
+# endif
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    clear_lockfile ();
+    exit (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt\0", CATDIR, Dec2Sections[NBigDec],&temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
+
+
+/**********/
+int hms_to_deg (h0, h1, d0, d1, string) 
+     char *string;
+     double *h0, *h1, *d0, *d1;
+{
+  
+  int flag_d0, flag_d1, flag_h0, flag_h1;
+  double tmp;
+  
+  *d0 = *h0 = *d1 = *h1 = 0;
+
+  flag_h0 = dparse (h0, 1, string);
+  flag_h1 = dparse (h1, 4, string);
+  flag_d0 = dparse (d0, 7, string);
+  flag_d1 = dparse (d1, 9, string);
+  *h0 *= flag_h0;
+  *h1 *= flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  dparse (&tmp, 2, string);
+  *h0 += tmp/60.0;
+  dparse (&tmp, 3, string);
+  *h0 += tmp/3600.0;
+  
+  dparse (&tmp, 5, string);
+  *h1 += tmp/60.0;
+  dparse (&tmp, 6, string);
+  *h1 += tmp/3600.0;
+  
+  dparse (&tmp, 8, string);
+  *d0 += tmp/60.0;
+
+  dparse (&tmp, 10, string);
+  *d1 += tmp/60.0;
+
+  *h0 *= 15*flag_h0;
+  *h1 *= 15*flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  return (TRUE);
+}
+
+
+/*
+      if (buffer[i*48 + 19] == ' ') continue;
+      strncpy (temp, &buffer[i*48 + 19], 20);       temp[20] = 0;
+      hms_to_deg (&RA,  &DEC, temp, ' ', 3);
+
+
+  dBigRA = 360.0 / (int)(0.5 + 48*cos(3.1415927*0.5*(BigDecBounds[NBigDec] + BigDecBounds[NBigDec + 1])/180.0));
+
+  NBigRA = ra / dBigRA;
+
+  NBig = NBigRA;
+  for (i = 0; (i < 12) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+  for (i = 13; (i < 24) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+
+
+  fprintf (stderr, "%d %d %d %d %f %f -> %f %f %f\n", NBigDec, NBigRA, NBigRASections[NBigDec], NBig, ra, dec, BigDecBounds[NBigDec], BigDecBounds[NBigDec + 1], dBigRA);
+*/
Index: /trunk/Ohana/src/addusno/src/old/gimages.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/gimages.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/gimages.c	(revision 2490)
@@ -0,0 +1,214 @@
+# include "addstar.h"
+double opening_angle ();
+
+Image *gimages (image, Npimage)
+Image image[];
+int *Npimage;
+{
+  
+  int i, j, k, NIMAGE, Nimage, addtolist;
+  int NTIMAGE, Ntimage, ntimage;
+  int NPIMAGE, npimage;
+  FILE *f;
+  Image *timage, *pimage;
+  Coords tcoords;
+  Header header;
+  double r, d;
+  double Xi[5], Yi[5], Xo[5], Yo[5];  /* image and original corners */
+
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (ImageCat, &header)) {
+    if (VERBOSE) fprintf (stderr, "New image catalog %s (1)\n", ImageCat);
+    *Npimage = 0;
+    return ((Image *) NULL);
+  }
+
+  /* project onto rectilinear grid with 1 arcsec pixels */
+  /* we keep the original crpix1,2 and crref1,2 */
+  tcoords = image[0].coords;
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+  tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+  tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+  strcpy (tcoords.ctype, "RA---TAN");
+
+  /* define original corners */
+  Xo[0] = 0;           Yo[0] = 0;
+  Xo[1] = image[0].NX; Yo[1] = 0;
+  Xo[2] = image[0].NX; Yo[2] = image[0].NY;
+  Xo[3] = 0;           Yo[3] = image[0].NY;
+  Xo[4] = 0;           Yo[4] = 0;  /* so we can make a loop easily */
+  for (j = 0; j < 5; j++) {
+    XY_to_RD (&r, &d, Xo[j], Yo[j], &image[0].coords);
+    RD_to_XY (&Xo[j], &Yo[j], r, d, &tcoords);
+  }
+  
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "New image catalog: %s (2)\n", ImageCat);
+    free (header.buffer);
+    *Npimage = 0;
+    return ((Image *) NULL);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+
+  NTIMAGE = 100;
+  ALLOCATE (timage, Image, NTIMAGE);
+
+  npimage = 0;
+  NPIMAGE = 20;
+  ALLOCATE (pimage, Image, NPIMAGE);
+
+  for (Ntimage = 0; Ntimage < Nimage; Ntimage += ntimage) {
+    ntimage = Fread (timage, sizeof(Image), NTIMAGE, f, "image");
+    for (i = 0; i < ntimage; i++) {
+      addtolist = FALSE;
+      /* define image corners */
+      Xi[0] = 0;            Yi[0] = 0;
+      Xi[1] = timage[i].NX; Yi[1] = 0;
+      Xi[2] = timage[i].NX; Yi[2] = timage[i].NY;
+      Xi[3] = 0;            Yi[3] = timage[i].NY;
+      Xi[4] = 0;            Yi[4] = 0;  /* so we can make a loop easily */
+      /* transform to tcoords */
+      for (j = 0; j < 5; j++) {
+	XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	RD_to_XY (&Xi[j], &Yi[j], r, d, &tcoords);
+      }
+      /* check if any edges cross */
+      for (j = 0; j < 4; j++) {
+	for (k = 0; k < 4; k++) {
+	  addtolist |= edge_check (&Xi[j], &Yi[j], &Xo[k], &Yo[k]);
+	}
+      }
+      
+      /*
+      fprintf (stderr, "%f %f %f %d %f %f %d %d %d %f %f %s: %d\n", 0.1*timage[i].detection_limit, 0.1*timage[i].saturation_limit, 0.02*timage[i].cerror, 
+	       timage[i].tzero, 1e-4*timage[i].trate, 
+	       0.001*timage[i].secz, timage[i].nstar, timage[i].NX, timage[i].NY, 0.001*timage[i].Mcal, 0.1*timage[i].Xm, timage[i].name, addtolist);
+      
+      fprintf (stderr, "%s\n", timage[i].coords.ctype);
+      fprintf (stderr, "%f %f\n", timage[i].coords.crval1, timage[i].coords.crval2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.crpix1, timage[i].coords.crpix2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.pc1_1, timage[i].coords.pc1_2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.pc2_1, timage[i].coords.pc2_2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.cdelt1, timage[i].coords.cdelt2);      
+      */
+
+      if (addtolist) {
+	pimage[npimage] = timage[i];
+	npimage ++;
+	if (npimage == NPIMAGE) {
+	  NPIMAGE += 20;
+	  REALLOCATE (pimage, Image, NPIMAGE);
+	}
+      }
+    }
+
+    if (ntimage == 0) {
+      fprintf (stderr, "ERROR: expected %d images, only found %d\n", Nimage, Ntimage);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+
+  if (VERBOSE) fprintf (stderr, "found %d overlapping images\n", npimage);
+
+  fclose (f);
+  *Npimage = npimage;
+  return (pimage);
+
+}
+  
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+double opening_angle (x1, y1, x2, y2, x3, y3)
+double x1, y1, x2, y2, x3, y3;
+{
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
+
+
+
+
+/* probably not needed now 
+char *_parse_nextword();
+
+
+int fparse (X, NX, line)
+float *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
+
+*/
Index: /trunk/Ohana/src/addusno/src/old/gregions.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/gregions.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/gregions.c	(revision 2490)
@@ -0,0 +1,57 @@
+# include "addstar.h"
+
+GSCRegion *gregions (image, Nregions)
+Image *image;
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dr, dd, dec, ra;
+  int i, j, done, nregion, NREGION;
+  
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", GSCFILE);
+    clear_lockfile ();
+    exit (0);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "found %d region files:\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "  %d %s\n", i, region[i].filename);
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /trunk/Ohana/src/addusno/src/old/gstars.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/gstars.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/gstars.c	(revision 2490)
@@ -0,0 +1,189 @@
+# include "addstar.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 31
+# define BLOCK 1000
+#include <sys/time.h>
+#include <time.h>
+
+Stars *gstars (file, NSTARS, image) 
+char file[];
+int *NSTARS;
+Image *image;
+{
+
+  FILE *f;
+  Header header;
+  int i, j, nstar;
+  int nbytes, Nbytes;
+  Stars *stars;
+  char *buffer, line[64], *c;
+  struct tm timeptr;
+  double tmp;
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't find image file %s\n", file);
+    clear_lockfile ();
+    exit(0);
+  }
+
+  /* open file */
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find data file %s\n", file);
+    clear_lockfile ();
+    exit(0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  c = strrchr (file, 0x2f);
+  if (c == (char *) NULL) {
+    strcpy (image[0].name, file);
+  } else { 
+    strcpy (image[0].name, (c+1));
+  }
+  /* get astrometry information */
+  strcpy (image[0].coords.ctype, "NONE");
+  fits_scan (&header, "CTYPE1",   "%s",  1, image[0].coords.ctype);
+  if (strcmp (image[0].coords.ctype, "RA---PLY")) {
+    fprintf (stderr, "ERROR: wrong astrometric info in header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  fits_scan (&header, "CDELT1",   "%f", 1, &image[0].coords.cdelt1); 
+  fits_scan (&header, "CDELT2",   "%f", 1, &image[0].coords.cdelt2);
+  fits_scan (&header, "CRVAL1",   "%lf", 1, &image[0].coords.crval1);
+  fits_scan (&header, "CRVAL2",   "%lf", 1, &image[0].coords.crval2);  
+  fits_scan (&header, "CRPIX1",   "%f", 1, &image[0].coords.crpix1);
+  fits_scan (&header, "CRPIX2",   "%f", 1, &image[0].coords.crpix2);
+  fits_scan (&header, "PC001001", "%f", 1, &image[0].coords.pc1_1);
+  fits_scan (&header, "PC001002", "%f", 1, &image[0].coords.pc1_2);
+  fits_scan (&header, "PC002001", "%f", 1, &image[0].coords.pc2_1);
+  fits_scan (&header, "PC002002", "%f", 1, &image[0].coords.pc2_2);
+  fits_scan (&header, "CERROR",   "%lf", 1, &tmp);
+  /* RA Terms */
+  fits_scan (&header, "PCA1X2Y0", "%f", 1, &image[0].coords.polyterms[0][0]);
+  fits_scan (&header, "PCA1X1Y1", "%f", 1, &image[0].coords.polyterms[1][0]);
+  fits_scan (&header, "PCA1X0Y2", "%f", 1, &image[0].coords.polyterms[2][0]);
+  fits_scan (&header, "PCA1X3Y0", "%f", 1, &image[0].coords.polyterms[3][0]);
+  fits_scan (&header, "PCA1X2Y1", "%f", 1, &image[0].coords.polyterms[4][0]);
+  fits_scan (&header, "PCA1X1Y2", "%f", 1, &image[0].coords.polyterms[5][0]);
+  fits_scan (&header, "PCA1X0Y3", "%f", 1, &image[0].coords.polyterms[6][0]);
+  /* Dec Terms */
+  fits_scan (&header, "PCA2X2Y0", "%f", 1, &image[0].coords.polyterms[0][1]);
+  fits_scan (&header, "PCA2X1Y1", "%f", 1, &image[0].coords.polyterms[1][1]);
+  fits_scan (&header, "PCA2X0Y2", "%f", 1, &image[0].coords.polyterms[2][1]);
+  fits_scan (&header, "PCA2X3Y0", "%f", 1, &image[0].coords.polyterms[3][1]);
+  fits_scan (&header, "PCA2X2Y1", "%f", 1, &image[0].coords.polyterms[4][1]);
+  fits_scan (&header, "PCA2X1Y2", "%f", 1, &image[0].coords.polyterms[5][1]);
+  fits_scan (&header, "PCA2X0Y3", "%f", 1, &image[0].coords.polyterms[6][1]);
+  image[0].coords.Npolyterms = 2; /* how many do we use? */
+  /* CERROR in data file is in pixels, convert to 20*arcsec */
+  image[0].cerror = tmp * 50.0 * image[0].coords.cdelt1 * 3600.0;
+  while (image[0].coords.crval1 < 0) image[0].coords.crval1 += 360.0;
+  while (image[0].coords.crval1 > 360.0) image[0].coords.crval1 -= 360.0;
+ 
+  fits_scan (&header, "NAXIS1",   "%hd", 1, &image[0].NX); 
+  fits_scan (&header, "NAXIS2",   "%hd", 1, &image[0].NY);
+  fits_scan (&header, "PHOTCODE", "%hd", 1, &image[0].source);
+  if (NEWPHOTCODE) {
+    image[0].source = PHOTCODE;
+  }
+  image[0].NX -= XOVERSCAN;
+  image[0].NY -= YOVERSCAN;
+
+  tmp = 0;
+  fits_scan (&header, "FLIMIT",   "%lf", 1, &tmp);
+  image[0].detection_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FSATUR",   "%lf", 1, &tmp);
+  image[0].saturation_limit = tmp * 10.0;
+
+  if (!fits_scan (&header, "TZERO",   "%d",  1, &image[0].tzero)) {
+    fits_scan (&header, "UT",   "%s",  1, line);
+    /* remove : characters */
+    for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (c, 0x3a))
+      *c = ' ';
+    sscanf (line, "%d %d %d", &timeptr.tm_hour, &timeptr.tm_min, &timeptr.tm_sec);
+    fits_scan (&header, "DATE-UT",   "%s",  1, line);
+    for (c = strchr (line, 0x2f); c != (char *) NULL; c = strchr (c, 0x2f))
+      *c = ' ';
+    sscanf (line, "%d %d %d", &timeptr.tm_year, &timeptr.tm_mon, &timeptr.tm_mday);
+    if (timeptr.tm_year < 90) { /* correct for year 2000 turnover */
+      timeptr.tm_year += 100;
+    }
+    image[0].tzero = mktime (&timeptr);
+  }
+
+  tmp = 0;
+  fits_scan (&header, "TRATE",   "%lf", 1, &tmp);
+  image[0].trate = 10000 * tmp;
+
+  tmp = 0;
+  fits_scan (&header, "AIRMASS", "%lf", 1, &tmp);
+  image[0].secz = 1000*tmp;
+
+  /* secz is in units milli-airmass */
+  image[0].Mcal =  ALPHA*(image[0].secz - 1000);
+  image[0].Xm   = 30.0;
+  image[0].code = 0;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+
+  /* find number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar);
+  if (image[0].nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  ALLOCATE (stars, Stars, image[0].nstar);
+  Nbytes = image[0].nstar*BYTES_STAR;
+
+  /* load in stars by blocks of 1000 */
+  nstar = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR));
+  for (i = 0; i < (int)(Nbytes / (BLOCK*BYTES_STAR)); i++) {
+    nbytes = Fread (buffer, 1, (BLOCK*BYTES_STAR), f, "char");
+    if (nbytes != BLOCK*BYTES_STAR) {
+      fprintf (stderr, "ERROR: failed to read in stars (1)\n");
+      clear_lockfile ();
+      exit (0);
+    }
+    for (j = 0; j < BLOCK; j++, nstar++) {
+      dparse (&stars[nstar].X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].M,  3, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].dM, 4, &buffer[j*BYTES_STAR]);
+      XY_to_RD (&stars[nstar].R, &stars[nstar].D, stars[nstar].X, stars[nstar].Y, &image[0].coords);
+      stars[nstar].found = -1;
+    }
+  }
+  /* left over fraction of a block */
+  nbytes = Fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f, "char");
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstar++) {
+    dparse (&stars[nstar].X, 1, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].Y, 2, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].M, 3, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].dM, 4, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&stars[nstar].R, &stars[nstar].D, stars[nstar].X, stars[nstar].Y, &image[0].coords);
+    stars[nstar].found = -1;
+  }
+
+  if (image[0].nstar != nstar) {
+    fprintf (stderr, "ERROR: failed to read in all stars (%d != %d)\n", image[0].nstar, nstar);
+    clear_lockfile ();
+    exit (0);
+  }
+  free (header.buffer);
+  free (buffer);
+ 
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+  *NSTARS = image[0].nstar;
+
+  return (stars);
+}
Index: /trunk/Ohana/src/addusno/src/old/sort_stars.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/sort_stars.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/sort_stars.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "relphot.h"
+
+void sort_stars (radec, stars, Nstars)
+int  **radec;
+Star  *stars;
+int    Nstars;
+{
+  
+  int i;
+  double *RAs;
+
+  ALLOCATE (radec[0], int, Nstars);
+  ALLOCATE (RAs, double, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    radec[0][i] = i;
+    RAs[i] = stars[i].RA;
+  }
+
+  sort_seq (radec[0], RAs, Nstars);
+  free (RAs);
+
+}
+
+
+void sort_seq (seq, value, N) 
+int *seq;
+double *value;
+int N;
+{
+  int l,j,ir,i;
+  int temp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = seq[--l];
+    }
+    else {
+      temp = seq[ir];
+      seq[ir] = seq[0];
+      if (--ir == 0) {
+	seq[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[seq[j]] < value[seq[j+1]]) ++j;
+      if (value[temp] < value[seq[j]]) {
+	seq[i]=seq[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
+
+
Index: /trunk/Ohana/src/addusno/src/old/string.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/string.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/string.c	(revision 2490)
@@ -0,0 +1,64 @@
+# include <stdio.h>
+# include <math.h>
+# define TRUE  1
+# define FALSE 0
+
+int scan_line (f, line) 
+FILE *f;
+char line[];
+{
+
+  int i, status;
+  char c;
+  
+  status = EOF + 1;
+  
+  for (i = 0, c = 0; (c != '\n') && (status != EOF); i++) {
+    status = fscanf (f, "%c", &c);
+    line[i] = c;
+  }
+  line[i - 1] = 0;  /* this could make things crash! */
+
+  if (i > 1) {
+    status = EOF + 1;
+  }
+
+  return (status);
+
+}
+
+char *_parse_nextword(string)
+char *string;
+{
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (; isspace (*string); string++);
+  for (; (*string != 0) && !isspace (*string); string++);
+  for (; isspace (*string); string++);
+  return (string);
+}
+
+int dparse (X, NX, line)
+double *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
Index: /trunk/Ohana/src/addusno/src/old/wimage.c
===================================================================
--- /trunk/Ohana/src/addusno/src/old/wimage.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/old/wimage.c	(revision 2490)
@@ -0,0 +1,67 @@
+# include "addstar.h"
+
+wimage (filename, image, Nstars)
+char *filename;
+Image image[];
+int Nstars;
+{
+  
+  int Nimages, status;
+  FILE *f;
+  Header header;
+
+  if (!fits_read_header (ImageCat, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't find %s, creating a new one\n", ImageCat);
+    if (!fits_read_header (ImageTemplate, &header)) {
+      fprintf (stderr, "ERROR: can't find template header %s\n", ImageTemplate);
+      clear_lockfile ();
+      exit (0);
+    }
+    f = fopen (ImageCat, "w");
+    if (f == NULL) {
+      fprintf (stderr, "ERROR: can't create/open image catalog file: %s\n", ImageCat);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+  
+  Nimages = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimages);
+  Nimages ++;
+  fits_modify (&header, "NIMAGES", "%d", 1, Nimages);
+
+  f = fopen (ImageCat, "r+");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't create/open image catalog file: %s\n", ImageCat);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  /* position to begining of file to write header */
+  fseek (f, 0, SEEK_SET);
+  status = Fwrite (header.buffer, 1, header.size, f, "char");
+  if (status != header.size) {
+    fprintf (stderr, "ERRPR: failed writing data to image header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  fseek (f, 0, SEEK_END);
+  fprintf (stderr, "Image: %d\n", sizeof(Image));
+  status = Fwrite (image, sizeof(Image), 1, f, "image");
+  if (status != 1) {
+    fprintf (stderr, "ERRPR: failed writing data to image catalog\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  fclose (f);
+  
+
+}
+
+/* the image we add in this routine is always a new image.  
+   We only need to do two things:
+     1) append the data for the image to the end of the file
+     2) update the NIMAGES field in the header (which means, read in header, re-write)
+ */
Index: /trunk/Ohana/src/addusno/src/reset_catalog.c
===================================================================
--- /trunk/Ohana/src/addusno/src/reset_catalog.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/reset_catalog.c	(revision 2490)
@@ -0,0 +1,86 @@
+# include "addusno.h"
+
+reset_catalog (catalog)
+Catalog catalog[];
+{
+
+  int i, j, k, n, m, N, M, found;
+  int *next, last, this;
+  int Nave, Nmeas, Ndel;
+  unsigned int flags;
+  Measure *tmpmeasure;
+  unsigned short NotUSNO, NotProper;
+
+  Nave = catalog[0].Naverage;
+ 
+  /* set up link listed pointers for new measurements */
+  Nmeas = catalog[0].Nmeasure;
+  ALLOCATE (next, int, Nmeas);
+  /* set up pointers for linked list of measurements */
+  for (i = 0; i < Nmeas - 1; i++) {
+    next[i] = i+1;
+  }
+  next[i] = -1;
+  last = i;
+ 
+  /** find matched stars **/
+  NotUSNO = 0xffff ^ ID_USNO;
+  NotProper = 0xffff ^ ID_PROPER;
+  for (i = 0; i < Nave; i++) {
+    found = FALSE;
+    if (catalog[0].average[i].code & ID_USNO) {
+      catalog[0].average[i].code &= NotUSNO;
+      found = TRUE;
+    }
+    if (catalog[0].average[i].code & ID_PROPER) {
+      catalog[0].average[i].code &= NotProper;
+      found = TRUE;
+    }
+    if (found) {
+      M = catalog[0].average[i].offset;
+      Ndel = 0;
+      for (k = 0; k < catalog[0].average[i].Nm; k++) {
+	if (catalog[0].measure[M+k].t == 0) {
+	  if (M+k > 0) {
+	    this = next[M+k];
+	    if (next[M+k] == -1) {
+	      next[M+k-1] = -1;
+	    } else {
+	      for (j = M+k+1; (j < Nmeas) && (next[j] == -2); j++);
+	      if (j == Nmeas) {
+		next[M+k-1] = -1;
+		fprintf (stderr, "warning, why didn't I find last link to start with?\n");
+	      }
+	      else {
+		next[M+k-1] = this;
+	      }
+	    }
+	  }
+	  next[M+k] = -2; /* delete link */
+	  Ndel ++;
+	}
+      }
+      catalog[0].average[i].Nm -= Ndel;
+      Nmeas -= Ndel;
+    }
+  }
+  
+  /* fix order of Measure (memory intensive, but fast) */
+  N = 0; 
+  ALLOCATE (tmpmeasure, Measure, Nmeas);
+  for (i = 0; i < Nave; i++) {
+    n = catalog[0].average[i].offset;
+    catalog[0].average[i].offset = N;
+    for (k = 0; k < catalog[0].average[i].Nm; k++, N++) {
+      tmpmeasure[N] = catalog[0].measure[n]; 
+      n = next[n];
+    }
+  }
+  free (catalog[0].measure);
+  catalog[0].measure = tmpmeasure;
+    
+  if (VERBOSE) fprintf (stderr, "deleted %d reference %d -> %d)\n", 
+			catalog[0].Nmeasure - Nmeas, catalog[0].Nmeasure, Nmeas);
+  catalog[0].Nmeasure = Nmeas;
+}
+
Index: /trunk/Ohana/src/addusno/src/sort_lists.c
===================================================================
--- /trunk/Ohana/src/addusno/src/sort_lists.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/sort_lists.c	(revision 2490)
@@ -0,0 +1,48 @@
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
Index: /trunk/Ohana/src/addusno/src/wcatalog.c
===================================================================
--- /trunk/Ohana/src/addusno/src/wcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/addusno/src/wcatalog.c	(revision 2490)
@@ -0,0 +1,74 @@
+# include "addstar.h"
+
+wcatalog (catname, catalog)
+char *catname;
+Catalog catalog[];
+{
+  
+  char filename[256], line[256];
+  int i, Nitems, nitems, status, mode;
+  FILE *f;
+  struct stat filestat;
+
+  sprintf (filename, "%s/%s\0", CATDIR, catname);
+
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, make backup copy */
+    sprintf (line, "mv %s %s~\0", filename, filename);
+    status = system (line);
+    if (status) {
+      fprintf (stderr, "ERROR: unable to create %s~, exiting\n", filename);
+      exit (0);
+    }
+  }
+
+  if (catalog[0].Naverage == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars in catalog, skipping\n");
+    return (FALSE);
+  }
+  
+  f = fopen (filename, "w");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't create new catalog file: %s\n", filename);
+    exit (0);
+  }
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  chmod (filename, mode);
+  
+  fits_modify (&catalog[0].header, "NSTARS", "%d", 1, catalog[0].Naverage);
+  fits_modify (&catalog[0].header, "NMEAS", "%d", 1, catalog[0].Nmeasure);
+  fits_modify (&catalog[0].header, "NMISS", "%d", 1, catalog[0].Nmissing);
+
+  fits_modify (&catalog[0].header, "ADDUSNO", "%t", 1, TRUE);
+
+  nitems = Fwrite (catalog[0].header.buffer, 1, catalog[0].header.size, f, "char");
+  if (nitems != catalog[0].header.size) {
+    fprintf (stderr, "ERROR: failed to write header\n");
+    exit (0);
+  }
+
+  Nitems = catalog[0].Naverage;
+  nitems = Fwrite (catalog[0].average, sizeof(Average), Nitems, f, "average");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to write catalog file aves %s\n", filename);
+    exit (0);
+  }
+  
+  Nitems = catalog[0].Nmeasure;
+  nitems = Fwrite (catalog[0].measure, sizeof(Measure), Nitems, f, "measure");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to write catalog file meas %s\n", filename);
+    exit (0);
+  }
+
+  Nitems = catalog[0].Nmissing;
+  nitems = Fwrite (catalog[0].missing, sizeof(Missing), Nitems, f, "missing");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to write catalog file miss %s\n", filename);
+    exit (0);
+  }
+
+  fclose (f);
+
+}
+
Index: /trunk/Ohana/src/fixcat/Makefile
===================================================================
--- /trunk/Ohana/src/fixcat/Makefile	(revision 2490)
+++ /trunk/Ohana/src/fixcat/Makefile	(revision 2490)
@@ -0,0 +1,61 @@
+include ../../Configure
+CC      =       gcc -g  # override this for now for minimal test
+HOME 	=	$(ROOT)/src/fixcat
+CONFIG  =	$(ROOT)/config
+PROGRAM =       fixcat
+
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC) -I$(LINC)/$(ARCH)
+LIBS	= 	-L$(LLIB) -lFITS -lohana -lm 
+CFLAGS	=	-o $*.$(ARCH).o $(INCS)
+CCFLAGS	=	$(INCS) $(LIBS) 
+
+FIXCAT = \
+$(SRC)/fixcat.$(ARCH).o 	$(SRC)/gcatalog.$(ARCH).o   \
+$(SRC)/coordops.$(ARCH).o	$(SRC)/sorts.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o 	$(SRC)/config.$(ARCH).o     \
+$(SRC)/Fread.$(ARCH).o		$(SRC)/check_lockfile.$(ARCH).o \
+$(SRC)/find_images.$(ARCH).o	$(SRC)/match_images.$(ARCH).o	\
+$(SRC)/gregions.$(ARCH).o	$(SRC)/aregion.$(ARCH).o	\
+$(SRC)/find_funnymags.$(ARCH).o	$(SRC)/gcatstats.$(ARCH).o\
+$(SRC)/find_matches.$(ARCH).o	$(SRC)/check_permissions.$(ARCH).o
+
+
+OBJ = $(FIXCAT)
+
+default: $(PROGRAM)
+
+$(MARKSTAR): $(INC)/markstar.h
+
+# dependancy rules for binary code ##########################
+$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+
+$(BIN)/$(PROGRAM).$(ARCH): $(OBJ)
+	$(CC) $(OBJ) -o $(BIN)/$(PROGRAM).$(ARCH) $(CCFLAGS)
+
+install: $(DESTBIN)/$(PROGRAM)
+
+$(DESTBIN)/$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+	rm -f $(DESTBIN)/$(PROGRAM)
+	cp $(BIN)/$(PROGRAM).$(ARCH) $(DESTBIN)/$(PROGRAM)
+
+# utilities #################################################
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+.SUFFIXES: .$(ARCH).o
+
+.c.$(ARCH).o:
+	$(CC) $(CFLAGS) -c $<
Index: /trunk/Ohana/src/fixcat/doc/example.txt
===================================================================
--- /trunk/Ohana/src/fixcat/doc/example.txt	(revision 2490)
+++ /trunk/Ohana/src/fixcat/doc/example.txt	(revision 2490)
@@ -0,0 +1,13 @@
+
+rats: foreach f ( */*.cpt )
+foreach? echo $f
+foreach? echo $f >> bright.log
+foreach? (markstar -v $f >> bright.dat) >>& bright.log
+foreach? end
+
+
+
+ echo $f
+ echo $f >> bright.log
+ (markstar -v $f >> bright.dat) >>& bright.log
+ end
Index: /trunk/Ohana/src/fixcat/include/markstar.h
===================================================================
--- /trunk/Ohana/src/fixcat/include/markstar.h	(revision 2490)
+++ /trunk/Ohana/src/fixcat/include/markstar.h	(revision 2490)
@@ -0,0 +1,42 @@
+# include <ohana.h>
+# include <loneos.h>
+
+int    VERBOSE;
+int    RESET;
+int    FORCE_RUN;
+
+/* global variables set in parameter file */
+char   CATDIR[256];
+char   GSCDIR[256];
+char   ImageCat[256];
+char   GSCFILE[256];
+
+double RADIUS;
+double TRAIL_WIDTH;
+int    NBINS;
+int    NPTSINLINE;
+double MIN_DENSITY;
+double NSIGMA;
+
+double BRIGHT_HALO_MAG;
+double BRIGHT_HALO_SLOPE;
+double BRIGHT_XTRAIL_WIDTH;
+double BRIGHT_XTRAIL_MAG;
+double BRIGHT_XTRAIL_SLOPE;
+double BRIGHT_YTRAIL_WIDTH;
+double BRIGHT_YTRAIL_MAG;
+double BRIGHT_YTRAIL_SLOPE;
+
+double GHOST_MAG;
+double GHOST_RADIUS;
+double OPTICAL_AXIS1;
+double OPTICAL_AXIS2;
+
+typedef struct {
+  Coords coords;
+  float *X, *Y;
+  int *N;
+  double RA[2], DEC[2];
+  double Area, density, spacing;
+} CatStats;
+
Index: /trunk/Ohana/src/fixcat/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/ConfigInit.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/ConfigInit.c	(revision 2490)
@@ -0,0 +1,45 @@
+# include "markstar.h"
+
+ConfigInit (int argc, char **argv) {
+
+  char *config, *file;
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (&argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (0);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+  /* used in other pipeline functions */
+  ScanConfig (config, "IMAGE_CATALOG",   "%s",  0, ImageCat);
+  ScanConfig (config, "CATDIR",          "%s",  0, CATDIR);
+  ScanConfig (config, "GSCDIR",          "%s",  0, GSCDIR);
+  ScanConfig (config, "GSCFILE",         "%s",  0, GSCFILE);
+  /* unique to markstar */
+  ScanConfig (config, "SEARCH_RADIUS",   "%lf", 0, &RADIUS);
+  ScanConfig (config, "TRAIL_WIDTH",     "%lf", 0, &TRAIL_WIDTH);
+  ScanConfig (config, "NANGLE_BINS",     "%d",  0, &NBINS);
+  ScanConfig (config, "NPTSINLINE",      "%d",  0, &NPTSINLINE);
+  ScanConfig (config, "MIN_DENSITY",     "%lf", 0, &MIN_DENSITY);
+  ScanConfig (config, "SPACE_SIGMA",     "%lf", 0, &NSIGMA); 
+
+  ScanConfig (config, "BRIGHT_HALO_MAG",     "%lf", 0, &BRIGHT_HALO_MAG);
+  ScanConfig (config, "BRIGHT_HALO_SLOPE",   "%lf", 0, &BRIGHT_HALO_SLOPE);
+  ScanConfig (config, "BRIGHT_XTRAIL_WIDTH", "%lf", 0, &BRIGHT_XTRAIL_WIDTH);
+  ScanConfig (config, "BRIGHT_XTRAIL_MAG",   "%lf", 0, &BRIGHT_XTRAIL_MAG);
+  ScanConfig (config, "BRIGHT_XTRAIL_SLOPE", "%lf", 0, &BRIGHT_XTRAIL_SLOPE);
+  ScanConfig (config, "BRIGHT_YTRAIL_WIDTH", "%lf", 0, &BRIGHT_YTRAIL_WIDTH);
+  ScanConfig (config, "BRIGHT_YTRAIL_MAG",   "%lf", 0, &BRIGHT_YTRAIL_MAG);
+  ScanConfig (config, "BRIGHT_YTRAIL_SLOPE", "%lf", 0, &BRIGHT_YTRAIL_SLOPE);
+
+  ScanConfig (config, "GHOST_MAG",       "%lf", 0, &GHOST_MAG);
+  ScanConfig (config, "GHOST_RADIUS",    "%lf", 0, &GHOST_RADIUS);
+  ScanConfig (config, "OPTICAL_AXIS1",   "%lf", 0, &OPTICAL_AXIS1);
+  ScanConfig (config, "OPTICAL_AXIS2",   "%lf", 0, &OPTICAL_AXIS2);
+ 
+  free (config);
+}
Index: /trunk/Ohana/src/fixcat/src/aregion.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/aregion.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/aregion.c	(revision 2490)
@@ -0,0 +1,186 @@
+# include "markstar.h"
+
+double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+			 52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+			 0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+			 -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+		       "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+		       "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+		       "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			"n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			"s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			"s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		"disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		"disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+                   0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+/* find region file which contains ra, dec */
+aregion (region, f, ra, dec) 
+GSCRegion region[];
+FILE *f;
+double ra, dec;
+{
+  
+  
+  char buffer[28800], temp[50], file[50];
+  double dr, dd;
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done, nregion;
+  
+  while (ra < 0) { ra += 360.0; }
+  while (ra >= 360.0) { ra -= 360.0; }
+    
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt\0", GSCDIR);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] = -180.0;
+    region[0].RA[1] =  540.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+# ifdef DEBUG
+    fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+# ifdef DEBUG
+      fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+# ifdef DEBUG
+    fprintf (stderr, "%f %f %f  %f %f %f  %s\n", DEC0, dec, DEC1, RA0, ra, RA1, temp);
+# endif
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    exit (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt\0", GSCDIR, Dec2Sections[NBigDec],&temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
+
+
+/**********/
+int hms_to_deg (h0, h1, d0, d1, string) 
+     char *string;
+     double *h0, *h1, *d0, *d1;
+{
+  
+  int flag_d0, flag_d1, flag_h0, flag_h1;
+  double tmp;
+  
+  *d0 = *h0 = *d1 = *h1 = 0;
+
+  flag_h0 = dparse (h0, 1, string);
+  flag_h1 = dparse (h1, 4, string);
+  flag_d0 = dparse (d0, 7, string);
+  flag_d1 = dparse (d1, 9, string);
+  *h0 *= flag_h0;
+  *h1 *= flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  dparse (&tmp, 2, string);
+  *h0 += tmp/60.0;
+  dparse (&tmp, 3, string);
+  *h0 += tmp/3600.0;
+  
+  dparse (&tmp, 5, string);
+  *h1 += tmp/60.0;
+  dparse (&tmp, 6, string);
+  *h1 += tmp/3600.0;
+  
+  dparse (&tmp, 8, string);
+  *d0 += tmp/60.0;
+
+  dparse (&tmp, 10, string);
+  *d1 += tmp/60.0;
+
+  *h0 *= 15*flag_h0;
+  *h1 *= 15*flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  return (TRUE);
+}
+
+
+/*
+      if (buffer[i*48 + 19] == ' ') continue;
+      strncpy (temp, &buffer[i*48 + 19], 20);       temp[20] = 0;
+      hms_to_deg (&RA,  &DEC, temp, ' ', 3);
+
+
+  dBigRA = 360.0 / (int)(0.5 + 48*cos(3.1415927*0.5*(BigDecBounds[NBigDec] + BigDecBounds[NBigDec + 1])/180.0));
+
+  NBigRA = ra / dBigRA;
+
+  NBig = NBigRA;
+  for (i = 0; (i < 12) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+  for (i = 13; (i < 24) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+
+
+  fprintf (stderr, "%d %d %d %d %f %f -> %f %f %f\n", NBigDec, NBigRA, NBigRASections[NBigDec], NBig, ra, dec, BigDecBounds[NBigDec], BigDecBounds[NBigDec + 1], dBigRA);
+*/
Index: /trunk/Ohana/src/fixcat/src/check_lockfile.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/check_lockfile.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/check_lockfile.c	(revision 2490)
@@ -0,0 +1,39 @@
+# include "markstar.h"
+
+check_lockfile ()
+{
+  
+  FILE *f;
+  char filename[128];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    fprintf (stderr, "ERROR: catalog %s is locked, try again later\n", CATDIR);
+    exit (0);
+  }
+
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock file %s\n", filename);
+    exit (0);
+  }
+  fclose (f);
+
+}
+
+clear_lockfile ()
+{
+  
+  char filename[128], line[256];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    sprintf (line, "rm %s\0", filename);
+    system (line);
+  } else {
+    fprintf (stderr, "can't remove lockfile, why not?\n");
+  }
+
+}
Index: /trunk/Ohana/src/fixcat/src/check_permissions.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/check_permissions.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/check_permissions.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "markstar.h"
+
+check_permissions (char *basefile) {
+  
+  FILE *f;
+  char *c, dir[256], filename[256];
+  struct stat filestat;
+  uid_t fuid, uid;
+  gid_t fgid, gid;
+  int status;
+
+  uid = getuid();
+  gid = getgid();
+
+  /* check permission to write to directory */
+  sprintf (filename, "%s\0", basefile);
+  c = strrchr (filename, '/');
+  if (c == (char *) NULL) {
+    strcpy (dir, ".");
+  } else {
+    *c = 0;
+    strcpy (dir, filename);
+  }
+  status = stat (dir, &filestat);
+  if (status == -1) {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  } 
+  if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRWXU)) ||
+      ((gid == filestat.st_gid) && (filestat.st_mode & S_IRWXG)) || 
+      (filestat.st_mode & S_IRWXO)) {
+  } else {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  }
+  
+  /* check permission to write to file */
+  sprintf (filename, "%s\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+  /* check permission to write to backup file */
+  sprintf (filename, "%s~\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+}
Index: /trunk/Ohana/src/fixcat/src/config.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/config.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/config.c	(revision 2490)
@@ -0,0 +1,110 @@
+# include <ohana.h>
+# define D_NBYTES 4096
+
+char *LoadConfigFile (filename) 
+char *filename; 
+{
+  
+  FILE *f;
+  int i, done, Nbytes, NBYTES, size;
+  char *config;
+  
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "couldn't find %s\n", filename);
+    return ((char *) NULL);
+  }
+ 
+  NBYTES = D_NBYTES;
+  ALLOCATE (config, char, NBYTES);
+ 
+  size = 0;
+  done = FALSE;
+  for (i = 0; !done; i++) {
+    Nbytes = Fread (&config[i*D_NBYTES], sizeof(char), D_NBYTES, f, "char");
+    size += Nbytes;
+    if (Nbytes < D_NBYTES) 
+      done = TRUE;
+    else {
+      NBYTES += D_NBYTES;
+      REALLOCATE (config, char, NBYTES);
+    }
+  }
+  
+  config[size] = '\n';
+  config[size+1] = 0;
+  REALLOCATE (config, char, size + 2);
+ 
+  fclose (f);
+
+  return (config);
+}
+
+int ScanConfig /* we expect one more field: the pointer to the value requested */
+# ifndef ANSI
+(config, field, mode, va_alist) 
+ char *config; char *field, *mode; va_dcl
+# else
+(char       config[],
+ char       field[],
+ char       mode[],...)
+# endif
+{
+ 
+  int i, j;
+  char *p, *p2, tmp[256];
+  va_list argp;
+  double value;
+  
+# ifndef ANSI
+  va_start (argp);
+# else
+  va_start (argp, N);
+# endif
+  
+  /* find the correct line with field */
+  p2 = config;
+  for (i = 0; ; i++) {
+    if (!strncmp (field, p2, strlen(field))) {
+      p = p2 + strlen (field);
+      break;
+    }
+    else {
+      p2 = strchr (p2, '\n');
+      if (p2 == (char *) NULL) {
+	fprintf (stderr, "entry %s not found in config file\n", field);
+	return (FALSE);
+      }
+      else p2++;
+    }
+  }
+  if (!strcmp (mode, "%s")) {
+    p2 = strchr (p, '\n');
+    if (p2 == (char *) NULL)
+      p2 = config + strlen(config);
+    bcopy (p, tmp, (p2-p));
+    tmp[(p2-p)] = 0;
+    stripwhite (tmp);
+    p2 = va_arg (argp, char *);
+    strcpy (p2, tmp);
+  }
+  else {
+ 
+    /* try to get a numerical value from the field */
+    value = strtod (p, &p2);
+    if ((*p2 == 'd') || (*p2 == 'D')) 
+      value *= pow (10.0, atof (p2 + 1));
+    
+    if (!strcmp (mode, "%d"))  *va_arg (argp, int *)       = value;
+    if (!strcmp (mode, "%u"))  *va_arg (argp, unsigned *)  = value;
+    if (!strcmp (mode, "%ld")) *va_arg (argp, long *)      = value;
+    if (!strcmp (mode, "%hd")) *va_arg (argp, short *)     = value;
+    if (!strcmp (mode, "%f"))  *va_arg (argp, float *)     = value;
+    if (!strcmp (mode, "%lf")) *va_arg (argp, double *)    = value;
+    
+  }
+ 
+  va_end (argp);
+  return (TRUE);
+  
+}
Index: /trunk/Ohana/src/fixcat/src/coordops.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/coordops.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/coordops.c	(revision 2490)
@@ -0,0 +1,342 @@
+# include "markstar.h"
+
+XY_to_RD (ra, dec, x, y, coords)
+double *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+# if 1
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+# else
+  {
+# endif
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN")) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+fXY_to_RD (ra, dec, x, y, coords)
+float *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+RD_to_XY (x, y, ra, dec, coords)
+double *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    /* fprintf (stderr, "approximate to polynomial TAN plane fit\n");  */
+  }
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+fRD_to_XY (x, y, ra, dec, coords)
+float *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+
+GetCoords (coords, header) 
+Coords coords[];
+Header header[];
+{
+
+  int status;
+  double rotate;
+
+  rotate = 0.0;
+  coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+  coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+  coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+  coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+  strcpy (coords[0].ctype, "NONE");
+
+  status = TRUE; 
+  if (fits_scan (header, "CTYPE2", "%s", 1, coords[0].ctype)) {
+    status  = fits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+    status &= fits_scan (header, "CRPIX1", "%lf", 1, &coords[0].crpix1);
+    status &= fits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+    status &= fits_scan (header, "CRPIX2", "%lf", 1, &coords[0].crpix2);
+    if (fits_scan (header, "CDELT1", "%lf", 1, &coords[0].cdelt1)) {
+      status &= fits_scan (header, "CDELT2", "%lf", 1, &coords[0].cdelt2);
+      if (fits_scan (header, "CROTA2", "%lf", 1, &rotate)) {
+	coords[0].pc1_1 =  cos(rotate*RAD_DEG);
+	coords[0].pc1_2 = -sin(rotate*RAD_DEG);
+	coords[0].pc2_1 =  sin(rotate*RAD_DEG);
+	coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+      }
+      if (fits_scan (header, "PC001001", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "PC001002", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "PC002001", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "PC002002", "%lf", 1, &coords[0].pc2_2);
+      }
+    }
+    else {
+      if (fits_scan (header, "CD1_1", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "CD1_2", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "CD2_1", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "CD2_2", "%lf", 1, &coords[0].pc2_2);
+	coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      }
+      else {
+	status = FALSE;
+      }
+    }
+  }
+  else {
+    if (fits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1)) {
+      status  = fits_scan (header, "RA_X", "%lf", 1, &coords[0].pc1_1);
+      status &= fits_scan (header, "RA_Y", "%lf", 1, &coords[0].pc1_2);
+      status &= fits_scan (header, "DEC_O", "%lf", 1, &coords[0].crval2);  
+      status &= fits_scan (header, "DEC_X", "%lf", 1, &coords[0].pc2_1);
+      status &= fits_scan (header, "DEC_Y", "%lf", 1, &coords[0].pc2_2);
+      coords[0].crpix1 = coords[0].crpix2 = 0.0;
+      coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      strcpy (coords[0].ctype, "GENE");
+    }
+  }
+  if (!status) {
+    fprintf (stderr, "error getting all elements for coordinate mode %d\n", coords[0].ctype);
+    coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+    coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+    coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+    coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+    strcpy (coords[0].ctype, "NONE");
+  }
+}
+
+
+  /* -PLY projection is an extrapolation of the -TAN projection. 
+     In addition to the usual linear terms of CRPIXi, PC00i00j, there are 
+     higher order polynomial terms (up to 3rd order):
+     Axis 1 terms:
+     PCA1X2Y0 = coords.polyterm[0][0] = x^2                                             
+     PCA1X1Y1 = coords.polyterm[1][0] = xy                                          
+     PCA1X0Y2 = coords.polyterm[2][0] = y^2                                             
+     PCA1X3Y0 = coords.polyterm[3][0] = x^3                                             
+     PCA1X2Y1 = coords.polyterm[4][0] = x^2 y                                             
+     PCA1X1Y2 = coords.polyterm[5][0] = x y^2                                             
+     PCA1X0Y3 = coords.polyterm[6][0] = y^2                                              
+     Axis 2 terms:
+     PCA2X2Y0 = coords.polyterm[0][1] = x^2                                               
+     PCA2X1Y1 = coords.polyterm[1][1] = xy                                                
+     PCA2X0Y2 = coords.polyterm[2][1] = y^2                                               
+     PCA2X3Y0 = coords.polyterm[3][1] = x^3                                               
+     PCA2X2Y1 = coords.polyterm[4][1] = x^2 y                                             
+     PCA2X1Y2 = coords.polyterm[5][1] = x y^2                                             
+     PCA2X0Y3 = coords.polyterm[6][1] = y^2                                               
+  */
Index: /trunk/Ohana/src/fixcat/src/find_bright_stars.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_bright_stars.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_bright_stars.c	(revision 2490)
@@ -0,0 +1,142 @@
+# include "markstar.h"
+
+find_bright_stars (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, n, m, first_j, Nave, Ngsc;
+  Catalog GSCdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2;
+  char *mark;
+  double dX, dY, dR, MaxDist, MaxDist1, MaxRadius, radius, radius2;
+
+  load_gsc_data (&GSCdata, catstats);
+
+  Nave = catalog[0].Naverage;
+  Ngsc = GSCdata.Naverage;
+    
+  /* in the function below, it is better to have the catalog with
+     more stars associated with index 2 (j) */ 
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+  ALLOCATE (X1, float, Ngsc);
+  ALLOCATE (Y1, float, Ngsc);
+  ALLOCATE (N1, int, Ngsc);
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Ngsc; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], GSCdata.average[i].R, GSCdata.average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Ngsc > 1) sort_lists (X1, Y1, N1, Ngsc);
+  
+  /* first find stellar halos */
+  /* max radius (mag = -1) */
+  /** the j index moves quickly and is better associated with the catalog with more stars */
+  MaxRadius = BRIGHT_HALO_SLOPE * (-1.0 - BRIGHT_HALO_MAG); 
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*MaxRadius) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*MaxRadius) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    radius = MAX (BRIGHT_HALO_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_HALO_MAG), 0.0);
+    if (radius == 0) {
+      i++; 
+      continue;
+    }
+    radius2 = radius*radius;
+    for (; (dX > -2*radius) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < radius2) {  /* new measurement of this star */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find y spikes */
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -BRIGHT_YTRAIL_WIDTH) {
+      i++;
+      continue;
+    }
+    if (dX >= BRIGHT_YTRAIL_WIDTH) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist = MAX (BRIGHT_YTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_YTRAIL_MAG), 0.0);
+    for (; (dX > -BRIGHT_YTRAIL_WIDTH) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dX) < BRIGHT_YTRAIL_WIDTH) && (fabs(dY) < MaxDist)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find x spikes */
+  /** find catalog stars near GSC stars **/
+  MaxDist = MAX (BRIGHT_XTRAIL_SLOPE * (-1.0 - BRIGHT_XTRAIL_MAG), 0.0);
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -MaxDist) {
+      i++;
+      continue;
+    }
+    if (dX >= MaxDist) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist1 = MAX (BRIGHT_XTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_XTRAIL_MAG), 0.0);
+    for (; (dX > -MaxDist1) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dY) < BRIGHT_XTRAIL_WIDTH) && (fabs(dX) < MaxDist1)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+
+  /* done with search, mark selected stars */
+  for (i = 0; i < Nave; i++) {
+    if (mark[i]) {
+      catalog[0].average[N2[i]].code = ID_BLEED;
+    }
+  } 
+  
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (mark);
+  free (GSCdata.average);
+
+}
+
Index: /trunk/Ohana/src/fixcat/src/find_funnymags.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_funnymags.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_funnymags.c	(revision 2490)
@@ -0,0 +1,27 @@
+# include "markstar.h"
+
+find_funnymags (catalog, images, Nimage)
+Catalog catalog[];
+Image images[];
+int Nimage;
+{
+
+  int i;
+  int *bad;
+
+  ALLOCATE (bad, int, Nimage);
+  bzero (bad, Nimage*sizeof(int));
+
+  for (i = 0; i < catalog[0].Nmeasure; i++) {
+    if (catalog[0].measure[i].M < 9000) {
+      bad[catalog[0].image[i]] ++;
+    }
+  }
+
+  for (i = 0; i < Nimage; i++) {
+    if (bad[i] > 0) {
+      fprintf (stdout, "%s %d %d\n", images[i].name, images[i].tzero, bad[i]);
+    }
+  }
+
+}
Index: /trunk/Ohana/src/fixcat/src/find_ghosts.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_ghosts.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_ghosts.c	(revision 2490)
@@ -0,0 +1,70 @@
+# include "markstar.h"
+
+find_ghosts (catalog, catstats, filename, image, Nimage)
+Catalog catalog[];
+CatStats catstats[];
+char *filename;
+Image image[];
+int Nimage;
+{
+
+  int i, j, first_j, Nave, Ngsc, Nregions;
+  Catalog GSCdata, Ghostdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2, *match;
+  char *mark;
+  double dX, dY, dR, RADIUS2, BRIGHT_RADIUS, radius, X, Y, R, D;
+  Image timage;
+  GSCRegion *region, *gregions2();
+
+  for (i = 0; i < Nimage; i++) {
+    
+    /* coords structure for ghost image */
+    timage = image[i];
+    timage.coords.cdelt1 = -1*image[i].coords.cdelt1;
+    timage.coords.cdelt2 = -1*image[i].coords.cdelt2;
+    timage.coords.crpix1 = 2*OPTICAL_AXIS1 - image[i].coords.crpix1;
+    timage.coords.crpix2 = 2*OPTICAL_AXIS2 - image[i].coords.crpix2;
+
+    region = gregions2 (&timage, &Nregions);
+    
+    /* find ghost stars */
+    load_gsc_data_ghost (&GSCdata, region, Nregions, &timage);
+
+    /* refect ghost stars to find locations of ghosts */
+    ALLOCATE (Ghostdata.average, Average, MAX (GSCdata.Naverage, 1));
+    for (j = 0; j < GSCdata.Naverage; j++) {
+      RD_to_XY (&X, &Y, GSCdata.average[j].R, GSCdata.average[j].D, &timage);
+      fXY_to_RD (&Ghostdata.average[j].R, &Ghostdata.average[j].D, X, Y, &image[i]);
+      Ghostdata.average[j].M = GSCdata.average[j].M;
+    }    
+    Ghostdata.Naverage = GSCdata.Naverage;
+
+    /* match ghosts and image stars, mark ghosts */
+    find_matches (catalog, catstats, &Ghostdata, i);
+
+    free (Ghostdata.average);
+    free (GSCdata.average);
+  }
+
+}
+
+/* 
+
+   just to be clear on some of the terms:
+
+   the "ghost" is the fuzzy patch of light on an image caused by
+     a reflected star
+
+   the "ghost star" is the star in the sky which causes a ghost
+
+   the "ghost image" is the image location on the sky 
+     where ghost stars may come from.
+
+   the "image stars" are observed stars at the location of the
+     ghost - these are detections of the ghost
+
+
+*/
Index: /trunk/Ohana/src/fixcat/src/find_group.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_group.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_group.c	(revision 2490)
@@ -0,0 +1,69 @@
+# include "markstar.h"
+
+find_group (catstats, mark, Npts, i, ANGLE)
+     CatStats catstats[];
+     double *ANGLE;
+     int i, Npts;
+     char *mark;
+{
+ 
+  float *R, *D;
+  int j, N, bin, Ndegbin;
+  unsigned short int *A;
+  double Ra, De, dR, dD, angle, limit;
+
+   /* assign some parameter values */
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+  limit = 10.0*sqrt((double)(M_PI*RADIUS*RADIUS*catstats[0].density)/(double)(NBINS));
+  Ndegbin = NBINS / 180.0;
+  ALLOCATE (A, unsigned short int, NBINS)
+  bzero (A, NBINS*sizeof(short));
+
+  /* look for points concentrated in an angle bin */
+  if (mark[i]) return (FALSE);
+  Ra = R[i];
+  De = D[i];
+  N = 0;
+  /* points east */
+  for (j = i + 1; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) 
+	continue;
+      if (angle < 0) angle += M_PI;
+      bin = 1 + angle*DEG_RAD*Ndegbin;
+      A[bin] ++;
+      if (A[bin] > limit) {
+	*ANGLE = (bin - 1.0) / (DEG_RAD*Ndegbin);
+	return (TRUE);
+      }
+      N ++;
+    }
+  }
+  /* points west */
+  for (j = i - 1; (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) 
+	continue;
+      if (angle < 0) angle += M_PI;
+      bin = 1 + angle*DEG_RAD*Ndegbin;
+      A[bin] ++;	
+      if (A[bin] > limit) {
+	*ANGLE = (bin - 1.0) / (DEG_RAD*Ndegbin);
+	return (TRUE);
+      }
+      N ++;
+    }
+  }
+  return (FALSE);
+}
+  
Index: /trunk/Ohana/src/fixcat/src/find_images.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_images.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_images.c	(revision 2490)
@@ -0,0 +1,261 @@
+# include "markstar.h"
+# define OLDSTYLE 1
+# if (OLDSTYLE)
+double opening_angle ();
+# endif
+
+Image *find_images (catstats, Nimages)
+CatStats catstats[];
+int *Nimages;
+{
+  
+  Header header;
+  Image *timage, *image;
+  int i, j, k, found, nimage, Nimage, NIMAGE, NTIMAGE, Nloop, Nlast;
+  int n, Nim, status;
+  FILE *f;
+  double Xc[6], Yc[6], Xi[6], Yi[6], r, d, x, y, dx, dy;
+  Coords *tcoords;
+
+  /* we make positional comparisons in the projection of catalog */
+  tcoords = &catstats[0].coords;
+  /* define catalog corners */
+  Xc[0] = catstats[0].RA[0]; Yc[0] = catstats[0].DEC[0];
+  Xc[1] = catstats[0].RA[1]; Yc[1] = catstats[0].DEC[0];
+  Xc[2] = catstats[0].RA[1]; Yc[2] = catstats[0].DEC[1];
+  Xc[3] = catstats[0].RA[0]; Yc[3] = catstats[0].DEC[1];
+  Xc[4] = catstats[0].RA[0]; Yc[4] = catstats[0].DEC[0];
+  Xc[5] = catstats[0].RA[1]; Yc[5] = catstats[0].DEC[1];
+  for (j = 0; j < 6; j++) {
+    r = Xc[j]; d = Yc[j];
+    RD_to_XY (&Xc[j], &Yc[j], r, d, tcoords);
+  }
+  /* find Y positions of RA center */
+  r = 0.5*(catstats[0].RA[0] + catstats[0].RA[1]);
+  d = catstats[0].DEC[0];
+  RD_to_XY (&x, &y, r, d, tcoords);
+  Yc[0] = MIN (y, Yc[0]);
+  Yc[1] = MIN (y, Yc[1]);
+  Yc[4] = MIN (y, Yc[4]);
+  /* find Y positions of RA center */
+  r = 0.5*(catstats[0].RA[0] + catstats[0].RA[1]);
+  d = catstats[0].DEC[1];
+  RD_to_XY (&x, &y, r, d, tcoords);
+  Yc[2] = MAX (y, Yc[2]);
+  Yc[3] = MAX (y, Yc[3]);
+  Yc[5] = MAX (y, Yc[5]);
+
+  dx = 0.02*(Xc[2] - Xc[0]);
+  dy = 0.02*(Yc[2] - Yc[0]);
+  Xc[0] -= dx; Yc[0] -= dy;
+  Xc[1] += dx; Yc[1] -= dy;
+  Xc[2] += dx; Yc[2] += dy;
+  Xc[3] -= dx; Yc[3] += dy;
+  Xc[4] -= dx; Yc[4] -= dy;
+  Xc[5] -= dx; Yc[5] -= dy;
+
+  /* check if image datafile exists, get header, number of images */
+  if (!fits_read_header (ImageCat, &header)) {
+    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
+    exit (0);
+  }
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  if (Nimage == 0) {
+    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
+    exit (0);
+  }
+
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: trouble opening Image catalog: %s (2)\n", ImageCat);
+    exit (0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* set up buffers for images, temporary storage */
+  NTIMAGE = 100;
+  ALLOCATE (timage, Image, NTIMAGE);
+  NIMAGE = 100;
+  ALLOCATE (image, Image, NIMAGE);
+  nimage = 0;
+  Nloop = Nimage / NTIMAGE + 1;
+  Nlast = Nimage % NTIMAGE;
+  
+  /* read in images in groups of NTIMAGE (100) */
+  for (n = 0; n < Nloop; n++) {
+    Nim = (n == Nloop - 1) ? Nlast : NTIMAGE;
+    status = Fread (timage, sizeof(Image), Nim, f, "image");
+    if (status != Nim) {
+      fprintf (stderr, "ERROR: couldn't read images from image catalog: %s\n", ImageCat);
+      exit (0);
+    }
+    /* test each image in block */
+    for (i = 0; i < Nim; i++) {
+      /* define image corners */
+      Xi[0] = 0;            Yi[0] = 0;
+      Xi[1] = timage[i].NX; Yi[1] = 0;
+      Xi[2] = timage[i].NX; Yi[2] = timage[i].NY;
+      Xi[3] = 0;            Yi[3] = timage[i].NY;
+      Xi[4] = 0;            Yi[4] = 0;
+      Xi[5] = timage[i].NX; Yi[5] = timage[i].NY;
+      found = FALSE;
+      /* transform to tcoords */
+      if (catstats[0].DEC[1] > 86.25) { /* pole */
+	for (j = 0; j < 6; j++) {
+	  XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	  if (d > catstats[0].DEC[0] - 0.5) found = TRUE;
+	}
+      } else {
+	for (j = 0; j < 6; j++) {
+	  XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	  RD_to_XY (&Xi[j], &Yi[j], r, d, tcoords);
+	}
+	/* check if edges cross */
+	for (j = 0; (j < 5) && !found; j++) {
+	  for (k = 0; (k < 5) && !found; k++) {
+	    found |= edge_check (&Xi[j], &Yi[j], &Xc[k], &Yc[k]);
+	  }
+	}
+      }
+      if (found) {
+	image[nimage] = timage[i]; 
+	image[nimage].code = 0;
+	nimage ++;
+	if (nimage == NIMAGE) {
+	  NIMAGE += 100;
+	  REALLOCATE (image, Image, NIMAGE);
+	}
+      }
+    }
+  }
+      
+  if (VERBOSE) { 
+    for (i = 0; i < nimage; i++) {
+      XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+      fprintf (stderr, "associated images: %d %8.4f %8.4f %10d %6d  %5.3f %6.3f %6.3f\n", 
+	       i, r, d, image[i].tzero, image[i].nstar, 0.001*image[i].secz, 
+	       0.001*image[i].Mcal, 0.001*image[i].dMcal);
+    }
+  }
+
+  REALLOCATE (image, Image, MAX (nimage, 1));
+  free (timage);
+  *Nimages = nimage;
+  fclose (f);
+  return (image);
+}
+
+# if (OLDSTYLE)
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+double opening_angle (x1, y1, x2, y2, x3, y3)
+double x1, y1, x2, y2, x3, y3;
+{
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
+#else 
+
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double dot;
+  double dx1, dx2, dy1, dy2, dx3, dy3, x, y;
+  double cross, L1, L3, d1, d2;
+
+  dx1 = x1[1] - x1[0]; dy1 = y1[1] - y1[0];
+  dx2 = x2[1] - x2[0]; dy2 = y2[1] - y2[0];
+
+  cross = dx2*dy1 - dx1*dy2;
+  
+  if (cross == 0) {  /* lines are parallel, are they inline? */
+    dx3 = x2[1] - x1[0]; dy2 = y2[1] - y1[0];
+    L1 = hypot (dx1,dy1);
+    L3 = hypot (dx3,dy3);
+
+    dot = fabs (dx1*dx3 + dy1*dy3) / (L1*L3);
+    if (dot == 1.0) { /* lines are inline, do they overlap? */
+      d1 = (x1[1]-x2[1])*(x1[1]-x2[0]) + (y1[1]-y2[1])*(y1[1]-y2[0]);
+      d2 = (x1[0]-x2[1])*(x1[0]-x2[0]) + (y1[0]-y2[1])*(y1[0]-y2[0]);
+      if (d1*d2 < 0) { /* lines overlap */
+	return (TRUE);
+      } else {
+	return (FALSE);
+      }
+    } else {
+      return (FALSE);
+    }
+  }
+
+  x = (dx1*dx2*(y2[0] - y1[0]) + (x1[0]*dy1*dx2 - x2[0]*dy2*dx1)) / cross;
+
+  if (dx1 != 0) {
+    y = y1[0] + (x - x1[0])*dy1/dx1;
+  } else {
+    y = y2[0] + (x - x2[0])*dy2/dx2;
+  }
+
+  d1 = (x - x1[0])*(x - x1[1]) + (y - y1[0])*(y - y1[1]);
+  d2 = (x - x2[0])*(x - x2[1]) + (y - y2[0])*(y - y2[1]);
+  if ((d1 > 0) || (d2 > 0)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+      
+
+#endif
+
Index: /trunk/Ohana/src/fixcat/src/find_line.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_line.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_line.c	(revision 2490)
@@ -0,0 +1,161 @@
+# include "markstar.h"
+
+find_line (catstats, mark, Npts, i, M, B, Angle)
+     CatStats catstats[];
+     double *M, *B, Angle;
+     int i, Npts;
+     char *mark;
+{
+  
+  float *R, *D;
+  int j, N;
+  double X, Y, X2, Y2, XY, m, b, det;
+  double dR, dD, Ra, De, angle;
+  char Flipped;
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+
+  /* fit a line to points near line */
+  Ra = R[i];
+  De = D[i];
+  X = Ra;
+  Y = De;
+  X2 = Ra*Ra;
+  Y2 = De*De;
+  XY = Ra*De;
+  N = 1;
+  /* points to the east */
+  for (j = i + 1; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      if (fabs(angle - Angle) < RAD_DEG) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* points to the west */
+  for (j = i - 1; !mark[i] && (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      if (fabs(angle - Angle) < RAD_DEG) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* determine coeffs */
+  Flipped = 0;
+  det = 1.0 / (X2*N - X*X);
+  m = det * (XY*N - X*Y);
+  b = det * (X2*Y - XY*X);
+  if (fabs(m) > 1.1) { /* use a line of R = m*D + b instead */
+    /* fprintf (stderr, "high slope object: %f %f  -> ", m, b); */
+    det = 1.0 / (Y2*N - Y*Y);
+    m = det * (XY*N - X*Y);
+    b = det * (Y2*X - XY*Y);
+    Flipped = 1;
+    /* fprintf (stderr, "%f %f\n", m, b); */
+  }
+
+  *M = m;
+  *B = b;
+  return (Flipped);
+
+}
+
+
+find_better_line (catstats, mark, Npts, i, M, B, axis)
+     CatStats catstats[];
+     double *M, *B;
+     int i, Npts, axis;
+     char *mark;
+{
+  
+  float *R, *D;
+  int j, N;
+  double X, Y, X2, Y2, XY, m, b, det;
+  double dR, dD, Ra, De, delta;
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+
+  /* fit a line to points near line */
+  Ra = R[i];
+  De = D[i];
+  X = Y = X2 = Y2 = XY = N = 0;
+  m = *M;  b = *B;
+
+  /* points to the east */
+  for (j = i; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      if (axis == 1) 
+	delta = R[j] - m*D[j] - b;
+      else
+	delta = D[j] - m*R[j] - b;
+      if (fabs(delta) < 2*TRAIL_WIDTH) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* points to the west */
+  for (j = i - 1; (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      if (axis == 1) 
+	delta = R[j] - m*D[j] - b;
+      else
+	delta = D[j] - m*R[j] - b;
+      if (fabs(delta) < 2*TRAIL_WIDTH) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* determine coeffs */
+  if (axis == 0) {
+    det = 1.0 / (X2*N - X*X);
+    m = det * (XY*N - X*Y);
+    b = det * (X2*Y - XY*X);
+  } else {
+    det = 1.0 / (Y2*N - Y*Y);
+    m = det * (XY*N - X*Y);
+    b = det * (Y2*X - XY*Y);
+  }
+
+  /* fprintf (stderr, "%f %f %d\n", m, b, N); */
+
+  *M = m;
+  *B = b;
+
+}
Index: /trunk/Ohana/src/fixcat/src/find_matches.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_matches.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_matches.c	(revision 2490)
@@ -0,0 +1,87 @@
+# include "markstar.h"
+
+find_matches (catalog, catstats, Ghostdata, Nimage)
+CatStats catstats[];
+Catalog catalog[], Ghostdata[];
+int Nimage;
+{
+
+  int i, j, k, n, m, N, M, first_j;
+  double X, Y, RADIUS, RADIUS2;
+  float *X1, *Y1, *X2, *Y2;
+  float dX, dY, dR;
+  int *N1, *N2;
+  int Nstar, Nghost, Ng;
+  unsigned int flags;
+  Coords *tcoords;
+
+  Nstar = catalog[0].Naverage;
+  Nghost = Ghostdata[0].Naverage;
+
+  if (Nghost < 1) return (0);
+
+  /* it is better to have the catalog with fewer stars
+     assigned to the X1 set */
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+
+  ALLOCATE (X1, float, Nghost);
+  ALLOCATE (Y1, float, Nghost);
+  ALLOCATE (N1, int, Nghost);
+
+  /* project ghosts to the frame of the catalog */
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Nghost; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], Ghostdata[0].average[i].R, Ghostdata[0].average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Nghost > 1) sort_lists (X1, Y1, N1, Nghost);
+
+  /* choose a radius for matches */
+  RADIUS2 = GHOST_RADIUS*GHOST_RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nghost) && (j < Nstar); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*GHOST_RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*GHOST_RADIUS) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*GHOST_RADIUS) && (j < Nstar); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < RADIUS2) {  
+	/* this object may be a ghost star, 
+	   but only mark those measurements on the correct image */
+	M = N2[j];
+	m = catalog[0].average[M].offset;
+	Ng = 0;
+	for (k = 0; k < catalog[0].average[M].Nm; k++) {
+	  if (catalog[0].image[m+k] == Nimage) {
+	    catalog[0].measure[m+k].average |= GHOST_DATA;
+	    Ng ++;
+	  }
+	}
+	/* all measurements are ghosts */
+	if (catalog[0].average[M].Nm == Ng) {
+	  catalog[0].average[M].code = ID_GHOST;
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+
+  free (X1);
+  free (Y1);
+  free (N1);
+
+}
Index: /trunk/Ohana/src/fixcat/src/find_trails.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/find_trails.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/find_trails.c	(revision 2490)
@@ -0,0 +1,41 @@
+# include "markstar.h"
+
+find_trails (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, N, Nave, axis, marked;
+  double density, spacing, Area, Angle, m, b, RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  char *mark;
+  int *N1;
+  Coords tcoords;
+  
+  Nave = catalog[0].Naverage;
+  N1 = catstats[0].N;
+
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  for (i = 0; i < Nave; i++) {
+    /* already marked, ignore */
+    if ((mark[i]) || 
+	(catalog[0].average[N1[i]].code == ID_BLEED) || 
+	(catalog[0].average[N1[i]].code == ID_GHOST))
+      continue;
+    /* a good star, ignore */
+    if ((catalog[0].average[N1[i]].Nm > 3) && 
+	(catalog[0].average[N1[i]].Nm > 4*catalog[0].average[N1[i]].Nn)) {
+      continue;
+    }
+    if (find_group (catstats, mark, Nave, i, &Angle)) {
+      /* this point has an excess nearby concentration, find the line */
+      axis = find_line (catstats, mark, Nave, i, &m, &b, Angle);
+      find_better_line (catstats, mark, Nave, i, &m, &b, axis);
+      mark_trail (catstats, mark, Nave, i, m, b, axis, catalog);
+    }
+  }
+}
+
Index: /trunk/Ohana/src/fixcat/src/fixcat.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/fixcat.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/fixcat.c	(revision 2490)
@@ -0,0 +1,49 @@
+# include "markstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, Nimages;
+  Image *image, *find_images();
+  Catalog catalog;
+  CatStats catstats;
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: fixcat (catalog)\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile (); 
+
+  gcatalog (argv[1], &catalog);
+
+  gcatstats (&catalog, &catstats);
+
+  image = find_images (&catstats, &Nimages);
+
+  match_images (&catalog, image, Nimages);
+    
+  find_funnymags (&catalog, image, Nimages);  
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+}
+
Index: /trunk/Ohana/src/fixcat/src/gcatalog.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/gcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/gcatalog.c	(revision 2490)
@@ -0,0 +1,108 @@
+# include "markstar.h"
+
+gcatalog (catname, catalog)
+char *catname;
+Catalog catalog[];
+{
+  
+  char filename[128], line[64];
+  int Nitems, nitems;
+  int i, Nmeas, Nmiss, done;
+  FILE *f;
+  struct tm *local;
+  struct timeval now;
+  unsigned int NotTrail;
+  unsigned short NotBad;
+
+  sprintf (filename, "%s/%s\0", CATDIR, catname);
+
+  /* read catalog header */
+  if (!fits_read_header (filename, &catalog[0].header)) {
+    fprintf (stderr, "ERROR: file doesn't exist %s\n", filename);
+    exit (0);
+  }
+
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open catalog file: %s\n", filename);
+    exit (0);
+  }
+  fseek (f, catalog[0].header.size, SEEK_SET); 
+
+  /** find number of stars, measurements **/
+  catalog[0].Nmissing = catalog[0].Naverage = catalog[0].Nmeasure = 0;
+  fits_scan (&catalog[0].header, "NSTARS", "%d", 1, &catalog[0].Naverage);
+  fits_scan (&catalog[0].header, "NMEAS", "%d", 1, &catalog[0].Nmeasure);
+  fits_scan (&catalog[0].header, "NMISS", "%d", 1, &catalog[0].Nmissing);
+
+  ALLOCATE (catalog[0].average, Average, MAX (catalog[0].Naverage, 1));
+  ALLOCATE (catalog[0].measure, Measure, MAX (catalog[0].Nmeasure, 1));
+  ALLOCATE (catalog[0].missing, Missing, MAX (catalog[0].Nmissing, 1));
+  if (catalog[0].Naverage == 0) {
+    /* this is a valid ending state: no stars */
+    if (VERBOSE) fprintf (stderr, "SUCCESS: no stars yet in catalog %s\n", filename);
+    fclose (f);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  /* read average values */
+  Nitems = catalog[0].Naverage;
+  nitems = Fread (catalog[0].average, sizeof(Average), Nitems, f, "average");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (1)\n", filename);
+    fclose (f);
+    exit (0);
+  }
+  
+  /* read measurements */
+  Nitems = catalog[0].Nmeasure;
+  nitems = Fread (catalog[0].measure, sizeof(Measure), Nitems, f, "measure");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (2)\n", filename);
+    fclose (f);
+    exit (0);
+  }
+  
+  /* read missing */
+  Nitems = catalog[0].Nmissing;
+  nitems = Fread (catalog[0].missing, sizeof(Missing), Nitems, f, "missing");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (3)\n", filename);
+    fclose (f);
+    exit (0);
+  }
+  
+  if (VERBOSE) fprintf (stderr, "read %d stars from catalog file %s (%d measurements, %d missing)\n", 
+	   catalog[0].Naverage, filename, catalog[0].Nmeasure, catalog[0].Nmissing);
+
+  for (i = Nmeas = Nmiss = 0; i < catalog[0].Naverage; i++) {
+    Nmeas += catalog[0].average[i].Nm; 
+    Nmiss += catalog[0].average[i].Nn; 
+  }
+  if ((Nmeas != catalog[0].Nmeasure) || (Nmiss != catalog[0].Nmissing)) {
+    fprintf (stderr, "ERROR: data in catalog %s is corrupt, sums don't check\n");
+    fprintf (stderr, "ERROR: Nmeas: %d, %d\n", Nmeas, catalog[0].Nmeasure);
+    fprintf (stderr, "ERROR: Nmiss: %d, %d\n", Nmiss, catalog[0].Nmissing);
+    exit (0);
+  }
+
+  if (RESET) {
+    NotBad = (0xffff ^ 0xc003);
+    for (i = 0; i < catalog[0].Naverage; i++) {
+      if ((catalog[0].average[i].code & ID_MOVING) &&
+	  (catalog[0].average[i].code & ID_BAD_OBJECT) &&
+	  (catalog[0].average[i].code & 0x0003)) {
+	/* this will set the correct bit for each to 0 */ 
+	catalog[0].average[i].code &= NotBad;
+      }
+    }
+    for (i = 0; i < catalog[0].Nmeasure; i++) {
+      catalog[0].measure[i].average &= ~PART_OF_TRAIL;
+    }
+  }
+
+
+  fclose (f);
+
+}
Index: /trunk/Ohana/src/fixcat/src/gcatstats.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/gcatstats.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/gcatstats.c	(revision 2490)
@@ -0,0 +1,66 @@
+# include "markstar.h"
+
+gcatstats (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i;
+  double RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  int *N1;
+  Coords tcoords;
+  
+  fits_scan (&catalog[0].header, "RA0", "%lf", 1, &MinRA);
+  fits_scan (&catalog[0].header, "RA1", "%lf", 1, &MaxRA);
+  fits_scan (&catalog[0].header, "DEC0", "%lf", 1, &MinDEC);
+  fits_scan (&catalog[0].header, "DEC1", "%lf", 1, &MaxDEC);
+
+  /* double check on region RA and DEC ranges */
+  DecCenter = 0.5*(MinDEC + MaxDEC);
+  RaCenter = 0.5*(MinRA + MaxRA);
+  if (MaxDEC > 86.25) {  /* we are on the pole */
+    DecCenter = 90.0;
+    RaCenter = 0.0;
+  }
+
+  catstats[0].RA[0] = MinRA;
+  catstats[0].RA[1] = MaxRA;
+  catstats[0].DEC[0] = MinDEC;
+  catstats[0].DEC[1] = MaxDEC;
+  catstats[0].Area = (MaxDEC - MinDEC)*(MaxRA - MinRA) / cos (RAD_DEG*DecCenter);
+  if (MaxDEC > 86.25) {  /* we are on the pole */
+    catstats[0].Area = 44.2;
+  }
+  catstats[0].density = catalog[0].Naverage / (3600*3600*catstats[0].Area);
+  catstats[0].spacing = 1.0 / (NSIGMA * catstats[0].density * 2*TRAIL_WIDTH);
+  fprintf (stderr, "Area, density, spacing: %f %f %f\n", catstats[0].Area, 
+	   catstats[0].density, catstats[0].spacing);
+  /* number of stars per square arcsec */
+
+  /** allocate local arrays **/
+  ALLOCATE (catstats[0].X, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].Y, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].N, int,   catalog[0].Naverage);
+
+  /* project onto rectilinear grid with 1 arcsec pixels, sort by X */
+  /* reference for coords is center of field  */
+  catstats[0].coords.crval1 = RaCenter;
+  catstats[0].coords.crval2 = DecCenter;
+  catstats[0].coords.crpix1 = catstats[0].coords.crpix2 = 0.0;
+  catstats[0].coords.cdelt1 = catstats[0].coords.cdelt2 = 1.0 / 3600.0;
+  catstats[0].coords.pc1_1 = catstats[0].coords.pc2_2 = 1.0;
+  catstats[0].coords.pc1_2 = catstats[0].coords.pc2_1 = 0.0;
+  strcpy (catstats[0].coords.ctype, "RA---TAN");
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  for (i = 0; i < catalog[0].Naverage; i++, X1++, Y1++) {
+    fRD_to_XY (X1, Y1, catalog[0].average[i].R, catalog[0].average[i].D, &catstats[0].coords);
+    catstats[0].N[i] = i;
+  }
+  if (catalog[0].Naverage > 1) sort_lists (catstats[0].X, catstats[0].Y, catstats[0].N, catalog[0].Naverage);
+  
+}
+
Index: /trunk/Ohana/src/fixcat/src/gregions.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/gregions.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/gregions.c	(revision 2490)
@@ -0,0 +1,134 @@
+# include "markstar.h"
+
+GSCRegion *gregions1 (catstats, Nregions)
+CatStats catstats[];
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  int i, j, k, x, y, done, nregion, nregion2, NREGION;
+  double ra, dec, dx, dy, Xo[4], Yo[4];
+  FILE *f;
+
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: could not open GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  nregion = 0;
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+
+  if (catstats[0].DEC[0] == 86.25) { /* pole region */
+    dec = 86.0;
+    for (ra = 0.1; ra < 370; ra+= 30.0) {
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion - 1) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  } else {
+    for (x = 0; x < 2; x++) {
+      for (y = 0; y < 2; y++) {
+	for (dx = -0.1; dx <= 0.1; dx += 0.2) {
+	  for (dy = -0.1; dy <= 0.1; dy += 0.2) {
+	    ra  = catstats[0].RA[x] + dx;
+	    dec = catstats[0].DEC[y] + dy;
+	    aregion (&region[nregion], f, ra, dec);
+	    done = FALSE;
+	    for (j = 0; (j < nregion) && !done; j++) {
+	      if (!strcmp (region[nregion].filename, region[j].filename)) {
+		done = TRUE;
+	      }
+	    }
+	    if (!done) {
+	      nregion ++;
+	    } 
+	    if (nregion == NREGION) {
+	      NREGION += 10;
+	      REALLOCATE (region, GSCRegion, NREGION);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "using %d regions\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "region %d: %f %f  %f %f\n", i, region[i].RA[0], region[i].RA[1], region[i].DEC[0], region[i].DEC[1]);
+    } 
+  }
+
+  REALLOCATE (region, GSCRegion, MAX (nregion, 1));
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
+
+GSCRegion *gregions2 (image, Nregions)
+Image *image;
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dr, dd, dec, ra;
+  int i, j, done, nregion, NREGION;
+  
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "found %d region files:\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "  %d %s\n", i, region[i].filename);
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /trunk/Ohana/src/fixcat/src/load_gsc_data.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/load_gsc_data.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/load_gsc_data.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "markstar.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+load_gsc_data (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes, Nregions;
+  double R, D, M, MagLimit;
+  FILE *f;
+  GSCRegion *region, *gregions1(), *gregions2();
+  
+  region = gregions1 (catstats, &Nregions);
+
+  MagLimit = MAX (MAX (BRIGHT_HALO_MAG, BRIGHT_XTRAIL_MAG), BRIGHT_YTRAIL_MAG); 
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  Nbytes = BLOCK*BYTES_STAR;
+  
+  for (j = 0; j < Nregions; j++) {
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "GSC file for region %s missing\n", region[j].filename);
+      exit (0);
+    }
+    
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > MagLimit) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+    fclose (f);
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, nstar);
+  catalog[0].Naverage = nstar;
+  
+}
+
Index: /trunk/Ohana/src/fixcat/src/load_gsc_data_ghost.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/load_gsc_data_ghost.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/load_gsc_data_ghost.c	(revision 2490)
@@ -0,0 +1,75 @@
+# include "markstar.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+/* this routine is basically identical to load_gsc_data, but
+   it is not limited to a single region file, and it merges the 
+   results */
+
+load_gsc_data_ghost (catalog, region, Nregion, image)
+Catalog catalog[];
+GSCRegion *region;
+int Nregion;
+Image image[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes;
+  double R, D, M, X, Y;
+  FILE *f;
+  Coords *tcoords;
+  int MinX, MinY, MaxX, MaxY;
+  
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  tcoords = &image[0].coords;
+  MinX = 0;
+  MinY = 0;
+  MaxX = image[0].NX;
+  MaxY = image[0].NY;
+  
+  for (j = 0; j < Nregion; j++) {
+    
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "no GSC file for region %s (2)\n", region[j].filename);
+      exit (0);
+    }
+    
+    Nbytes = BLOCK*BYTES_STAR;
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > GHOST_MAG) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	RD_to_XY (&X, &Y, R, D, tcoords);
+	if ((X < MinX) || (X > MaxX) || (Y < MinY) || (Y > MaxY)) continue;
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+    fclose (f);
+
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, MAX (nstar, 1));
+  catalog[0].Naverage = nstar;
+
+}
+
+
Index: /trunk/Ohana/src/fixcat/src/mark_trail.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/mark_trail.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/mark_trail.c	(revision 2490)
@@ -0,0 +1,272 @@
+# include "markstar.h"
+int *make_common_list ();
+int *check_common_list ();
+
+mark_trail (catstats, mark, Nave, i, m, b, axis, catalog)
+     CatStats catstats[];
+     char *mark;
+     int i, Nave, axis;
+     double m, b;
+     Catalog catalog[];
+{
+
+  float *R, *D;
+  int j, k, jj, kk, N, NPTS, marked, start, end, Nm;
+  int *good, *seq, *N1;
+  double *dist, *dist2;
+  double d2, di, Di, dD, n, Dist, scale, norm;
+  double spacing;
+  int *list, Nlist;
+  int M, Nmeas, thisimage;
+
+  R = catstats[0].X;
+  D = catstats[0].Y;
+  N1 = catstats[0].N;
+  spacing = catstats[0].spacing;
+
+  NPTS = 200;
+  ALLOCATE (good, int, NPTS);
+  ALLOCATE (dist, double, NPTS);
+  ALLOCATE (dist2, double, NPTS);
+  ALLOCATE (seq, int, NPTS);
+
+  /* Find all points which lie near line */
+  /* save the entry number and distance along line */
+  N = 0;
+  scale = sqrt (1.0 + m*m);
+
+  if (axis == 1) {
+    for (j = 0; j < Nave; j++) {
+      norm = scale * fabs(R[j] - m*D[j] - b);
+      if (!mark[j] && (norm < TRAIL_WIDTH)) {
+	good[N] = j;
+	dist[N] = scale * (D[j] - D[i] + m*(R[j] - R[i]));
+	seq[N] = N;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 200;
+	  REALLOCATE (good, int, NPTS);
+	  REALLOCATE (dist, double, NPTS);
+	  REALLOCATE (dist2, double, NPTS);
+	  REALLOCATE (seq, int, NPTS);
+	}
+      }
+    }
+  } else {
+    for (j = 0; j < Nave; j++) {
+      norm = scale * fabs(D[j] - m*R[j] - b);
+      if (!mark[j] && (norm < TRAIL_WIDTH)) {
+	good[N] = j;
+	dist[N] = scale * (R[j] - R[i] + m*(D[j] - D[i]));
+	seq[N] = N;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 200;
+	  REALLOCATE (good, int, NPTS);
+	  REALLOCATE (dist, double, NPTS);
+	  REALLOCATE (dist2, double, NPTS);
+	  REALLOCATE (seq, int, NPTS);
+	}
+      }
+    }
+  }
+  
+  if (N < NPTSINLINE) 
+    return (0);
+
+  sort_seq (dist, seq, N);
+  
+  start = -1; end = -1;
+  for (j = 0; j < N-1; j++) {
+    /* if we have part of a line, and next point is in the line, check for common images */
+    if ((start != -1) && (fabs(dist[j] - dist[j+1]) < spacing)) {
+      list = check_common_list (list, N1[good[seq[j+1]]], &Nlist, catalog);
+      if (Nlist == 0) { /* if no common images, dump list and continue */
+	end = j + 1;
+	if (end - start > NPTSINLINE) {
+	  if (axis == 0)
+	    fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", m, b, N, end-start, start, end, dist[start], dist[end-1]);
+	  else
+	    fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", 1.0/m, -1.0*b/m, N, end-start, start, end, dist[start], dist[end-1]);
+	  for (k = start; k < end; k++) {
+	    M = N1[good[seq[k]]];
+	    mark[good[seq[k]]] = TRUE;
+	    /* we need to mark measurements from all images in common on the line */
+	    Nm = 0;
+	    for (jj = 0; jj < catalog[0].average[M].Nm; jj++) {
+	      Nmeas = catalog[0].average[M].offset + jj;
+	      thisimage = catalog[0].image[Nmeas];
+	      for (kk = 0; kk < Nlist; kk++) {
+		if (thisimage == list[kk]) {
+		  catalog[0].measure[Nmeas].average |= PART_OF_TRAIL;
+		  Nm ++;
+		}
+	      }
+	    }
+	    /* if there is only 1 measurement, mark object as bad */
+	    if (catalog[0].average[M].Nm == Nm) {
+	      catalog[0].average[M].code = ID_TRAIL;
+	    }
+	    catalog[0].average[M].code = ID_TRAIL;
+	  }
+	}
+	start = -1;
+	end = -1;
+      }
+    }
+    /* if we haven't yet found a line segment, check for the beginning */
+    if ((start < 0) && (fabs(dist[j] - dist[j+1]) < spacing)) {
+      start = j;
+      list = make_common_list (N1[good[seq[j]]], N1[good[seq[j+1]]], &Nlist, catalog);
+      if (Nlist == 0) { /* if no common images, move on */
+	start = -1;
+	free (list);
+      }
+    }
+    /* if we have a complete line, check for validity.  if it has enough members,
+	 mark them and continue searching for lines */
+    if ((start != -1) && ((fabs(dist[j] - dist[j+1]) >= spacing) || (j == N-2))) {
+      end = j + 1;
+      if (end - start > NPTSINLINE) {
+	if (axis == 0)
+	  fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", m, b, N, end-start, start, end, dist[start], dist[end-1]);
+	else
+	  fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", 1.0/m, -1.0*b/m, N, end-start, start, end, dist[start], dist[end-1]);
+	for (k = start; k < end; k++) {
+	  M = N1[good[seq[k]]];
+	  mark[good[seq[k]]] = TRUE;
+	  if (catalog[0].average[M].code == ID_BLEED) continue;
+	  /* we need to mark measurements from all images in common on the line */
+	  Nm = 0;
+	  for (jj = 0; jj < catalog[0].average[M].Nm; jj++) {
+	    Nmeas = catalog[0].average[M].offset + jj;
+	    thisimage = catalog[0].image[Nmeas];
+	    for (kk = 0; kk < Nlist; kk++) {
+	      if (thisimage == list[kk]) {
+		catalog[0].measure[Nmeas].average |= PART_OF_TRAIL;
+		Nm ++;
+	      }
+	    }
+	  }
+	  /* if there is only 1 measurement, mark object as bad */
+	  if (catalog[0].average[M].Nm == Nm) {
+	    catalog[0].average[M].code = ID_TRAIL;
+	  }
+	  catalog[0].average[M].code = ID_TRAIL;
+	}
+      }
+      free (list);
+      start = -1;
+      end = -1;
+    }
+  }
+}
+
+
+/* I is Average seq number for star 1, J for star 2 */
+/* make a list of images in common between two measurements */
+int *make_common_list (I, J, Nlist, catalog)
+int I, J, *Nlist;
+Catalog catalog[];
+{
+
+  int i, j, N1, N2, nlist, NLIST;
+  int *list;
+  int k, already;
+
+  NLIST = 50;
+  ALLOCATE (list, int, NLIST);
+  nlist = 0;
+
+  for (i = 0; i < catalog[0].average[I].Nm; i++) {
+    N1 = catalog[0].average[I].offset + i;
+    if (catalog[0].image[N1] == -1)
+      continue; /* not a real measurement */
+    for (j = 0; j < catalog[0].average[J].Nm; j++) {
+      N2 = catalog[0].average[J].offset + j;
+      if (catalog[0].image[N2] == -1)
+	continue; /* not a real measurement */
+      if (catalog[0].image[N1] == catalog[0].image[N2]) {
+	already = FALSE; 
+	for (k = 0; !already && (k < nlist); k++) {
+	  if (catalog[0].image[N1] == list[k]) { 
+	    already = TRUE;
+	  }
+	}
+	if (!already) {
+	  list[nlist] = catalog[0].image[N1];
+	  nlist ++;
+	  if (nlist == NLIST - 1) {
+	    NLIST += 50;
+	    REALLOCATE (list, int, NLIST);
+	  }
+	}
+      }
+    }
+  }
+  
+  REALLOCATE (list, int, MAX(nlist, 1));
+  *Nlist = nlist;
+  return (list);
+
+}
+
+
+
+/* J is Average seq number for star */
+
+int *check_common_list (inlist, J, Nlist, catalog)
+int *inlist, J, *Nlist;
+Catalog catalog[];
+{
+
+  int i, j, N2, Ninlist;
+  int *list, NLIST, nlist;
+  int already, found, k;
+
+  NLIST = 50;
+  ALLOCATE (list, int, NLIST);
+  nlist = 0;
+  Ninlist = *Nlist;
+
+  for (j = 0; j < catalog[0].average[J].Nm; j++) {
+    N2 = catalog[0].average[J].offset + j;
+    found = FALSE;
+    for (i = 0; !found && (i < Ninlist); i++) {
+      if (catalog[0].image[N2] == -1)
+	continue; /* not a real measurement */
+      if (inlist[i] == catalog[0].image[N2]) {
+	found = TRUE;
+	already = FALSE; 
+	for (k = 0; !already && (k < nlist); k++) {
+	  if (inlist[i] == list[k]) {
+	    already = TRUE;
+	  }
+	}
+	if (!already) {
+	  list[nlist] = inlist[i];
+	  nlist ++;
+	  if (nlist == NLIST - 1) {
+	    NLIST += 50;
+	    REALLOCATE (list, int, NLIST);
+	  }
+	}
+      }
+    }
+  }
+  
+  /* if there are no common images, return the input list */
+  if (nlist != 0) {
+    free (inlist);
+    REALLOCATE (list, int, MAX(nlist, 1));
+    *Nlist = nlist;
+    return (list);
+  } else {
+    return (inlist);
+  }
+
+}
+
+
+/* measurements associated with image number -1 are not 
+   measurements we made, but are added, like USNO */
Index: /trunk/Ohana/src/fixcat/src/markstar.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/markstar.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/markstar.c	(revision 2490)
@@ -0,0 +1,66 @@
+# include "markstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, Nstars, Nimage, Nregions, Nmissed;
+  Image *image, *find_images();
+  Catalog catalog;
+  CatStats catstats;
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  FORCE_RUN = FALSE;
+  if ((i = get_argument (argc, argv, "-f"))) {
+    FORCE_RUN = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  RESET = FALSE;
+  if ((i = get_argument (argc, argv, "-reset"))) {
+    RESET = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: markstar (catalog)\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile (); 
+  check_permissions (argv[1]);
+
+  gcatalog (argv[1], &catalog);
+
+  gcatstats (&catalog, &catstats);
+
+  image = find_images (&catstats, &Nimage);
+
+  match_images (&catalog, image, Nimage);
+    
+  find_bright_stars (&catalog, &catstats); 
+
+  find_ghosts (&catalog, &catstats, argv[1], image, Nimage);  
+
+  find_trails (&catalog, &catstats);  
+
+  wcatalog (argv[1], &catalog);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+}
+
Index: /trunk/Ohana/src/fixcat/src/match_images.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/match_images.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/match_images.c	(revision 2490)
@@ -0,0 +1,57 @@
+# include "markstar.h"
+
+match_images (catalog, image, Nimage)
+Catalog catalog[];
+Image   image[];
+int Nimage;
+{
+  
+  int j, k, found;
+  unsigned int *start, *stop;
+
+  /* this must be allocated so future free will not fail */
+  ALLOCATE (catalog[0].image, int, MAX (catalog[0].Nmeasure, 1));
+  if (catalog[0].Naverage == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars in catalog, skipping\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (start, unsigned int, Nimage);
+  ALLOCATE (stop,  unsigned int, Nimage);
+  for (j = 0; j < Nimage; j++) {
+    start[j] = image[j].tzero - MAX(0.05*image[j].trate*image[j].NY, 1);
+    stop[j]  = image[j].tzero + MAX(1.05*image[j].trate*image[j].NY, 1);
+  }
+
+  for (j = 0; j < catalog[0].Nmeasure; j++) {
+    found = FALSE;
+    if (catalog[0].measure[j].t == 0) {
+      catalog[0].image[j] = -1;
+      found = TRUE;
+    }
+    for (k = 0; (k < Nimage) && !found; k++) {
+      if ((catalog[0].measure[j].t >= start[k]) && 
+	  (catalog[0].measure[j].t <= stop[k])) {
+	catalog[0].image[j] = k;
+	found = TRUE;
+      }
+    }
+    if (!found) {
+      fprintf (stderr, "ERROR: can't find source image for this measurement: %d\n",
+	       catalog[0].measure[j].t);
+      exit (0);
+    }
+  }
+  free (start);
+  free (stop);
+}
+
+  /* this routine uses the time of each measurement to match the
+measurement with an image.  Since the measurement is only store to 1
+sec accuracy, which corresponds to roughly 30 rows at nominal speed,
+we can't tell exactly which image the star come from.  However, this
+doesn't matter, and in fact this helps a bit: a measurement from the
+top of one image is the same as from the bottom of the next.
+Therefore, we intentionally blur the edges of the images by 5%, which
+will help to tie together neighboring images... */
+
Index: /trunk/Ohana/src/fixcat/src/sorts.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/sorts.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/sorts.c	(revision 2490)
@@ -0,0 +1,175 @@
+
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+sort_entries (X, Y, N) 
+     double *X, *Y;
+     int N;
+{
+  int l,j,ir,i;
+  double tX, tY;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+  }
+}
+
+
+
+sort (X, N) 
+     double *X;
+     int N;
+{
+  int l,j,ir,i;
+  double tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+  }
+}
+
+
+sort_seq (X, S, N) 
+     double *X;
+     int *S;
+     int N;
+{
+  int l,j,ir,i;
+  int tS;
+  double tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    S[i] = tS;
+  }
+}
+
Index: /trunk/Ohana/src/fixcat/src/wcatalog.c
===================================================================
--- /trunk/Ohana/src/fixcat/src/wcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/fixcat/src/wcatalog.c	(revision 2490)
@@ -0,0 +1,74 @@
+# include "markstar.h"
+
+wcatalog (catname, catalog)
+char *catname;
+Catalog catalog[];
+{
+  
+  int i, Nitems, nitems, status, mode;
+  char filename[128], line[256];
+  FILE *f;
+  struct stat filestat;
+
+  sprintf (filename, "%s/%s\0", CATDIR, catname);
+
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, make backup copy */
+    sprintf (line, "mv %s %s~\0", filename, filename);
+    status = system (line);
+    if (status) {
+      fprintf (stderr, "ERROR: unable to create %s~, exiting\n", filename);
+      exit (0);
+    }
+  }
+
+  if (catalog[0].Naverage == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars in catalog, skipping\n");
+    return (FALSE);
+  }
+  
+  f = fopen (filename, "w");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't create new catalog file: %s\n", filename);
+    exit (0);
+  }
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  chmod (filename, mode);
+  
+  fits_modify (&catalog[0].header, "NSTARS", "%d", 1, catalog[0].Naverage);
+  fits_modify (&catalog[0].header, "NMEAS", "%d", 1, catalog[0].Nmeasure);
+  fits_modify (&catalog[0].header, "NMISS", "%d", 1, catalog[0].Nmissing);
+
+  fits_modify (&catalog[0].header, "MARKSTAR", "%t", 1, TRUE);
+
+  nitems = Fwrite (catalog[0].header.buffer, 1, catalog[0].header.size, f, "char");
+  if (nitems != catalog[0].header.size) {
+    fprintf (stderr, "ERROR: failed to write header\n");
+    exit (0);
+  }
+
+  Nitems = catalog[0].Naverage;
+  nitems = Fwrite (catalog[0].average, sizeof(Average), Nitems, f, "average");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to write catalog file aves %s\n", filename);
+    exit (0);
+  }
+  
+  Nitems = catalog[0].Nmeasure;
+  nitems = Fwrite (catalog[0].measure, sizeof(Measure), Nitems, f, "measure");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to write catalog file meas %s\n", filename);
+    exit (0);
+  }
+
+  Nitems = catalog[0].Nmissing;
+  nitems = Fwrite (catalog[0].missing, sizeof(Missing), Nitems, f, "missing");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to write catalog file miss %s\n", filename);
+    exit (0);
+  }
+
+  fclose (f);
+
+}
+
Index: /trunk/Ohana/src/getstar/Makefile
===================================================================
--- /trunk/Ohana/src/getstar/Makefile	(revision 2490)
+++ /trunk/Ohana/src/getstar/Makefile	(revision 2490)
@@ -0,0 +1,58 @@
+include ../../Configure
+HOME 	=	$(ROOT)/src/getstar
+PROGRAM =       getstar
+
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC) -I$(LINC)/$(ARCH)
+LIBS	= 	-L$(LLIB) -lFITS -lohana -lm 
+CFLAGS	=	-o $*.$(ARCH).o $(INCS)
+CCFLAGS	=	$(INCS) $(LIBS) 
+
+GETSTAR = \
+$(SRC)/getstar.$(ARCH).o 	$(SRC)/gcatalog.$(ARCH).o 	\
+$(SRC)/gregions.$(ARCH).o 	$(SRC)/gimages.$(ARCH).o        \
+$(SRC)/wstars.$(ARCH).o   	$(SRC)/find_matches.$(ARCH).o 	\
+$(SRC)/sort_lists.$(ARCH).o 	$(SRC)/ConfigInit.$(ARCH).o 	\
+$(SRC)/aregion.$(ARCH).o	$(SRC)/clean_stars.$(ARCH).o	\
+$(SRC)/args.$(ARCH).o
+
+OBJ = $(GETSTAR)
+
+default: $(PROGRAM)
+
+$(GETSTAR): $(INC)/getstar.h
+
+# dependancy rules for binary code ##########################
+$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+
+$(BIN)/$(PROGRAM).$(ARCH): $(OBJ)
+	$(CC) $(OBJ) -o $(BIN)/$(PROGRAM).$(ARCH) $(CCFLAGS)
+
+install: $(DESTBIN)/$(PROGRAM)
+
+$(DESTBIN)/$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+	rm -f $(DESTBIN)/$(PROGRAM)
+	cp $(BIN)/$(PROGRAM).$(ARCH) $(DESTBIN)/$(PROGRAM)
+
+# utilities #################################################
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+.SUFFIXES: .$(ARCH).o
+
+.c.$(ARCH).o:
+	$(CC) $(CFLAGS) -c $<
+
+
Index: /trunk/Ohana/src/getstar/doc/database.txt
===================================================================
--- /trunk/Ohana/src/getstar/doc/database.txt	(revision 2490)
+++ /trunk/Ohana/src/getstar/doc/database.txt	(revision 2490)
@@ -0,0 +1,91 @@
+
+\begin{verbatim}
+
+typedef struct {
+  float R;                    /* RA  in decimal degrees */
+  float D;                    /* DEC in decimal degrees */
+  short int M;                /* thousandths of mag (-32.000 to 32.000 valid range) */
+  unsigned short int Nm;      /* number of measurements */
+  unsigned short int Xp, Xm;  /* chisq values in tenths */
+  unsigned int offset;        /* offset to first Measure-ment */
+} Average;                    /* = 20 bytes / average */
+
+typedef struct {
+  char dR, dD;                /* tenths of arcsec (-12.7 to +12.7 valid range) */
+  short int M;                /* thousandths of mag (-32.000 to 32.000 valid range) */
+  unsigned char dM;           /* thousandths of mag (0.000 -- 0.255 valid range) */
+  float t;                    /* time in seconds (what is reference?) */
+  unsigned int average;       /* reference to corresponding Average entry, 
+				 upper byte of value contains flags.
+				 limit of 16,777,215 stars (Naverage) 
+				 in a file (=0xFFFFFF).
+				 flags = average & 0x1000000 */
+} Measure;                    /* = 13 bytes / measure */
+
+# define BLEND_IMAGE   0X01000000
+# define BLEND_CATALOG 0X02000000
+# define UPPER_LIMIT   0X04000000
+# define CALIBRATED    0X08000000
+
+\end{verbatim}
+
+The above two structures define the entries in the photometry
+database.  The database consists of a large number of files
+representing a small patch on the sky (roughly 1.5 degree$^2$ in most
+places).  These files are organized into directories representing
+bands of Declination.  A reference file determines the coordinate
+boundaries for each of the files so that a given point on the sky can
+unambiguously be associated with a specific file in a specific
+directory.  The sky coordinates for each file is the same as those
+used by the HST Guide Star catalog, except for the region around the
+North celestial pole, for which all stars are included in a single
+file.  
+
+Within a given file, the data are stored in a binary format, with an
+ASCII FITS-like header.  The header is examply in the format of a
+normal FITS header, but with the exception that all files have a fixed
+number of header blocks (for now 3 blocks = 8640 bytes).  This is done
+to speed loading the header and finding the beginning of the binary
+data.  The number of 3 blocks seems quite generous, as currently only
+a few FITS keywords have been defined for each file, basically
+keywords to define the number of stars and the total number of
+measurements stored in the file, as well as values to define the RA
+and DEC range of the file.  
+
+The first section of data following the header blocks consists of
+average measurements for each uniquely observed star.  Each star
+occupies 20 bytes, the size of the Average structure defined above.
+The Average structure contains the average Ra, Dec, and Magnitude for
+the star, as well as the number of measurements, and \chisq\ values
+for the magnitude and position.  Finally, there is a 32 bit integer
+which defines the offset to the first measurement for this star.  This
+offset is defined as the number of Measure records from the start of
+the Measure structure.
+
+The second section of data, following the Average data contains all
+measurements for each star listed in Average.  Each measurement
+occupies 13 bytes, the size of the Measure structure.  This structure
+contains the difference of this position from the average RA and DEC,
+and the instrumental magnitude of this measurement (in the units
+defined by the fstat program, which give m = -2.5*log(cts) + Mo, where
+Mo is currently 24.5 [10/15]).  There is also the magnitude error for
+this measurement, the time of the measurement (in seconds relative to
+a to-be-determined zero point), and a reference to the entry in the
+Average structure so we can relate a given measurement with a given star.
+This last entry also includes a byte of flags, of which only 4 have
+currently been defined.  This means the Average offset can only be as
+large as  16,777,215 (0xffffff), limiting the possible number of stars
+allowed in a given file.  This does not seem like a long term problem,
+though:  aside from the fact that this number is very large and we
+only expect in the vicinity of 20,000 stars per file, the file can
+easily be divided into pieces at a later date if needed.  this last
+step is trivial, consisting of splitting the data up into smaller
+RA,DEC regions, and updating the reference catalog.  With the above
+definitions for the Average and Measure structures, we will typically
+expect 20,000 * 15 measurements per year and 20,000 average entries in
+a given file.  This implies a file size of about 4.3 MB at the end of
+a year.  It is also possible that we will choose to split the files up
+in the future if the number of measurements makes their size
+unweildy.  4.3 MB is sufficiently small that this is not a problem,
+but after only 5 years, the files will be over 21 MB each, getting to
+be fairly significant.  
Index: /trunk/Ohana/src/getstar/doc/description.txt
===================================================================
--- /trunk/Ohana/src/getstar/doc/description.txt	(revision 2490)
+++ /trunk/Ohana/src/getstar/doc/description.txt	(revision 2490)
@@ -0,0 +1,94 @@
+
+ADDSTAR:
+
+This program takes a photometry file, with astrometry, provided by
+earlier routines and incorporates the stellar measurements into the
+photometry database.  This routine does NOT try to calibrate or check
+the photometry, nor does it try to improve the coordinate
+determinations or calculate chisquares for position or photometry -
+those tasks are performed by other routines.
+
+Addstar starts by loading in the photometry file and converting the
+pixel coordinates to sky coordinates using the astrometry information
+in the header of the file.  It also gets the detection limits and
+stores the image astrometry information.
+
+Next, addstar determines which of all the previous images overlaps
+with this image and also which of the catalog regions overlaps with
+this image.
+
+Addstar considers each catalog region in turn, and compares the
+positions of stars in the catalog with stars in the image.  If a
+catalog star is detected, a new measurement is added to the catalog.
+If a catalog star is not detected, but is in the field of view of this
+image, the detection limit for this image is added to the list of
+measurements as an upper limit.  If the image contains a star which is
+not already included in the catalog, the star is added to the catalog,
+and all previous images are checked to see if they included this
+location.  If so, upper limits are added to the list of measurements.
+
+To deal with blended images, we have taken the philosophy that all
+measurements compatible with the coordinates of a given star should be
+included in the list of measurements.  This assumes that programs or people
+downstream will figure out which is the "correct" measurement.  To
+this end, if a catalog star is consistent with multiple measurements,
+they are all added to the catalog measurement and the measurements are
+given a flag to say that there was blending in the catalog (ie, it is
+probably the catalog star which is a blend).  If multiple catalog
+stars are consistent with the same image star, that measurement is
+added to each catalog star, and given a flag to say that there was
+blending on the image.
+
+After all catalogs have been checked, updated, and written to disk,
+the image is added to the database of images.
+
+The format for a catalog region file is as follows:
+
+-- 
+Header
+--
+Averages
+--
+Measurements
+--
+
+The Header follows the format of a FITS header but always stored with
+3 blocks to speed up read time: 2880 x 3 bytes.  Two important
+keywords in the header: NSTARS & NMEAS
+
+All average values are stored consecutively in a single block.  They
+are written as an array with NSTARS elements of the Average structure
+defined below.  The individual measurements follow the averages as a
+block.  To find a measurement for a given star, you need to get the
+value of the offset for the star.  this is the element number for the
+first measurement of this star, and are followed by next measurements
+for this star, until the value Nm is reached.
+
+Here are the structures being used for the average and measurement
+values:
+
+typedef struct {
+  float R;                    /* RA  in decimal degrees */
+  float D;                    /* DEC in decimal degrees */
+  short int M;                /* thousandths of mag (-32.000 to 32.000 valid range) */
+  unsigned short int Nm;      /* number of measurements */
+  unsigned short int Xp, Xm;  /* chisq values in tenths */
+  unsigned int offset;        /* offset to first measurement */
+} Average;                    /* = 20 bytes / average */
+
+typedef struct {
+  char dR, dD;                /* tenths of arcsec (-12.7 to +12.7 valid range) */
+  short int M;                /* thousandths of mag (-32.000 to 32.000 valid range) */
+  unsigned char dM;           /* thousandths of mag (0.000 -- 0.255 valid range) */
+  float t;                    /* time in seconds (what is reference?) */
+  unsigned int average;       
+  /* reference to corresponding average entry, upper byte stores flags:
+   limit of 16,777,215 stars (Naverage) in a file (=0xFFFFFF) 
+   flags: average & 0x1000000 */
+} Measure;                    /* = 13 bytes / measure */
+
+/* flags for measurements: */
+# define BLEND_IMAGE   0X01000000
+# define BLEND_CATALOG 0X02000000
+# define UPPER_LIMIT   0X04000000
+# define CALIBRATED    0X08000000
Index: /trunk/Ohana/src/getstar/etc/phottemp.cat
===================================================================
--- /trunk/Ohana/src/getstar/etc/phottemp.cat	(revision 2490)
+++ /trunk/Ohana/src/getstar/etc/phottemp.cat	(revision 2490)
@@ -0,0 +1,296 @@
+SIMPLE  =                    F  / ASTROCAM PHOTOMETRY FILE                    \
+BITPIX  =                   16 /                                              \
+NAXIS   =                    2  / NUMBER OF AXES                              \
+NAXIS1  =                 1106  / NUMBER OF COLUMNS                           \
+NAXIS2  =                 1024  / NUMBER OF ROWS                              \
+BSCALE  =             1.000000 /                                              \
+BZERO   =             0.000000 /                                              \
+DATE    = '19/12/94'            / UT Date of file creation (DD/MM/YY)         \
+ORIGIN  = 'MDM Observatory'     / Michigan-Dartmouth-MIT                      \
+LATITUDE=              31.9500  / Latitude (degrees N)                        \
+LONGITUD=            -111.6150  / Longitude (degrees E)                       \
+OBSERVER= 'Metzger '            / Name of observer                            \
+TELESCOP= '1.3m McGraw-Hill'    / Telescope used for observation              \
+INSTRUME= 'Charlotte Direct'    / Instrument used for observation             \
+DETECTOR= 'Charlotte/Tek 1024^2 CCD'  / Detector used for observation         \
+FRAME   =                   32  / Frame number of observation                 \
+CCDPICNO=                   32  / Frame number of observation                 \
+OBJECT  = 'ocl0327 '            / Name of object                              \
+IMAGETYP= 'OBJECT  '            / Type of observation                         \
+EXPTIME =              250.000  / Integration time (seconds)                  \
+DARKTIME=              250.067  / Dark current time (seconds)                 \
+DATE-OBS= '19/12/94'            / UT Date of observation (DD/MM/YY)           \
+UT      = ' 05:25:44.00'        / Universal time (UTC) at exposure start      \
+JD      =       2449705.726204                                                \
+RA      =           50.700      / Right Ascension                             \
+DEC     =           89.000      / Declination                                 \
+DIRECTN =                 -1    / Moving South                                \
+EQUINOX =             1950.000  / Equinox of RA and DEC                       \
+HA      = ' 02:14:06.72'        / Hour angle at start                         \
+ST      = ' 03:49:36.85'        / Sidereal time at start                      \
+ZD      = ' 36:26:07.17'        / Zenith distance (degrees)                   \
+AIRMASS =                1.243  / Airmass at start                            \
+FILTER  = 'I KP    '            / Filter description                          \
+GAIN    =                3.350  / Nominal gain (e-/ADU)                       \
+SECPIX1 =                0.508  / Arcseconds per pixel in fast dir            \
+SECPIX2 =                0.508  / Arcseconds per pixel in slow dir            \
+CCDBIN1 =                    1  / On-chip column binning (fast dir)           \
+CCDBIN2 =                    1  / On-chip row binning (slow dir)              \
+GPROBE  = '  5000.00   7000.00'  / Guide probe X Y                            \
+DATASEC = '[51:1074,1:1024]'    / Image area of frame                         \
+CCDSEC  = '[1:1074,1:1024]'     / Image area relative to full chip            \
+BIASSEC = '[1080:1106,1:1023]'  / Overscan area of frame                      \
+UNSIGN  =                    T /                                              \
+NSTARS  =                    0  / NUMBER OF stars                             \
+CTYPE1  = 'RA---SIN          ' /                                               
+CTYPE2  = 'DEC--SIN          ' /                                               
+CDELT1  =             0.000733 /                                               
+CDELT2  =             0.000733 /                                               
+CRVAL1  =            50.191418 /                                               
+CRVAL2  =            88.998663 /                                               
+CRPIX1  =          1028.644173 /                                               
+CRPIX2  =           503.129830 /                                               
+PC001001=             0.999906 /                                               
+PC001002=             0.012081 /                                               
+PC002001=            -0.011936 /                                               
+PC002002=             0.999950 /                                               
+END                                                                           \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+ 246.5  352.1 13.000 020 1 3.2
+ 246.5  352.1 14.100 020 1 3.2
+ 279.4  328.9 13.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 436.6  413.5 14.300 020 1 3.2
+   9.3  856.5 13.000 020 1 3.2
+   9.3  856.2 13.600 020 1 3.2
+ 319.7  697.9 12.000 020 1 3.2
+ 319.7  697.7 12.100 020 1 3.2
+ 244.3    9.5 14.100 020 1 3.2
+ 284.7  334.4 14.000 020 1 3.2
+ 127.1  122.8 14.200 020 1 3.2
+ 140.2  791.1 13.700 020 1 3.2
+ 140.2  790.8 14.400 020 1 3.2
+ 131.7  636.3 13.800 020 1 3.2
+ 423.8  700.6 13.800 020 1 3.2
+ 423.7  700.7 12.500 020 1 3.2
+ 266.2  290.7 13.800 020 1 3.2
+ 266.0  290.7 13.100 020 1 3.2
+ 570.7  721.6 13.600 020 1 3.2
+ 570.7  721.6 13.100 020 1 3.2
+ 548.7  673.0 13.700 020 1 3.2
+ 264.2  219.7 12.800 020 1 3.2
+ 264.0  219.7 12.100 020 1 3.2
+ 161.9  797.4 11.900 020 1 3.2
+ 162.0  797.2 12.200 020 1 3.2
+ 505.8  851.8 13.700 020 1 3.2
+  88.2  419.0 11.400 020 1 3.2
+  88.2  419.0 11.800 020 1 3.2
+ 426.9  613.2  9.400 020 1 3.2
+ 427.4  613.5  7.600 020 1 3.2
+ 326.1  595.2 12.100 020 1 3.2
+ 326.2  595.1 12.600 020 1 3.2
+ 444.4  845.2 14.200 020 1 3.2
+ 254.1  916.8 14.500 020 1 3.2
+ 502.6  882.4 14.200 020 1 3.2
+ 128.3  275.7 12.300 020 1 3.2
+ 128.3  275.7 12.900 020 1 3.2
+ 230.9  554.8 13.300 020 1 3.2
+ 230.9  554.7 14.200 020 1 3.2
+  47.5  685.2 13.500 020 1 3.2
+  47.5  684.9 14.200 020 1 3.2
+ 382.6  658.7 14.000 020 1 3.2
+ 182.2  330.3 14.200 020 1 3.2
+ 245.1  548.3 12.600 020 1 3.2
+ 245.3  548.0 13.200 020 1 3.2
+  50.3  849.0 13.700 020 1 3.2
+  50.5  848.8 14.300 020 1 3.2
+  17.9  772.7 14.200 020 1 3.2
+ 499.8  712.8 13.500 020 1 3.2
+ 499.8  712.6 14.400 020 1 3.2
+ 294.5  349.4 14.000 020 1 3.2
+ 497.7  747.8 11.000 020 1 3.2
+ 497.5  747.8 10.900 020 1 3.2
+ 109.7  323.5 14.000 020 1 3.2
+  59.5  917.6 14.300 020 1 3.2
+  59.4  917.8 13.700 020 1 3.2
+  82.2  880.5 13.800 020 1 3.2
+ 145.1  341.2 14.500 020 1 3.2
+ 452.7  592.4 14.400 020 1 3.2
+ 623.4  820.0 13.700 020 1 3.2
+ 609.7  829.3 13.500 020 1 3.2
+ 481.8  938.3 14.400 020 1 3.2
+ 617.0  792.7 13.500 020 1 3.2
+ 183.2  539.7 14.400 020 1 3.2
+ 133.9  679.6 14.400 020 1 3.2
+ 423.7  667.8  6.500 020 1 3.2
+ 434.7  111.9 13.200 020 1 3.2
+ 434.5  111.9 13.200 020 1 3.2
+ 434.6  111.9 14.200 020 1 3.2
+1222.3  684.2 13.900 020 1 3.2
+1077.6  282.5 14.000 020 1 3.2
+1077.8  282.5 13.400 020 1 3.2
+ 720.8  562.1 14.100 020 1 3.2
+ 721.1  561.9 14.400 020 1 3.2
+1182.1  944.4 12.100 020 1 3.2
+1181.9  944.4 11.800 020 1 3.2
+1181.9  944.4 12.300 020 1 3.2
+ 761.2  423.1 14.300 020 1 3.2
+ 761.0  423.1 14.100 020 1 3.2
+ 926.7  436.8 13.400 020 1 3.2
+ 926.6  436.8 14.200 020 1 3.2
+1209.1   45.0 13.200 020 1 3.2
+1209.2   43.6 12.800 020 1 3.2
+1135.2  653.1  8.100 020 1 3.2
+1135.6  653.4  8.200 020 1 3.2
+1123.5  735.8 12.000 020 1 3.2
+1123.6  735.8 11.800 020 1 3.2
+1123.7  735.7 11.600 020 1 3.2
+ 730.7   28.6 12.100 020 1 3.2
+ 730.7   28.6 12.200 020 1 3.2
+ 783.1  267.5 14.200 020 1 3.2
+ 783.2  267.5 13.400 020 1 3.2
+ 876.2  462.7 13.800 020 1 3.2
+ 876.4  462.7 14.200 020 1 3.2
+ 917.2  399.9 13.700 020 1 3.2
+ 917.3  399.9 13.200 020 1 3.2
+1227.5  218.4 10.400 020 1 3.2
+1227.7  218.4 10.500 020 1 3.2
+1022.7  146.0 13.300 020 1 3.2
+1022.5  146.0 14.100 020 1 3.2
+1324.7   72.3 12.900 020 1 3.2
+1324.6   72.3 13.200 020 1 3.2
+ 743.2  379.4 14.300 020 1 3.2
+ 742.9  379.4 13.900 020 1 3.2
+1255.9  544.0 12.600 020 1 3.2
+1256.0  543.9 12.300 020 1 3.2
+ 848.9  251.1 13.200 020 1 3.2
+ 849.0  251.1 12.700 020 1 3.2
+ 495.6  147.4 11.400 020 1 3.2
+ 495.6  147.4 11.300 020 1 3.2
+ 495.5  147.4 11.000 020 1 3.2
+1016.4  735.5 14.200 020 1 3.2
+1016.3  735.7 13.900 020 1 3.2
+ 795.2  675.9 14.400 020 1 3.2
+ 887.2  968.8 10.800 020 1 3.2
+ 626.8  726.9 14.400 020 1 3.2
+ 718.6  800.1  9.700 020 1 3.2
+ 675.4  301.6 14.400 020 1 3.2
+ 801.6  436.8 14.200 020 1 3.2
+1066.4  870.0 13.700 020 1 3.2
+1066.5  869.9 13.800 020 1 3.2
+ 644.5  662.9  9.900 020 1 3.2
+ 639.1  760.4 13.000 020 1 3.2
+ 822.7  663.1 12.800 020 1 3.2
+ 822.7  663.1 13.100 020 1 3.2
+ 677.2  716.2 12.900 020 1 3.2
+ 765.6  641.5 13.200 020 1 3.2
+ 765.7  641.4 13.500 020 1 3.2
+ 998.3  425.8 14.400 020 1 3.2
+ 713.7  716.2 13.800 020 1 3.2
+ 814.7  887.6  2.000 020 1 3.2
+ 808.7  884.1  8.200 020 1 3.2
+1812.3  259.3 14.500 020 1 3.2
+1655.9  655.4 12.200 020 1 3.2
+1655.9  655.4 12.100 020 1 3.2
+1577.2  839.6 11.500 020 1 3.2
+1577.2  839.6 11.400 020 1 3.2
+1643.7  597.0 14.100 020 1 3.2
+1552.8  251.1 10.100 020 1 3.2
+1552.8  251.1 10.300 020 1 3.2
+1410.0  999.9 13.900 020 1 3.2
+1335.6  687.0 13.000 020 1 3.2
+1335.8  686.8 12.700 020 1 3.2
+1471.4  262.0 14.200 020 1 3.2
+1479.6  608.3 14.200 020 1 3.2
+1478.1  211.5 12.000 020 1 3.2
+1478.3  211.5 12.000 020 1 3.2
+1552.5   46.4 14.500 020 1 3.2
+2042.4  548.3 10.800 020 1 3.2
+2042.6  548.3 11.000 020 1 3.2
+1448.0  915.7 14.100 020 1 3.2
+1462.3  989.2 13.000 020 1 3.2
+1462.3  989.0 12.700 020 1 3.2
+1316.9  787.3 14.100 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1677.2  106.4 13.100 020 1 3.2
+1677.0  106.4 13.300 020 1 3.2
+1324.2  429.9  9.200 020 1 3.2
+1324.2  429.9  9.000 020 1 3.2
+1462.8  214.3 13.700 020 1 3.2
+1462.8  214.3 14.200 020 1 3.2
+1405.4   95.5 11.700 020 1 3.2
+1405.2   95.5 11.600 020 1 3.2
+1604.8   90.0 11.200 020 1 3.2
+1604.8   90.0 11.300 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1459.8  473.6 13.400 020 1 3.2
+1459.7  473.6 13.800 020 1 3.2
+1438.7   77.8 12.200 020 1 3.2
+1438.6   77.8 12.200 020 1 3.2
+1355.0  114.6 13.000 020 1 3.2
+1354.9  114.6 13.200 020 1 3.2
+1941.4  940.7 13.000 020 1 3.2
+1941.6  940.7 12.900 020 1 3.2
+1994.0  800.8 13.900 020 1 3.2
+1993.8  800.8 14.000 020 1 3.2
+2024.4  907.0 13.700 020 1 3.2
+2024.4  907.0 13.800 020 1 3.2
+2035.7  881.6 13.900 020 1 3.2
+2035.9  881.6 13.800 020 1 3.2
+1994.0  924.2 12.100 020 1 3.2
+1994.0  924.2 12.000 020 1 3.2
Index: /trunk/Ohana/src/getstar/etc/template.cat
===================================================================
--- /trunk/Ohana/src/getstar/etc/template.cat	(revision 2490)
+++ /trunk/Ohana/src/getstar/etc/template.cat	(revision 2490)
@@ -0,0 +1,296 @@
+SIMPLE  =                    F  / ASTROCAM PHOTOMETRY FILE                    \
+BITPIX  =                   16 /                                              \
+NAXIS   =                    2  / NUMBER OF AXES                              \
+NAXIS1  =                 1106  / NUMBER OF COLUMNS                           \
+NAXIS2  =                 1024  / NUMBER OF ROWS                              \
+BSCALE  =             1.000000 /                                              \
+BZERO   =             0.000000 /                                              \
+DATE    = '19/12/94'            / UT Date of file creation (DD/MM/YY)         \
+ORIGIN  = 'MDM Observatory'     / Michigan-Dartmouth-MIT                      \
+LATITUDE=              31.9500  / Latitude (degrees N)                        \
+LONGITUD=            -111.6150  / Longitude (degrees E)                       \
+OBSERVER= 'Metzger '            / Name of observer                            \
+TELESCOP= '1.3m McGraw-Hill'    / Telescope used for observation              \
+INSTRUME= 'Charlotte Direct'    / Instrument used for observation             \
+DETECTOR= 'Charlotte/Tek 1024^2 CCD'  / Detector used for observation         \
+FRAME   =                   32  / Frame number of observation                 \
+CCDPICNO=                   32  / Frame number of observation                 \
+OBJECT  = 'ocl0327 '            / Name of object                              \
+IMAGETYP= 'OBJECT  '            / Type of observation                         \
+EXPTIME =              250.000  / Integration time (seconds)                  \
+DARKTIME=              250.067  / Dark current time (seconds)                 \
+DATE-OBS= '19/12/94'            / UT Date of observation (DD/MM/YY)           \
+UT      = ' 05:25:44.00'        / Universal time (UTC) at exposure start      \
+JD      =       2449705.726204                                                \
+RA      =           50.700      / Right Ascension                             \
+DEC     =           89.000      / Declination                                 \
+DIRECTN =                 -1    / Moving South                                \
+EQUINOX =             1950.000  / Equinox of RA and DEC                       \
+HA      = ' 02:14:06.72'        / Hour angle at start                         \
+ST      = ' 03:49:36.85'        / Sidereal time at start                      \
+ZD      = ' 36:26:07.17'        / Zenith distance (degrees)                   \
+AIRMASS =                1.243  / Airmass at start                            \
+FILTER  = 'I KP    '            / Filter description                          \
+GAIN    =                3.350  / Nominal gain (e-/ADU)                       \
+SECPIX1 =                0.508  / Arcseconds per pixel in fast dir            \
+SECPIX2 =                0.508  / Arcseconds per pixel in slow dir            \
+CCDBIN1 =                    1  / On-chip column binning (fast dir)           \
+CCDBIN2 =                    1  / On-chip row binning (slow dir)              \
+GPROBE  = '  5000.00   7000.00'  / Guide probe X Y                            \
+DATASEC = '[51:1074,1:1024]'    / Image area of frame                         \
+CCDSEC  = '[1:1074,1:1024]'     / Image area relative to full chip            \
+BIASSEC = '[1080:1106,1:1023]'  / Overscan area of frame                      \
+UNSIGN  =                    T /                                              \
+NSTARS  =                    0  / NUMBER OF stars                             \
+CTYPE1  = 'RA---SIN          ' /                                               
+CTYPE2  = 'DEC--SIN          ' /                                               
+CDELT1  =             0.000733 /                                               
+CDELT2  =             0.000733 /                                               
+CRVAL1  =            50.191418 /                                               
+CRVAL2  =            88.998663 /                                               
+CRPIX1  =          1028.644173 /                                               
+CRPIX2  =           503.129830 /                                               
+PC001001=             0.999906 /                                               
+PC001002=             0.012081 /                                               
+PC002001=            -0.011936 /                                               
+PC002002=             0.999950 /                                               
+END                                                                           \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+                                                                              \
+ 246.5  352.1 13.000 020 1 3.2
+ 246.5  352.1 14.100 020 1 3.2
+ 279.4  328.9 13.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 187.3  238.8  9.800 020 1 3.2
+ 436.6  413.5 14.300 020 1 3.2
+   9.3  856.5 13.000 020 1 3.2
+   9.3  856.2 13.600 020 1 3.2
+ 319.7  697.9 12.000 020 1 3.2
+ 319.7  697.7 12.100 020 1 3.2
+ 244.3    9.5 14.100 020 1 3.2
+ 284.7  334.4 14.000 020 1 3.2
+ 127.1  122.8 14.200 020 1 3.2
+ 140.2  791.1 13.700 020 1 3.2
+ 140.2  790.8 14.400 020 1 3.2
+ 131.7  636.3 13.800 020 1 3.2
+ 423.8  700.6 13.800 020 1 3.2
+ 423.7  700.7 12.500 020 1 3.2
+ 266.2  290.7 13.800 020 1 3.2
+ 266.0  290.7 13.100 020 1 3.2
+ 570.7  721.6 13.600 020 1 3.2
+ 570.7  721.6 13.100 020 1 3.2
+ 548.7  673.0 13.700 020 1 3.2
+ 264.2  219.7 12.800 020 1 3.2
+ 264.0  219.7 12.100 020 1 3.2
+ 161.9  797.4 11.900 020 1 3.2
+ 162.0  797.2 12.200 020 1 3.2
+ 505.8  851.8 13.700 020 1 3.2
+  88.2  419.0 11.400 020 1 3.2
+  88.2  419.0 11.800 020 1 3.2
+ 426.9  613.2  9.400 020 1 3.2
+ 427.4  613.5  7.600 020 1 3.2
+ 326.1  595.2 12.100 020 1 3.2
+ 326.2  595.1 12.600 020 1 3.2
+ 444.4  845.2 14.200 020 1 3.2
+ 254.1  916.8 14.500 020 1 3.2
+ 502.6  882.4 14.200 020 1 3.2
+ 128.3  275.7 12.300 020 1 3.2
+ 128.3  275.7 12.900 020 1 3.2
+ 230.9  554.8 13.300 020 1 3.2
+ 230.9  554.7 14.200 020 1 3.2
+  47.5  685.2 13.500 020 1 3.2
+  47.5  684.9 14.200 020 1 3.2
+ 382.6  658.7 14.000 020 1 3.2
+ 182.2  330.3 14.200 020 1 3.2
+ 245.1  548.3 12.600 020 1 3.2
+ 245.3  548.0 13.200 020 1 3.2
+  50.3  849.0 13.700 020 1 3.2
+  50.5  848.8 14.300 020 1 3.2
+  17.9  772.7 14.200 020 1 3.2
+ 499.8  712.8 13.500 020 1 3.2
+ 499.8  712.6 14.400 020 1 3.2
+ 294.5  349.4 14.000 020 1 3.2
+ 497.7  747.8 11.000 020 1 3.2
+ 497.5  747.8 10.900 020 1 3.2
+ 109.7  323.5 14.000 020 1 3.2
+  59.5  917.6 14.300 020 1 3.2
+  59.4  917.8 13.700 020 1 3.2
+  82.2  880.5 13.800 020 1 3.2
+ 145.1  341.2 14.500 020 1 3.2
+ 452.7  592.4 14.400 020 1 3.2
+ 623.4  820.0 13.700 020 1 3.2
+ 609.7  829.3 13.500 020 1 3.2
+ 481.8  938.3 14.400 020 1 3.2
+ 617.0  792.7 13.500 020 1 3.2
+ 183.2  539.7 14.400 020 1 3.2
+ 133.9  679.6 14.400 020 1 3.2
+ 423.7  667.8  6.500 020 1 3.2
+ 434.7  111.9 13.200 020 1 3.2
+ 434.5  111.9 13.200 020 1 3.2
+ 434.6  111.9 14.200 020 1 3.2
+1222.3  684.2 13.900 020 1 3.2
+1077.6  282.5 14.000 020 1 3.2
+1077.8  282.5 13.400 020 1 3.2
+ 720.8  562.1 14.100 020 1 3.2
+ 721.1  561.9 14.400 020 1 3.2
+1182.1  944.4 12.100 020 1 3.2
+1181.9  944.4 11.800 020 1 3.2
+1181.9  944.4 12.300 020 1 3.2
+ 761.2  423.1 14.300 020 1 3.2
+ 761.0  423.1 14.100 020 1 3.2
+ 926.7  436.8 13.400 020 1 3.2
+ 926.6  436.8 14.200 020 1 3.2
+1209.1   45.0 13.200 020 1 3.2
+1209.2   43.6 12.800 020 1 3.2
+1135.2  653.1  8.100 020 1 3.2
+1135.6  653.4  8.200 020 1 3.2
+1123.5  735.8 12.000 020 1 3.2
+1123.6  735.8 11.800 020 1 3.2
+1123.7  735.7 11.600 020 1 3.2
+ 730.7   28.6 12.100 020 1 3.2
+ 730.7   28.6 12.200 020 1 3.2
+ 783.1  267.5 14.200 020 1 3.2
+ 783.2  267.5 13.400 020 1 3.2
+ 876.2  462.7 13.800 020 1 3.2
+ 876.4  462.7 14.200 020 1 3.2
+ 917.2  399.9 13.700 020 1 3.2
+ 917.3  399.9 13.200 020 1 3.2
+1227.5  218.4 10.400 020 1 3.2
+1227.7  218.4 10.500 020 1 3.2
+1022.7  146.0 13.300 020 1 3.2
+1022.5  146.0 14.100 020 1 3.2
+1324.7   72.3 12.900 020 1 3.2
+1324.6   72.3 13.200 020 1 3.2
+ 743.2  379.4 14.300 020 1 3.2
+ 742.9  379.4 13.900 020 1 3.2
+1255.9  544.0 12.600 020 1 3.2
+1256.0  543.9 12.300 020 1 3.2
+ 848.9  251.1 13.200 020 1 3.2
+ 849.0  251.1 12.700 020 1 3.2
+ 495.6  147.4 11.400 020 1 3.2
+ 495.6  147.4 11.300 020 1 3.2
+ 495.5  147.4 11.000 020 1 3.2
+1016.4  735.5 14.200 020 1 3.2
+1016.3  735.7 13.900 020 1 3.2
+ 795.2  675.9 14.400 020 1 3.2
+ 887.2  968.8 10.800 020 1 3.2
+ 626.8  726.9 14.400 020 1 3.2
+ 718.6  800.1  9.700 020 1 3.2
+ 675.4  301.6 14.400 020 1 3.2
+ 801.6  436.8 14.200 020 1 3.2
+1066.4  870.0 13.700 020 1 3.2
+1066.5  869.9 13.800 020 1 3.2
+ 644.5  662.9  9.900 020 1 3.2
+ 639.1  760.4 13.000 020 1 3.2
+ 822.7  663.1 12.800 020 1 3.2
+ 822.7  663.1 13.100 020 1 3.2
+ 677.2  716.2 12.900 020 1 3.2
+ 765.6  641.5 13.200 020 1 3.2
+ 765.7  641.4 13.500 020 1 3.2
+ 998.3  425.8 14.400 020 1 3.2
+ 713.7  716.2 13.800 020 1 3.2
+ 814.7  887.6  2.000 020 1 3.2
+ 808.7  884.1  8.200 020 1 3.2
+1812.3  259.3 14.500 020 1 3.2
+1655.9  655.4 12.200 020 1 3.2
+1655.9  655.4 12.100 020 1 3.2
+1577.2  839.6 11.500 020 1 3.2
+1577.2  839.6 11.400 020 1 3.2
+1643.7  597.0 14.100 020 1 3.2
+1552.8  251.1 10.100 020 1 3.2
+1552.8  251.1 10.300 020 1 3.2
+1410.0  999.9 13.900 020 1 3.2
+1335.6  687.0 13.000 020 1 3.2
+1335.8  686.8 12.700 020 1 3.2
+1471.4  262.0 14.200 020 1 3.2
+1479.6  608.3 14.200 020 1 3.2
+1478.1  211.5 12.000 020 1 3.2
+1478.3  211.5 12.000 020 1 3.2
+1552.5   46.4 14.500 020 1 3.2
+2042.4  548.3 10.800 020 1 3.2
+2042.6  548.3 11.000 020 1 3.2
+1448.0  915.7 14.100 020 1 3.2
+1462.3  989.2 13.000 020 1 3.2
+1462.3  989.0 12.700 020 1 3.2
+1316.9  787.3 14.100 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1787.6  883.5 12.200 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1979.1  300.3 12.900 020 1 3.2
+1677.2  106.4 13.100 020 1 3.2
+1677.0  106.4 13.300 020 1 3.2
+1324.2  429.9  9.200 020 1 3.2
+1324.2  429.9  9.000 020 1 3.2
+1462.8  214.3 13.700 020 1 3.2
+1462.8  214.3 14.200 020 1 3.2
+1405.4   95.5 11.700 020 1 3.2
+1405.2   95.5 11.600 020 1 3.2
+1604.8   90.0 11.200 020 1 3.2
+1604.8   90.0 11.300 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1921.5  738.1 13.500 020 1 3.2
+1459.8  473.6 13.400 020 1 3.2
+1459.7  473.6 13.800 020 1 3.2
+1438.7   77.8 12.200 020 1 3.2
+1438.6   77.8 12.200 020 1 3.2
+1355.0  114.6 13.000 020 1 3.2
+1354.9  114.6 13.200 020 1 3.2
+1941.4  940.7 13.000 020 1 3.2
+1941.6  940.7 12.900 020 1 3.2
+1994.0  800.8 13.900 020 1 3.2
+1993.8  800.8 14.000 020 1 3.2
+2024.4  907.0 13.700 020 1 3.2
+2024.4  907.0 13.800 020 1 3.2
+2035.7  881.6 13.900 020 1 3.2
+2035.9  881.6 13.800 020 1 3.2
+1994.0  924.2 12.100 020 1 3.2
+1994.0  924.2 12.000 020 1 3.2
Index: /trunk/Ohana/src/getstar/include/addstar.h
===================================================================
--- /trunk/Ohana/src/getstar/include/addstar.h	(revision 2490)
+++ /trunk/Ohana/src/getstar/include/addstar.h	(revision 2490)
@@ -0,0 +1,47 @@
+# include <ohana.h>
+# include <loneos.h>
+# include <signal.h>
+
+typedef struct {
+  double X;
+  double Y;
+  double R;
+  double D;
+  double M, dM;
+  char   dophot;
+  double sky;
+  double fx, fy, df;
+  double Mgal, Map;
+  int found;
+} Stars;
+
+/* global variables set in parameter file */
+char   ImageCat[256];
+char   ImageTemplate[256];
+char   CatTemplate[256];
+char   GSCFILE[256];
+char   CATDIR[256];
+double DEFAULT_RADIUS, NSIGMA, SNLIMIT;
+double ZeroPt;
+int    VERBOSE;
+int    SKIP_MISSED;
+int    XOVERSCAN, YOVERSCAN;
+int    XMIN, XMAX, YMIN, YMAX;
+int    ACCEPT_ASTROM;
+
+PhotCode *thiscode;
+
+char DateKeyword[64];
+char DateMode[64];
+char UTKeyword[64];
+char MJDKeyword[64];
+char JDKeyword[64];
+char ExptimeKeyword[64];
+char AirmassKeyword[64];
+char CCDNumKeyword[64];
+
+int CalReference;
+int CalColor;
+int CALIBRATE;
+int DUMP_MATCHES;
+int ONLY_IMAGES;
Index: /trunk/Ohana/src/getstar/include/getstar.h
===================================================================
--- /trunk/Ohana/src/getstar/include/getstar.h	(revision 2490)
+++ /trunk/Ohana/src/getstar/include/getstar.h	(revision 2490)
@@ -0,0 +1,47 @@
+# include <ohana.h>
+# include <loneos.h>
+# include <signal.h>
+
+typedef struct {
+  double X;
+  double Y;
+  double R;
+  double D;
+  double M, dM;
+  char   dophot;
+  double sky;
+  double fx, fy, df;
+  double Mgal, Map;
+  int found;
+} Stars;
+
+/* global variables set in parameter file */
+char   ImageCat[256];
+char   ImageTemplate[256];
+char   CatTemplate[256];
+char   GSCFILE[256];
+char   CATDIR[256];
+double DEFAULT_RADIUS, NSIGMA, SNLIMIT;
+double ZeroPt;
+int    VERBOSE;
+int    SKIP_MISSED;
+int    XOVERSCAN, YOVERSCAN;
+int    XMIN, XMAX, YMIN, YMAX;
+int    ACCEPT_ASTROM;
+
+PhotCode *thiscode;
+
+char DateKeyword[64];
+char DateMode[64];
+char UTKeyword[64];
+char MJDKeyword[64];
+char JDKeyword[64];
+char ExptimeKeyword[64];
+char AirmassKeyword[64];
+char CCDNumKeyword[64];
+
+int CalReference;
+int CalColor;
+int CALIBRATE;
+int DUMP_MATCHES;
+int ONLY_IMAGES;
Index: /trunk/Ohana/src/getstar/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/getstar/src/ConfigInit.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/ConfigInit.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "getstar.h"
+
+ConfigInit (int *argc, char **argv) {
+
+  char *config, *file;
+  char RadiusWord[80];
+  char PhotCodeFile[256];
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (1);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+  ScanConfig (config, "RADIUS",                 "%s", 0,  RadiusWord);
+  if (!strcasecmp (RadiusWord, "header")) {
+    DEFAULT_RADIUS = 0;
+  } else {
+    DEFAULT_RADIUS = atof (RadiusWord);
+  }
+
+  XMIN = XMAX = YMIN = YMAX = 0;
+  ScanConfig (config, "NSIGMA",                 "%lf", 0, &NSIGMA);
+  ScanConfig (config, "XOVERSCAN",              "%d", 0, &XOVERSCAN);
+  ScanConfig (config, "YOVERSCAN",              "%d", 0, &YOVERSCAN);
+  ScanConfig (config, "ZERO_PT",                "%lf", 0, &ZeroPt);
+
+  ScanConfig (config, "ADDSTAR_XMIN",           "%d", 0, &XMIN);
+  ScanConfig (config, "ADDSTAR_XMAX",           "%d", 0, &XMAX);
+  ScanConfig (config, "ADDSTAR_YMIN",           "%d", 0, &YMIN);
+  ScanConfig (config, "ADDSTAR_YMAX",           "%d", 0, &YMAX);
+
+  ScanConfig (config, "IMAGE_CATALOG",          "%s", 0, ImageCat);
+  ScanConfig (config, "IMAGE_CATALOG_TEMPLATE", "%s", 0, ImageTemplate);
+  ScanConfig (config, "CATALOG_TEMPLATE",       "%s", 0, CatTemplate);
+  ScanConfig (config, "GSCFILE",                "%s", 0, GSCFILE);
+  ScanConfig (config, "CATDIR",                 "%s", 0, CATDIR);
+  ScanConfig (config, "MIN_SN_FSTAT",           "%lf", 0, &SNLIMIT);
+  ScanConfig (config, "PHOTCODE_FILE",          "%s", 0, PhotCodeFile);
+
+  ScanConfig (config, "DATE-KEYWORD",           "%s", 0, DateKeyword);
+  ScanConfig (config, "DATE-MODE",              "%s", 0, DateMode);
+  ScanConfig (config, "UT-KEYWORD",             "%s", 0, UTKeyword);
+  ScanConfig (config, "MJD-KEYWORD",            "%s", 0, MJDKeyword);
+  ScanConfig (config, "JD-KEYWORD",             "%s", 0, JDKeyword);
+
+  ScanConfig (config, "EXPTIME-KEYWORD",        "%s", 0, ExptimeKeyword);
+  ScanConfig (config, "AIRMASS-KEYWORD",        "%s", 0, AirmassKeyword);
+  ScanConfig (config, "CCDNUM-KEYWORD",         "%s", 0, CCDNumKeyword);
+
+  if (!LoadPhotcodes (PhotCodeFile)) {
+    fprintf (stderr, "error loading photcodes\n");
+    exit (1);
+  }
+
+  free (config);
+  free (file);
+
+}
Index: /trunk/Ohana/src/getstar/src/addstar.c
===================================================================
--- /trunk/Ohana/src/getstar/src/addstar.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/addstar.c	(revision 2490)
@@ -0,0 +1,223 @@
+# include "addstar.h"
+
+/* these variables are needed by Shutdown */
+static FILE *f = (FILE *) NULL;
+static int Protect = FALSE;
+static int Trapped = FALSE;
+
+/* clean up open / locked ImageCat before shutting down */
+int Shutdown () {  
+  int dbstate;
+
+  Protect = TRUE;
+  fclearlockfile (ImageCat, f, LCK_HARD, &dbstate);
+  fprintf (stderr, "ERROR: addstar halted\n");
+  exit (1);
+}
+
+void TrapSignal (int sig) {
+    fprintf (stderr, "trapped signal %d, exiting gracefully\n", sig);
+    if (sig == 11) {
+      fprintf (stderr, "seg fault\n");
+      exit (1);
+    }
+    if (Protect) {
+      Trapped = TRUE;
+      fprintf (stderr, "blocking until protected sections are clear\n");
+      return;
+    }
+    Shutdown ();
+}    
+
+main (int argc, char **argv) {
+
+  int i, N, mode, dbstate;
+  int Nstars, Nimage, Nregions, Nmissed;
+  Stars *stars, *gstars();
+  Image image, *pimage, *gimages();
+  GSCRegion *region, *gregions();
+  Catalog catalog;
+  struct timeval now, then;  
+  
+  SetSignals ();
+  args (argc, argv);
+
+  /* load the input datafile */
+  stars = gstars (argv[1], &Nstars, &image);
+  if (Nstars == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars in data file, skipping\n");
+    fprintf (stderr, "SUCCESS\n");
+    exit (0);
+  }
+
+  /* lock the image catalog */
+  check_permissions (ImageCat);
+  f = fsetlockfile (ImageCat, 3600.0, LCK_HARD, &dbstate);
+  if ((f == (FILE *) NULL) && (dbstate != LCK_EMPTY)) {
+    fprintf (stderr, "ERROR: can't lock image catalog\n");
+    exit (1);
+  }
+  fseek (f, 0, SEEK_SET);
+
+  /* load images */
+  if (dbstate == LCK_EMPTY) {
+    Nimage = 0;
+  } else {
+    pimage = gimages (f, &image, &Nimage);
+  }
+  region = gregions (&image, &Nregions);
+  fprintf (stderr, "region %f %f %f %f\n", region[0].RA[0], region[0].RA[1], region[0].DEC[0], region[0].DEC[1]);
+
+  for (i = 0; i < Nregions; i++) {
+    check_permissions (region[i].filename);
+  }
+
+  if (CALIBRATE) { InitCalibration (); }
+
+  for (i = 0; i < Nregions; i++) {
+    catalog.filename = region[i].filename;  /* don't free region before catalog! */
+    fprintf (stderr, "adding to %s\n", region[i].filename);
+    
+    switch (lock_catalog (&catalog, LCK_XCLD)) {
+    case 0:
+      /* this is a serious error because ImageCat was NOT locked */
+      fprintf (stderr, "ERROR: can't lock file %s\n", catalog.filename);
+      exit (1);
+    case 1:
+      gcatalog (&catalog); /* load from disk */
+      break;
+    case 2:
+      mkcatalog (&region[i], &catalog); /* fills in new header info */
+      break;
+    }
+    find_matches (&region[i], stars, Nstars, &catalog, &image, pimage, Nimage);
+
+    /* protect wcatalog from interrupt signals */
+    Protect = TRUE;
+    if (!DUMP_MATCHES && !ONLY_IMAGES) wcatalog (&catalog);
+    if (Trapped) Shutdown ();
+    Protect = FALSE;
+    unlock_catalog (&catalog);
+  }
+
+  if (CALIBRATE) { FindCalibration (&image); }
+  if (DUMP_MATCHES) Shutdown ();
+
+  for (Nmissed = i = 0; i < Nstars; i++) {
+    if (stars[i].found == -1) {
+      fprintf (stderr, "%d %f %f %f %f\n", i, stars[i].R, stars[i].D, stars[i].M, stars[i].dM);
+      Nmissed ++;
+    }
+  }
+  if (Nmissed) fprintf (stderr, "WARNING: %d stars in image were missed!\n", Nmissed);
+
+  /* protect wimage from interrupt signals */
+  Protect = TRUE;
+  wimage (f, dbstate, &image, Nstars); 
+  if (Trapped) Shutdown ();
+  Protect = FALSE;
+
+  fclearlockfile (ImageCat, f, LCK_HARD, &dbstate);
+
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  chmod (ImageCat, mode);
+
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+
+}
+
+int SetSignals () {
+
+  int i;
+
+  /* disable almost all signal interrupts */
+  for (i = 0; i < 36; i++) {
+    switch (i) {
+      /* can't redirect this signals */
+    case SIGKILL:    /* kill -9: cannot be caught or ignored */
+    case SIGSTOP:    /* SIGSTOP: cannot be caught or ignored */
+      /* ignore these signals */
+    case SIGCHLD:    /* child halted: ignore */
+    case SIGPWR:     /* power failure - why ignore this? */
+    case SIGWINCH:   /* window resized */
+    case SIGCONT:    /* continue - maintain this action */
+    case SIGTSTP:    /* stop signal sent from tty - why ignore? */
+    case SIGURG:     /* socket signal, ignore this */
+      break;
+      
+    default:
+      signal (i, TrapSignal);
+    }
+  }
+
+}
+/*
+
+       Signal     Value     Action   Comment
+       -------------------------------------------------------------------------
+       SIGHUP        1        A      Hangup detected on controlling terminal
+                                     or death of controlling process
+       SIGINT        2        A      Interrupt from keyboard
+       SIGQUIT       3        A      Quit from keyboard
+       SIGILL        4        A      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
+
+       Next various other signals.
+
+       Signal       Value     Action   Comment
+       ---------------------------------------------------------------------
+       SIGTRAP        5         CG     Trace/breakpoint trap
+       SIGIOT         6         CG     IOT trap. A synonym for SIGABRT
+       SIGEMT       7,-,7       G
+       SIGBUS      10,7,10      AG     Bus error
+       SIGSYS      12,-,12      G      Bad argument to routine (SVID)
+       SIGSTKFLT    -,16,-      AG     Stack fault on coprocessor
+       SIGURG      16,23,21     BG     Urgent condition on socket (4.2 BSD)
+       SIGIO       23,29,22     AG     I/O now possible (4.2 BSD)
+       SIGPOLL                  AG     A synonym for SIGIO (System V)
+       SIGCLD       -,-,18      G      A synonym for SIGCHLD
+       SIGXCPU     24,24,30     AG     CPU time limit exceeded (4.2 BSD)
+       SIGXFSZ     25,25,31     AG     File size limit exceeded (4.2 BSD)
+       SIGVTALRM   26,26,28     AG     Virtual alarm clock (4.2 BSD)
+       SIGPROF     27,27,29     AG     Profile alarm clock
+       SIGPWR      29,30,19     AG     Power failure (System V)
+       SIGINFO      29,-,-      G      A synonym for SIGPWR
+       SIGLOST      -,-,-       AG     File lock lost
+       SIGWINCH    28,28,20     BG     Window resize signal (4.3 BSD, Sun)
+       SIGUNUSED    -,31,-      AG     Unused signal
+       (Here - denotes that a signal is absent; there where three values are given, the first one is usually  valid  for  alpha  and
+       sparc,  the  middle  one  for i386 and ppc, the last one for mips. Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a
+       sparc.)
+
+       The letters in the "Action" column have the following meanings:
+
+       A      Default action is to terminate the process.
+
+       B      Default action is to ignore the signal.
+
+       C      Default action is to dump core.
+
+       D      Default action is to stop the process.
+
+       E      Signal cannot be caught.
+
+       F      Signal cannot be ignored.
+
+       G      Not a POSIX.1 conformant signal.
+
+*/
Index: /trunk/Ohana/src/getstar/src/aregion.c
===================================================================
--- /trunk/Ohana/src/getstar/src/aregion.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/aregion.c	(revision 2490)
@@ -0,0 +1,180 @@
+# include "getstar.h"
+
+double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+			 52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+			 0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+			 -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+		       "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+		       "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+		       "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			"n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			"s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			"s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		"disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		"disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+                   0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+# define DEBUG 1
+
+/* find region file which contains ra, dec */
+aregion (region, f, ra, dec) 
+GSCRegion region[];
+FILE *f;
+double ra, dec;
+{
+  
+  
+  char buffer[28800], temp[50], file[256];
+  double dr, dd;
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done, nregion;
+  
+  while (ra < 0) { ra += 360.0; }
+  while (ra >= 360.0) { ra -= 360.0; }
+
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt\0", CATDIR);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] =  0.0;
+    region[0].RA[1] =  360.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    exit (1);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt\0", CATDIR, Dec2Sections[NBigDec], &temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
+
+
+/**********/
+int hms_to_deg (h0, h1, d0, d1, string) 
+     char *string;
+     double *h0, *h1, *d0, *d1;
+{
+  
+  int flag_d0, flag_d1, flag_h0, flag_h1;
+  double tmp;
+  
+  *d0 = *h0 = *d1 = *h1 = 0;
+
+  flag_h0 = dparse (h0, 1, string);
+  flag_h1 = dparse (h1, 4, string);
+  flag_d0 = dparse (d0, 7, string);
+  flag_d1 = dparse (d1, 9, string);
+  *h0 *= flag_h0;
+  *h1 *= flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  dparse (&tmp, 2, string);
+  *h0 += tmp/60.0;
+  dparse (&tmp, 3, string);
+  *h0 += tmp/3600.0;
+  
+  dparse (&tmp, 5, string);
+  *h1 += tmp/60.0;
+  dparse (&tmp, 6, string);
+  *h1 += tmp/3600.0;
+  
+  dparse (&tmp, 8, string);
+  *d0 += tmp/60.0;
+
+  dparse (&tmp, 10, string);
+  *d1 += tmp/60.0;
+
+  *h0 *= 15*flag_h0;
+  *h1 *= 15*flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  return (TRUE);
+}
+
+
+/*
+      if (buffer[i*48 + 19] == ' ') continue;
+      strncpy (temp, &buffer[i*48 + 19], 20);       temp[20] = 0;
+      hms_to_deg (&RA,  &DEC, temp, ' ', 3);
+
+
+  dBigRA = 360.0 / (int)(0.5 + 48*cos(3.1415927*0.5*(BigDecBounds[NBigDec] + BigDecBounds[NBigDec + 1])/180.0));
+
+  NBigRA = ra / dBigRA;
+
+  NBig = NBigRA;
+  for (i = 0; (i < 12) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+  for (i = 13; (i < 24) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+
+
+  fprintf (stderr, "%d %d %d %d %f %f -> %f %f %f\n", NBigDec, NBigRA, NBigRASections[NBigDec], NBig, ra, dec, BigDecBounds[NBigDec], BigDecBounds[NBigDec + 1], dBigRA);
+*/
Index: /trunk/Ohana/src/getstar/src/args.c
===================================================================
--- /trunk/Ohana/src/getstar/src/args.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/args.c	(revision 2490)
@@ -0,0 +1,31 @@
+# include "getstar.h"
+
+void help () {
+  fprintf (stderr, "USAGE: getstar (file) (output)\n");
+  exit (2);
+}
+
+int args (int argc, char **argv) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /* configuration info */
+  ConfigInit (&argc, argv);
+
+  /* check for command line options */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) help ();
+
+}
+
Index: /trunk/Ohana/src/getstar/src/calibrate.c
===================================================================
--- /trunk/Ohana/src/getstar/src/calibrate.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/calibrate.c	(revision 2490)
@@ -0,0 +1,143 @@
+# include "addstar.h"
+
+static int Ncal, NCAL;
+static float *Mobs, *dMobs, *Mref, *Cref, *Airm;
+static float *RA, *DEC, *X, *Y;
+int *Nstar;
+
+InitCalibration () {
+
+    fprintf (stderr, "calibrating the image...  %d\n", CalReference);
+    Ncal = 0;
+    NCAL = 1000;
+    ALLOCATE (Mobs,  float,  NCAL);
+    ALLOCATE (dMobs, float, NCAL);
+    ALLOCATE (Mref,  float,  NCAL);
+    ALLOCATE (Cref,  float,  NCAL);
+    ALLOCATE (Airm,  float,  NCAL);
+    ALLOCATE (Nstar, int, NCAL);
+    ALLOCATE (RA, float, NCAL);
+    ALLOCATE (DEC, float, NCAL);
+    ALLOCATE (X, float, NCAL);
+    ALLOCATE (Y, float, NCAL);
+}
+  
+SaveCalibration (float M, float dM, float Mr, float Mc, float A, int N, float ra, float dec, float x, float y) {
+
+  Mobs[Ncal] = M;
+  dMobs[Ncal] = dM;
+  Mref[Ncal] = Mr;
+  Cref[Ncal] = Mc;
+  Airm[Ncal] = A;
+  Nstar[Ncal] = N;
+
+  RA[Ncal] = ra;
+  DEC[Ncal] = dec;
+  X[Ncal] = x;
+  Y[Ncal] = y;
+  Ncal ++;
+
+  if (Ncal == NCAL) {
+    NCAL += 1000;
+    REALLOCATE (dMobs, float, NCAL);
+    REALLOCATE (Mobs,  float, NCAL);
+    REALLOCATE (Mref,  float, NCAL);
+    REALLOCATE (Cref,  float, NCAL);
+    REALLOCATE (Airm,  float, NCAL);
+    REALLOCATE (Nstar, int,   NCAL);
+    REALLOCATE (RA, float, NCAL);
+    REALLOCATE (DEC, float, NCAL);
+    REALLOCATE (X, float, NCAL);
+    REALLOCATE (Y, float, NCAL);
+  }
+}
+
+FindCalibration (Image *image) {
+
+  int i, MaxN, *Nlist, Nkeep;
+  float N, M1, M2, Klam, Clam, Xlam, Mabs, dM, dm, *Dmag;
+  float dAs, dMs, dYs;
+  
+  /* reject multiple matched-stars */
+  /* find maximum value of Nstar[] */
+  MaxN = -1;
+  for (i = 0; i < Ncal; i++) {
+    MaxN = MAX (Nstar[i], MaxN);
+  }
+  if (MaxN == -1) {
+    fprintf (stderr, "no clean stars\n");
+    image[0].Mcal = 10000;
+    image[0].dMcal = 10000;
+    return;
+  }
+  /* create a hash array from Nstar[] entries */
+  ALLOCATE (Nlist, int, MAX (1, MaxN + 1));
+  bzero (Nlist, MAX (0, MaxN*sizeof(int)));
+  for (i = 0; i < Ncal; i++) {
+    Nlist[Nstar[i]] ++;
+  }
+  
+  /* accumulate delta mags */
+  ALLOCATE (Dmag, float, Ncal);
+  Nkeep = 0;
+  Klam = thiscode[0].K;
+  Clam = thiscode[0].C;
+  Xlam = thiscode[0].X;
+  for (i = 0; i < Ncal; i++) {
+    /* if this entry has too many (or two few?) matches, skip it */
+    if (Nlist[Nstar[i]] != 1) continue;
+    Mabs = 0.001*(Mobs[i] + Klam*(Airm[i] - 1000) + Clam + Xlam*(Mref[i] - Cref[i])) - ZeroPt;
+
+    /* subpix correction : make parameters global! */
+    dAs = 0;
+    if (Y[i] < 400) dAs = 0.06 - 0.00015*Y[i];
+    dYs = Y[i] - (int) (Y[i]) + 0.55;
+    dMs = dAs * sin (6.28*dYs);
+    /* Mabs -= dMs; */
+
+    if (DUMP_MATCHES) 
+      fprintf (stdout, "%d  %6.3f %6.3f %6.3f  %10.6f %10.6f  %7.2f %7.2f\n", 
+	       i, Mabs, 0.001*Mref[i], 0.001*Cref[i], RA[i], DEC[i], X[i], Y[i]);
+
+    /* skip stars brighter than 8.0 */
+    /* if (Mabs < 8.0) continue; */
+    
+    Dmag[Nkeep] = (Mabs - 0.001*Mref[i]);
+    Nkeep ++;
+  }
+
+  if (Nkeep < 3) {
+    fprintf (stderr, "too few stars\n");
+    image[0].Mcal = 10000;
+    image[0].dMcal = 10000;
+    return;
+  }
+  fsort (Dmag, Nkeep);
+
+  /* accumulate delta mags (25% - 75% of list) */
+  M1 = 0.0;
+  M2 = 0.0;
+  N  = 0.0;
+  for (i = 0.25*Nkeep; i <= 0.75*Nkeep; i++) {
+
+    /* a straight mean works better, given the bad photometry of skyprobe */
+    M1 += Dmag[i];
+    M2 += SQ (Dmag[i]);
+    N  += 1.0; 
+
+  }
+
+  if (N > 1) {
+    M1 = M1 / N;
+    M2 = sqrt (fabs(M2/N - M1*M1));
+    fprintf (stderr, "N: %.0f, mean: %f, stdev: %f, precision: %f\n", N, M1, M2, M2 / sqrt (N));
+    image[0].Mcal = 1000 * M1;
+    image[0].dMcal = 1000 * M2 / sqrt (N);
+  } else {
+    fprintf (stderr, "too few stars\n");
+    image[0].Mcal = 10000;
+    image[0].dMcal = 10000;
+  }
+}
+
+
Index: /trunk/Ohana/src/getstar/src/check_permissions.c
===================================================================
--- /trunk/Ohana/src/getstar/src/check_permissions.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/check_permissions.c	(revision 2490)
@@ -0,0 +1,91 @@
+# include "addstar.h"
+
+check_permissions (char *basefile) {
+  
+  FILE *f;
+  char *c, dir[256], filename[256];
+  struct stat filestat;
+  uid_t fuid, uid;
+  gid_t fgid, gid;
+  int status, cmode;
+
+  uid = getuid();
+  gid = getgid();
+
+  /* check permission to write to directory */
+  sprintf (filename, "%s\0", basefile);
+  c = strrchr (filename, '/');
+  if (c == (char *) NULL) {
+    strcpy (dir, ".");
+  } else {
+    *c = 0;
+    strcpy (dir, filename);
+  }
+  status = stat (dir, &filestat);
+  if (status == -1) {
+    fprintf (stderr, "directory %s does not exist, creating...\n", dir);
+    cmode = S_IRWXU | S_IRWXG | S_IRWXO;
+    status = mkdir (dir, cmode);
+    if (status == -1) {
+      fprintf (stderr, "ERROR: can't create %s\n", dir);
+      exit (1);
+    }
+  } 
+  status = stat (dir, &filestat);
+  if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRWXU)) ||
+      ((gid == filestat.st_gid) && (filestat.st_mode & S_IRWXG)) || 
+      (filestat.st_mode & S_IRWXO)) {
+  } else {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (1);
+  }
+  
+  /* check permission to write to file */
+  sprintf (filename, "%s\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (1);
+    }
+  }
+  
+  /* check permission to write to backup file */
+  sprintf (filename, "%s~\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (1);
+    }
+  }
+  
+}
+
+/* uses cp only */
+make_backup (char *filename) {
+
+  int status, cmode;
+  struct stat filestat;
+  char line [256];
+
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, make backup copy */
+    sprintf (line, "cp %s %s~\0", filename, filename);
+    status = system (line);
+    if (status) {
+      fprintf (stderr, "ERROR: unable to create %s~, exiting\n", filename);
+      exit (1);
+    }
+    cmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    sprintf (line, "%s~\0", filename);
+    chmod (line, cmode);
+  }
+  
+}
Index: /trunk/Ohana/src/getstar/src/clean_stars.c
===================================================================
--- /trunk/Ohana/src/getstar/src/clean_stars.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/clean_stars.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "getstar.h"
+
+int clean_stars (Stars *stars, int *nstars, Image *image) {
+
+  int i, j, Nsubset, *subset, *skip, *found, Nstars, check, Nskip;
+  double Xo, Yo, Xt, Yt, radius;
+  double Mo, Mt, dM;
+
+  Nstars = *nstars;
+  ALLOCATE (found,  int, Nstars);
+  ALLOCATE (subset, int, Nstars);
+  ALLOCATE (skip,   int, Nstars);
+  bzero (skip, Nstars*sizeof(int));
+
+  Nskip = 0;
+  Nsubset = 0;
+  for (i = 0; i < Nstars; i++) {
+    RD_to_XY (&stars[i].X, &stars[i].Y, stars[i].R, stars[i].D, &image[0].coords);
+    check = (stars[i].found & BLEND_IMAGE) || (stars[i].found & BLEND_IMAGE_NEIGHBOR) || (stars[i].found & BLEND_CATALOG);
+    if (check) {
+      subset[Nsubset] = i;
+      found[Nsubset] = FALSE;
+      Nsubset ++;
+    }
+  }
+
+  if (Nsubset > 1) {
+    for (i = 0; i < Nsubset; i++) {
+      if (found[i]) continue;
+      Xo = stars[subset[i]].X;
+      Yo = stars[subset[i]].Y;
+      Mo = stars[subset[i]].M;
+      for (j = 0; j < Nsubset; j++) {
+	if (j == i) continue;
+	if (found[j]) continue;
+	Xt = stars[subset[j]].X;
+	Yt = stars[subset[j]].Y;
+	Mt = stars[subset[j]].M;
+	radius = hypot ((Xo-Xt), (Yo-Yt));
+	dM = fabs (Mo-Mt);
+	if ((radius < 5.0) && (dM < 0.005)) {
+	  skip[subset[j]] = TRUE;
+	  found[j] = TRUE;
+	  Nskip ++;
+	}
+      }
+      found[i] = TRUE;
+    }
+ 
+    for (i = j = 0; i < Nstars; i++) {
+      if (skip[i]) continue;
+      if (i == j) { 
+	j++;
+	continue;
+      }
+      stars[j] = stars[i];
+      j++;
+    }
+    *nstars = j;
+  }
+  fprintf (stderr, "%d skipped\n", Nskip);
+}
+
Index: /trunk/Ohana/src/getstar/src/coordops.c
===================================================================
--- /trunk/Ohana/src/getstar/src/coordops.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/coordops.c	(revision 2490)
@@ -0,0 +1,342 @@
+# include "addstar.h"
+
+XY_to_RD (ra, dec, x, y, coords)
+double *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+# if 1
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+# else
+  {
+# endif
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN")) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+fXY_to_RD (ra, dec, x, y, coords)
+float *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+RD_to_XY (x, y, ra, dec, coords)
+double *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    /* fprintf (stderr, "approximate to polynomial TAN plane fit\n");  */
+  }
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+fRD_to_XY (x, y, ra, dec, coords)
+float *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+
+GetCoords (coords, header) 
+Coords coords[];
+Header header[];
+{
+
+  int status;
+  double rotate;
+
+  rotate = 0.0;
+  coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+  coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+  coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+  coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+  strcpy (coords[0].ctype, "NONE");
+
+  status = TRUE; 
+  if (fits_scan (header, "CTYPE2", "%s", 1, coords[0].ctype)) {
+    status  = fits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+    status &= fits_scan (header, "CRPIX1", "%lf", 1, &coords[0].crpix1);
+    status &= fits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+    status &= fits_scan (header, "CRPIX2", "%lf", 1, &coords[0].crpix2);
+    if (fits_scan (header, "CDELT1", "%lf", 1, &coords[0].cdelt1)) {
+      status &= fits_scan (header, "CDELT2", "%lf", 1, &coords[0].cdelt2);
+      if (fits_scan (header, "CROTA2", "%lf", 1, &rotate)) {
+	coords[0].pc1_1 =  cos(rotate*RAD_DEG);
+	coords[0].pc1_2 = -sin(rotate*RAD_DEG);
+	coords[0].pc2_1 =  sin(rotate*RAD_DEG);
+	coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+      }
+      if (fits_scan (header, "PC001001", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "PC001002", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "PC002001", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "PC002002", "%lf", 1, &coords[0].pc2_2);
+      }
+    }
+    else {
+      if (fits_scan (header, "CD1_1", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "CD1_2", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "CD2_1", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "CD2_2", "%lf", 1, &coords[0].pc2_2);
+	coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      }
+      else {
+	status = FALSE;
+      }
+    }
+  }
+  else {
+    if (fits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1)) {
+      status  = fits_scan (header, "RA_X", "%lf", 1, &coords[0].pc1_1);
+      status &= fits_scan (header, "RA_Y", "%lf", 1, &coords[0].pc1_2);
+      status &= fits_scan (header, "DEC_O", "%lf", 1, &coords[0].crval2);  
+      status &= fits_scan (header, "DEC_X", "%lf", 1, &coords[0].pc2_1);
+      status &= fits_scan (header, "DEC_Y", "%lf", 1, &coords[0].pc2_2);
+      coords[0].crpix1 = coords[0].crpix2 = 0.0;
+      coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      strcpy (coords[0].ctype, "GENE");
+    }
+  }
+  if (!status) {
+    fprintf (stderr, "error getting all elements for coordinate mode %d\n", coords[0].ctype);
+    coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+    coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+    coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+    coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+    strcpy (coords[0].ctype, "NONE");
+  }
+}
+
+
+  /* -PLY projection is an extrapolation of the -TAN projection. 
+     In addition to the usual linear terms of CRPIXi, PC00i00j, there are 
+     higher order polynomial terms (up to 3rd order):
+     Axis 1 terms:
+     PCA1X2Y0 = coords.polyterm[0][0] = x^2                                             
+     PCA1X1Y1 = coords.polyterm[1][0] = xy                                          
+     PCA1X0Y2 = coords.polyterm[2][0] = y^2                                             
+     PCA1X3Y0 = coords.polyterm[3][0] = x^3                                             
+     PCA1X2Y1 = coords.polyterm[4][0] = x^2 y                                             
+     PCA1X1Y2 = coords.polyterm[5][0] = x y^2                                             
+     PCA1X0Y3 = coords.polyterm[6][0] = y^2                                              
+     Axis 2 terms:
+     PCA2X2Y0 = coords.polyterm[0][1] = x^2                                               
+     PCA2X1Y1 = coords.polyterm[1][1] = xy                                                
+     PCA2X0Y2 = coords.polyterm[2][1] = y^2                                               
+     PCA2X3Y0 = coords.polyterm[3][1] = x^3                                               
+     PCA2X2Y1 = coords.polyterm[4][1] = x^2 y                                             
+     PCA2X1Y2 = coords.polyterm[5][1] = x y^2                                             
+     PCA2X0Y3 = coords.polyterm[6][1] = y^2                                               
+  */
Index: /trunk/Ohana/src/getstar/src/find_matches.c
===================================================================
--- /trunk/Ohana/src/getstar/src/find_matches.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/find_matches.c	(revision 2490)
@@ -0,0 +1,57 @@
+# include "getstar.h"
+
+Stars *find_matches (Catalog *catalog, Image *image, int start, int end, Stars *stars, int *Nstar) {
+
+  int i, n, N, NSTARS;
+  int photcode;
+
+  if (stars == (Stars *) NULL) {
+    N = 0;
+    NSTARS = 1000;
+    ALLOCATE (stars, Stars, NSTARS);
+  } else {
+    N = *Nstar;
+    NSTARS = N + 1000;
+    REALLOCATE (stars, Stars, NSTARS);
+  }    
+
+  /* identify selection criteria */
+  photcode = -1;
+  if ((start == 0) && (end == 0)) {
+    start = image[0].tzero;
+    end   = image[0].tzero + 1e-4*image[0].NY*image[0].trate;  /* trate is in 0.1 msec / row */
+    photcode = image[0].source;
+  }
+  if (VERBOSE) fprintf (stderr, "extracting for range %d to %d (photcode %s)\n", start, end, photcode);
+
+  for (i = 0; (i < catalog[0].Nmeasure); i++) {
+    if ((i % 10000) == 0) fprintf (stderr, ". ");
+    if ((catalog[0].measure[i].t >= start) && (catalog[0].measure[i].t <= end) && (photcode == catalog[0].measure[i].source)) { 
+      n = catalog[0].measure[i].averef;
+      stars[N].R      = catalog[0].average[n].R - catalog[0].measure[i].dR / 360000.0;
+      stars[N].D      = catalog[0].average[n].D - catalog[0].measure[i].dD / 360000.0;
+
+      stars[N].M      = 0.001*(catalog[0].measure[i].M - catalog[0].measure[i].dt);
+      stars[N].dM     = catalog[0].measure[i].dM;
+      stars[N].dophot = catalog[0].measure[i].dophot;  
+
+      stars[N].Mgal   = 0.001*(catalog[0].measure[i].Mgal - catalog[0].measure[i].dt);
+
+      stars[N].fx     = 0.01*catalog[0].measure[i].FWx;
+      stars[N].fy     = stars[N].fx * 0.01*catalog[0].measure[i].fwy;
+      stars[N].df     = (360.0/255.0)*catalog[0].measure[i].theta;
+      stars[N].found  = catalog[0].measure[i].flags;
+
+      N ++;
+      if (N == NSTARS) {
+	NSTARS += 1000;
+	REALLOCATE (stars, Stars, NSTARS);
+      }    
+
+    } 
+  }
+  fprintf (stderr, "found %d meas\n", N);
+  *Nstar = N;
+  return (stars);
+}
+
Index: /trunk/Ohana/src/getstar/src/gcatalog.c
===================================================================
--- /trunk/Ohana/src/getstar/src/gcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/gcatalog.c	(revision 2490)
@@ -0,0 +1,45 @@
+# include "getstar.h"
+
+int gcatalog (Catalog *catalog) {
+  
+  int Nsecfilt;
+  char mode;
+
+  /* read catalog header */
+  mode = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+  if (!load_catalog (catalog, mode, VERBOSE)) {
+    fprintf (stderr, "ERROR: failure loading catalog\n");
+    exit (1);
+  }
+
+  /* check Nsecfile value, update if needed */
+  Nsecfilt = GetPhotcodeNsecfilt ();
+  if (catalog[0].Nsecfilt < Nsecfilt) {
+
+    int i, j, Nextra, in, out;
+    SecFilt *insec, *outsec;
+
+    Nextra = Nsecfilt - catalog[0].Nsecfilt;
+    insec = catalog[0].secfilt;
+    ALLOCATE (outsec, SecFilt, catalog[0].Naverage * Nsecfilt);
+    for (in = out = i = 0; i < catalog[0].Naverage; i++) {
+      for (j = 0; j < catalog[0].Nsecfilt; j++, in++, out++) {
+	outsec[out].M = insec[in].M;
+	outsec[out].Xm = insec[in].Xm;
+      }
+      for (j = 0; j < Nextra; j++, out++) {
+	outsec[out].M = NO_MAG;
+	outsec[out].Xm = NO_MAG;
+      }
+    }
+    free (catalog[0].secfilt);
+    catalog[0].secfilt = outsec;
+    catalog[0].Nsecfilt = Nsecfilt;
+  }
+
+  if (catalog[0].Nsecfilt > Nsecfilt) {
+    fprintf (stderr, "ERROR: can't reduce number of secondary filters\n");
+    exit (1);
+  }
+  return (TRUE);
+}
Index: /trunk/Ohana/src/getstar/src/getstar.c
===================================================================
--- /trunk/Ohana/src/getstar/src/getstar.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/getstar.c	(revision 2490)
@@ -0,0 +1,49 @@
+# include "getstar.h"
+
+main (int argc, char **argv) {
+
+  int i, Nstars, Nregions;
+  Image *image, *gimages(), *gtimes(), *find_images();
+  Catalog catalog;
+  GSCRegion *region, *tregion, *gregions();
+  Stars *stars;
+  
+  args (argc, argv);
+
+  image = gimages (argv[1]);
+
+  region = gregions (&image[0], &Nregions);
+
+  stars = (Stars *) NULL;
+  Nstars = 0;
+
+  for (i = 0; i < Nregions; i++) {
+    if (VERBOSE) fprintf (stderr, "extracting from %s\n", region[i].filename);
+    catalog.filename = region[i].filename;  /* don't free region before catalog! */
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 0:
+      fprintf (stderr, "ERROR: can't lock file\n");
+      exit (1);
+    case 1:
+      gcatalog (&catalog);
+      break;
+    case 2:
+      fprintf (stderr, "no data in %s, skipping\n", catalog.filename);
+      catalog.Naverage = 0;
+      catalog.Nmeasure = 0;
+      break;
+    default:
+      fprintf (stderr, "weird lock_catalog exit state\n");
+      exit (1);
+    }
+    unlock_catalog (&catalog);
+    stars = find_matches (&catalog, &image[0], 0, 0, stars, &Nstars);
+  }
+
+  /* write out the selected stars */
+  clean_stars (stars, &Nstars, image);
+  wstars (argv[2], stars, Nstars, image);
+  fprintf (stderr, "SUCCESS\n");
+  exit (0);
+
+}
Index: /trunk/Ohana/src/getstar/src/gimages.c
===================================================================
--- /trunk/Ohana/src/getstar/src/gimages.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/gimages.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "getstar.h"
+
+Image *gimages (char *filename) {
+  
+  int i, size, Nimage, nimage;
+  double zeropt;
+  struct stat filestatus;
+  FILE *f;
+  Image *timage, *image;
+  Header header;
+  
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "error opening image cat %s\n", ImageCat);
+    exit (1);
+  }
+
+  /* read header */
+  if (!fits_load_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "ERROR: can't read image catalog %s\n", ImageCat);
+    exit (1);
+  }
+
+  fits_scan (&header, "ZERO_PT", "%lf", 1, &zeropt);
+  if (fabs (ZeroPt - zeropt) > 1e-4) {
+    fprintf (stderr, "ERROR: zero point in image table (%f:%s) inconsistent with zero point in image header (%f:%s)\n",
+	     zeropt, ImageCat, ZeroPt, filename);
+    exit (1);
+  }
+
+  /* advance to data segment */ 
+  fseek (f, header.size, SEEK_SET); 
+
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  /* check that file size makes sense */
+  if (stat (ImageCat, &filestatus) == -1) {
+    fprintf (stderr, "ERROR: failed to get status of image catalog\n");
+    exit (1);
+  }
+  size = Nimage*sizeof(Image) + header.size;
+  if (size != filestatus.st_size) {
+    fprintf (stderr, "ERROR: image catalog has inconsistent size\n");
+    exit (1);
+  } 
+
+  ALLOCATE (timage, Image, Nimage);
+  nimage = Fread (timage, sizeof(Image), Nimage, f, "image");
+  if (nimage != Nimage) {
+    fprintf (stderr, "error reading images from table\n");
+    exit (1);
+  }
+
+  ALLOCATE (image, Image, 1);
+  for (i = 0; i < Nimage; i++) {
+    if (strcmp (timage[i].name, filename)) continue;
+    memcpy (image, &timage[i], sizeof(Image));
+    return (image);
+  }
+
+  fprintf (stderr, "error: failed to find desired image\n");
+  exit (1);
+}
Index: /trunk/Ohana/src/getstar/src/gregions.c
===================================================================
--- /trunk/Ohana/src/getstar/src/gregions.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/gregions.c	(revision 2490)
@@ -0,0 +1,56 @@
+# include "getstar.h"
+
+GSCRegion *gregions (image, Nregions)
+Image *image;
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dr, dd, dec, ra;
+  int i, j, done, nregion, NREGION;
+  
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", GSCFILE);
+    exit (1);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "found %d region files:\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "  %d %s\n", i, region[i].filename);
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /trunk/Ohana/src/getstar/src/gstars.c
===================================================================
--- /trunk/Ohana/src/getstar/src/gstars.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/gstars.c	(revision 2490)
@@ -0,0 +1,276 @@
+# include "addstar.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 66
+# define BLOCK 1000
+#include <sys/time.h>
+#include <time.h>
+
+Stars *gstars (file, NSTARS, image) 
+char file[];
+int *NSTARS;
+Image *image;
+{
+
+  FILE *f;
+  Header header;
+  int j, N, Ninstar;
+  int nbytes, Nbytes;
+  Stars *stars;
+  char *buffer, *c, *c2, photcode[64];
+  double tmp;
+  int done, doneread, Nskip, Nextra, itmp;
+  unsigned short int Nc;
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", file);
+    exit (1);
+  }
+
+  /* open file */
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", file);
+    exit (1);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* find image rootname */
+  c = strrchr (file, 0x2f);
+  if (c == (char *) NULL) {
+    strcpy (image[0].name, file);
+  } else { 
+    strcpy (image[0].name, (c+1));
+  }
+
+  /* get astrometry information */
+  if (!GetCoords (&image[0].coords, &header)) {
+    fprintf (stderr, "ERROR: no astrometric solution in header\n");
+    exit (1);
+  }
+  while (image[0].coords.crval1 < 0) image[0].coords.crval1 += 360.0;
+  while (image[0].coords.crval1 > 360.0) image[0].coords.crval1 -= 360.0;
+  itmp = 0;
+  fits_scan (&header, "NASTRO",   "%d", 1, &itmp);
+  if ((itmp == 0) && !ACCEPT_ASTROM) {
+    fprintf (stderr, "ERROR: bad astrometric solution in header\n");
+    exit (1);
+  }
+    
+  /* CERROR in data file is in arcsec */
+  if (!fits_scan (&header, "CERROR",   "%lf", 1, &tmp)) tmp = 1.0;
+  image[0].cerror = tmp * 50.0;
+  fits_scan (&header, "NAXIS1",   "%hd", 1, &image[0].NX); 
+  fits_scan (&header, "NAXIS2",   "%hd", 1, &image[0].NY);
+ 
+  /* get photcode from header */
+  if (thiscode == NULL) {
+    fits_scan (&header, "PHOTCODE", "%s", 1, photcode);
+    thiscode = GetPhotcodebyName (photcode);
+  }
+  if (thiscode == NULL) {
+    fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", photcode);
+    exit (1);
+  }
+  image[0].source = thiscode[0].code;
+
+  image[0].NX -= XOVERSCAN;
+  image[0].NY -= YOVERSCAN;
+  fits_scan (&header, ExptimeKeyword,  "%lf", 1, &tmp);
+  image[0].exptime = tmp;
+  
+  tmp = 0;
+  /* fits_scan (&header, "APMIFIT",  "%lf", 1, &tmp); */
+  image[0].apmifit = tmp * 1000.0;
+
+  tmp = 0;
+  /* fits_scan (&header, "dAPMIFIT", "%lf", 1, &tmp); */
+  image[0].dapmifit = tmp * 1000.0;
+
+  tmp = 0;
+  fits_scan (&header, "FLIMIT",   "%lf", 1, &tmp);
+  image[0].detection_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FSATUR",   "%lf", 1, &tmp);
+  image[0].saturation_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FWHM_X",   "%lf", 1, &tmp);
+  image[0].fwhm_x = tmp * 25.0 * image[0].coords.cdelt1 * 3600.0;
+
+  tmp = 0;
+  fits_scan (&header, "FWHM_Y",   "%lf", 1, &tmp);
+  image[0].fwhm_y = tmp * 25.0 * image[0].coords.cdelt1 * 3600.0;
+
+  if (!fits_scan (&header, "TZERO",   "%d",  1, &image[0].tzero)) {
+    image[0].tzero = parse_time (&header);
+  }
+
+  tmp = 0;
+  fits_scan (&header, "TRATE",   "%lf", 1, &tmp);
+  image[0].trate = 10000 * tmp;
+
+  tmp = 0;
+  fits_scan (&header, AirmassKeyword, "%lf", 1, &tmp);
+  image[0].secz = MIN (NO_MAG, 1000*tmp);
+
+  if (!fits_scan (&header, CCDNumKeyword, "%d", 1, &itmp)) {
+    image[0].ccdnum = 0xff;
+  } else {
+    image[0].ccdnum = itmp;
+  }
+
+  fits_scan (&header, "ZERO_PT", "%lf", 1, &ZeroPt);
+
+  /* secz is in units milli-airmass */
+  image[0].Mcal = 0.0;
+  image[0].code = 0;
+  image[0].Xm   = NO_MAG;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+
+  /* find expected number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar);
+  if (image[0].nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    exit (1);
+  }
+  ALLOCATE (stars, Stars, image[0].nstar);
+
+  /* load in stars by blocks of 1000 */
+  N = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR) + 1);
+  buffer[BLOCK*BYTES_STAR] = 0;
+  Nextra = 0;
+  doneread = FALSE;
+  while (!doneread) {
+    Nbytes = BYTES_STAR * BLOCK - Nextra;
+    nbytes = Fread (&buffer[Nextra], 1, Nbytes, f, "char");
+    if (nbytes == 0) {
+      doneread = TRUE;
+      continue;
+    }
+    nbytes += Nextra;
+    /* check line-by-line integrity */
+    c = buffer;
+    done = FALSE;
+    while ((c < buffer + nbytes) && (!done)) { 
+      for (c2 = c; *c2 == '\n'; c2++);
+      if (c2 > c) { /* extra return chars */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+	if (VERBOSE) fprintf (stderr, "deleted %d extra return chars\n", Nskip);
+      }
+      c2 = strchr (c, '\n');
+      if (c2 == (char *) NULL) {
+	done = TRUE;	
+	continue;
+      }
+      c2++;
+      if ((c2 - c) != BYTES_STAR) { /* bad line, delete it */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+	if (VERBOSE) fprintf (stderr, "deleted line, %d extra chars\n", Nskip);
+      } else {
+	c = c2;
+      }
+    }
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (j = 0; j < Ninstar; j++, N++) {
+      dparse (&stars[N].X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].M,  3, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].dM, 4, &buffer[j*BYTES_STAR]);
+      /* allow for some dynamic filtering of star list */
+      if (stars[N].dM > 1000.0 / SNLIMIT) { N--; continue; }
+      if (XMAX && (stars[N].X > XMAX))    { N--; continue; }
+      if (XMIN && (stars[N].X < XMIN))    { N--; continue; }
+      if (YMAX && (stars[N].Y > YMAX))    { N--; continue; }
+      if (YMIN && (stars[N].Y < YMIN))    { N--; continue; }
+
+      dparse (&tmp,         5, &buffer[j*BYTES_STAR]);
+      stars[N].dophot = tmp;
+      dparse (&stars[N].Mgal, 7, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].Map,  8, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].fx,   9, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].fy,  10, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].df,  11, &buffer[j*BYTES_STAR]);
+
+      XY_to_RD (&stars[N].R, &stars[N].D, stars[N].X, stars[N].Y, &image[0].coords);
+      while (stars[N].R < 0.0) stars[N].R += 360.0;
+      while (stars[N].R >= 360.0) stars[N].R -= 360.0;
+      stars[N].found = -1;
+    }
+  }
+
+  image[0].nstar = N;
+  REALLOCATE (stars, Stars, image[0].nstar);
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+  *NSTARS = image[0].nstar;
+
+  return (stars);
+}
+
+
+
+
+# if (0)
+  /* left over fraction of a block */
+  nbytes = Fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f, "char");
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    exit (1);
+  }
+  /* check line-by-line integrity */
+  Nnew = 0;
+  c = buffer;
+  done = FALSE;
+  while ((c < buffer + nbytes) && (!done)) { 
+    for (c2 = c; *c2 == '\n'; c2++);
+    if (c2 > c) { /* extra return chars */
+      memmove (c, c2, (int)(buffer + nbytes - c2));
+      Nnew += c2 - c;
+      fprintf (stderr, "deleting %d extra return chars\n", (int)(c2-c));
+    }
+    c2 = strchr (c, '\n');
+    if (c2 == (char *) NULL) {
+      if (Nnew > 0) {
+	nnew = Fread (&buffer[nbytes-Nnew], 1, Nnew, f, "char");
+	if (nnew != Nnew) {
+	  fprintf (stderr, "ERROR: failed to read in stars (1)\n");
+	  exit (1);
+	}
+      } else {
+	done = TRUE;	
+      }
+      continue;
+    }
+    c2++;
+    if ((c2 - c) != BYTES_STAR) {
+      /* this is a bad line, delete it, adjust data in buffer, 
+	 and be ready to read the rest of the last line */
+      memmove (c, c2, (int)(buffer + nbytes - c2));
+      Nnew += c2 - c;
+      fprintf (stderr, "deleting bad line with %d chars\n", (int)(c2-c));
+    } else {
+      c = c2;
+    }
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstar++, N++) {
+    dparse (&stars[N].X, 1, &buffer[j*BYTES_STAR]);
+    dparse (&stars[N].Y, 2, &buffer[j*BYTES_STAR]);
+    dparse (&stars[N].M, 3, &buffer[j*BYTES_STAR]);
+    dparse (&stars[N].dM, 4, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&stars[N].R, &stars[N].D, stars[N].X, stars[N].Y, &image[0].coords);
+    while (stars[N].R < 0.0) stars[N].R += 360.0;
+    while (stars[N].R >= 360.0) stars[N].R -= 360.0;
+    dparse (&tmp, 5, &buffer[j*BYTES_STAR]);
+    stars[N].dophot = tmp;
+    stars[N].found = -1;
+  }
+
+# endif
Index: /trunk/Ohana/src/getstar/src/misc.c
===================================================================
--- /trunk/Ohana/src/getstar/src/misc.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/misc.c	(revision 2490)
@@ -0,0 +1,398 @@
+# include "getstar.h"
+
+/***** convert [-]00:00:00 to 0.0000 ****/
+int dms_to_ddd (double *Value, char *string) {
+  
+  int valid, neg, status;
+  double tmp, value;
+  char *p1, *p2, *px;
+
+  valid = FALSE; 
+  neg = FALSE;
+  stripwhite (string);
+  p1 = string;
+  px = string + strlen(string);
+
+  if (string[0] == '-') { 
+    valid = TRUE; 
+    neg = TRUE;
+    p1 = &string[1];
+  }
+  if (string[0] == '+') { 
+    valid = TRUE; 
+    neg = FALSE;
+    p1 = &string[1];
+  }
+  if (isdigit(string[0])) { 
+    valid = TRUE;
+    p1 = &string[0];
+  }
+  if (!valid) { return (FALSE); }
+
+  status = 1;
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) return (FALSE); /* entry not a number: +fred */
+  value = tmp;
+  if (p2 == px) goto escape;    /* entry only number: +1.0 */ 
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;    /* entry not a number: +1:fred */
+  status = 2;
+  value += tmp / 60.0;
+  if (p2 == px) goto escape;    /* entry only number: +1:1 */
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;    /* entry not a number: +1:1:fred */
+  value += tmp / 3600.0;
+
+ escape:
+  if (neg) {
+    value *= -1;
+  }
+  *Value = value;
+
+  return (status);
+}
+
+/**********/
+int str_to_radec (double *ra, double *dec, char *str1, char *str2) {
+
+  double Ra, Dec;
+
+  *ra = *dec = 0;
+  switch (dms_to_ddd (&Ra, str1)) {
+  case 0:
+    fprintf (stderr, "syntax error in RA\n");
+    return (FALSE);
+  case 1:
+    break;
+  case 2:
+    Ra = Ra * 15;
+    break;
+  }
+  switch (dms_to_ddd (&Dec, str2)) {
+  case 0:
+    fprintf (stderr, "syntax error in DEC\n");
+    return (FALSE);
+  case 1:
+  case 2:
+    break;
+  }
+  *ra = Ra;
+  *dec = Dec;
+  return (TRUE);
+}
+
+# define FORMAT_DAYS    1
+# define FORMAT_HOURS   2
+# define FORMAT_MINUTES 3
+# define FORMAT_SECONDS 4
+# define FORMAT_JD      5
+# define FORMAT_DATE    6
+
+/**********/
+int chk_time (char *line) {
+
+  char *p1, *p2;
+  double tmp;
+  int mode;
+
+  p1 = line;
+  tmp = strtod (p1, &p2);
+  if (p2 == p1 + strlen (p1) - 1) {
+    if (*p2 == 'd') {
+      mode = FORMAT_DAYS;
+    }
+    if (*p2 == 'h') {
+      mode = FORMAT_HOURS;
+    }
+    if (*p2 == 'm') {
+      mode = FORMAT_MINUTES;
+    }
+    if (*p2 == 's') {
+      mode = FORMAT_SECONDS;
+    }
+    if (*p2 == 'j') {
+      mode = FORMAT_JD;
+    }
+  } else { 
+    mode = FORMAT_DATE;
+  }
+  return (mode);
+}
+
+/**********/
+int str_to_time (char *line, unsigned int *second) {
+  
+  char *tmpline;
+  struct tm *gmt;
+  struct timeval now;
+  double jd;
+  unsigned long tsec;
+
+  if (!strcasecmp (line, "NOW")) {
+    gettimeofday (&now, (struct timezone *) NULL);
+    *second = now.tv_sec;
+    return (TRUE);
+  }
+    
+  if (!strncasecmp (line, "TODAY", 5)) {
+    gettimeofday (&now, (struct timezone *) NULL);
+    if (line[5]) { /* line has extra data (ie, hh:mm:ss) */
+      tsec = now.tv_sec;
+      ALLOCATE (tmpline, char, 64);
+      gmt   = gmtime (&tsec);
+      sprintf (tmpline, "%04d/%02d/%02d,%s", 
+	       1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, &line[6]);
+      *second = date_to_sec (tmpline);
+      free (tmpline);
+      return (TRUE);
+    } else {
+      *second = 86400 * ((int)(now.tv_sec / 86400));
+      return (TRUE); 
+    }
+  }
+    
+  switch (chk_time (line)) {
+  case 0:
+    return (FALSE);
+  case FORMAT_DAYS:
+    *second = strtod (line, 0) * 86400.0;
+    return (TRUE);
+  case FORMAT_HOURS:
+    *second = strtod (line, 0) * 3600.0;
+    return (TRUE);
+  case FORMAT_MINUTES:
+    *second = strtod (line, 0) * 60.0;
+    return (TRUE);
+  case FORMAT_SECONDS:
+    *second = strtod (line, 0);
+    return (TRUE);
+  case FORMAT_JD:
+    jd = strtod (line, 0);
+    *second = jd_to_sec (jd);
+    return (TRUE);
+  case FORMAT_DATE:
+    *second = date_to_sec (line);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+
+/**********/
+int str_to_dtime (char *line, double *second) {
+  
+  switch (chk_time (line)) {
+  case 0:
+  case FORMAT_JD:
+  case FORMAT_DATE:
+    return (FALSE);
+  case FORMAT_DAYS:
+    *second = strtod (line, 0) * 86400.0;
+    return (TRUE);
+  case FORMAT_HOURS:
+    *second = strtod (line, 0) * 3600.0;
+    return (TRUE);
+  case FORMAT_MINUTES:
+    *second = strtod (line, 0) * 60.0;
+    return (TRUE);
+  case FORMAT_SECONDS:
+    *second = strtod (line, 0);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+/**********/
+double sec_to_jd (unsigned long second) {
+
+  double jd;
+  
+  jd = second/86400.0 + 2440587.5;
+  return (jd);
+}
+
+/**********/
+unsigned long int jd_to_sec (double jd) {
+
+  unsigned long int second;
+
+  second = (jd - 2440587.5)*86400;
+  return (second);
+}
+
+/**********/
+char *sec_to_date (unsigned long second) {
+  
+  struct tm *gmt;
+  char *line;
+  
+  ALLOCATE (line, char, 64);
+  gmt   = gmtime (&second);
+  sprintf (line, "%04d/%02d/%02d,%02d:%02d:%02d", 
+	   1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, 
+	   gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  return (line);
+
+}
+
+/***** date in format yyyy/mm/dd,hh:mm:ss *****/
+unsigned long date_to_sec (char *date) {
+  
+  unsigned long second;
+  double tmp, jd;
+  struct tm now;
+  char *p1, *p2, *px;
+  
+  p1 = date;
+  px = date + strlen(date);
+  bzero (&now, sizeof(now));
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_year = tmp;
+  if (now.tm_year > 1000) now.tm_year -= 1900;
+  if (now.tm_year <   50) now.tm_year += 100;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_mon = tmp - 1; /* mon runs from 0 - 11 */
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_mday = tmp;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  p1 = p2 + 1;
+  now.tm_hour = tmp;
+  if (p2 == px) goto escape;  
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_min = tmp;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+  tmp = strtod (p1, &p2);
+  if (p2 == p1) goto escape;
+  now.tm_sec = tmp;
+  if (p2 == px) goto escape;  
+  p1 = p2 + 1;
+
+ escape:
+  jd = now.tm_mday - 32075 + (int)(1461*(1900 + now.tm_year + 4800 + (int)(((now.tm_mon+1)-14)/12))/4)
+    + (int)(367*((now.tm_mon+1) - 2 - (int)(((now.tm_mon+1) - 14)/12)*12)/12)
+    - (int)(3*(int)((1900 + now.tm_year + 4900 + (int)(((now.tm_mon+1) - 14)/12))/100)/4) - 0.5;
+  
+  second = (jd - 2440587.5)*86400 + 3600.0*now.tm_hour + now.tm_min*60.0 + now.tm_sec;
+
+  return (second);
+}
+
+
+
+/* times may be in forms as:
+   20040200450s (N seconds since 1970.0)
+   2440900.232j (julian date)
+   99/02/23,03:22:18 (date string)
+   (separators may be anything except space, +, -)
+   99:02:15:12:23:30
+   99:02:15:12h23m30s
+   */
+
+
+int GetTimeFormat (unsigned int *TimeReference, int *TimeFormat) {
+
+  char *p;
+
+  *TimeReference = 0;
+  if ((p = get_variable ("TIMEREF")) != (char *) NULL) {
+    if (!str_to_time (p, TimeReference)) {
+      fprintf (stderr, "error in TIME_REF format\n");
+      return (FALSE);
+    }
+    free (p);
+  }
+  *TimeFormat = FALSE;
+  if ((p = get_variable ("TIMEFORMAT")) != (char *) NULL) {
+    if (!strcasecmp (p, "date")) *TimeFormat   = TIME_DATE;
+    if (!strcasecmp (p, "hours")) *TimeFormat  = TIME_HOURS;
+    if (!strcasecmp (p, "days")) *TimeFormat   = TIME_DAYS;
+    if (!strcasecmp (p, "JD")) *TimeFormat     = TIME_JD;
+    if (!strcasecmp (p, "MJD")) *TimeFormat    = TIME_MJD;
+    if (!strcasecmp (p, "sec")) *TimeFormat    = TIME_SEC;
+    if (!*TimeFormat) fprintf (stderr, "unknown TIME_FORMAT\n");
+    free (p);
+    return (FALSE);
+  }
+  if (!*TimeFormat) *TimeFormat = TIME_SEC;
+  return (TRUE);
+}
+  
+/* convert UNIX time to a value referenced to the TimeReference in the given unit */
+double TimeValue (unsigned int time, unsigned int TimeReference, int TimeFormat) {
+
+  double value, dt;
+
+  dt = (time > TimeReference) ? (time - TimeReference) : -1 * (double)(TimeReference - time);
+  switch (TimeFormat) {
+  case TIME_HOURS:
+    value = dt / 3600.0;
+    break;
+  case TIME_DAYS:
+    value = dt / 86400.0;
+    break;
+  case TIME_JD:
+    value = time / 86400.0 + 2440587.5;
+    break;
+  case TIME_MJD:
+    value = time / 86400.0 + 40587.0;
+    break;
+  case TIME_SEC:
+  default:
+    value = dt;
+    break;
+  }
+  return (value);
+}
+  
+/* convert time value referenced to the TimeReference in the given unit to UNIX time */
+unsigned int TimeRef (double value, unsigned int TimeReference, int TimeFormat) {
+
+  int dt;
+  unsigned int time;
+
+  switch (TimeFormat) {
+  case TIME_HOURS:
+    dt = value * 3600.0;
+    break;
+  case TIME_DAYS:
+    dt = value * 86400.0;
+    break;
+  case TIME_JD:
+    time = (value -  2440587.5) * 86400.0;
+    return (time);
+    break;
+  case TIME_MJD:
+    time = (value -  40587.0) * 86400.0;
+    return (time);
+    break;
+  case TIME_SEC:
+  default:
+    dt = value;
+    break;
+  }
+
+  time = TimeReference + dt;
+  return (time);
+}
Index: /trunk/Ohana/src/getstar/src/mkcatalog.c
===================================================================
--- /trunk/Ohana/src/getstar/src/mkcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/mkcatalog.c	(revision 2490)
@@ -0,0 +1,42 @@
+# include "addstar.h"
+# include <time.h>
+
+mkcatalog (GSCRegion *region, Catalog *catalog) {
+  
+  char filename[64], line[64];
+  int i, Nmeas, Nmiss;
+  struct tm *local;
+  struct timeval now;
+  char mode;
+  int status, Nextra, in, out, j;
+  SecFilt *insec, *outsec;
+
+  if (VERBOSE) fprintf (stderr, "new catalog file: %s\n", region[0].filename);
+  if (!fits_read_header (CatTemplate, &catalog[0].header)) {
+    fprintf (stderr, "ERROR: can't find template header %s\n", CatTemplate);
+    exit (1);
+  }
+  
+  /* assign header values for RA, DEC, DATE, etc */
+  fits_modify (&catalog[0].header, "RA0", "%lf", 1, region[0].RA[0]);
+  fits_modify (&catalog[0].header, "DEC0", "%lf", 1, region[0].DEC[0]);
+  fits_modify (&catalog[0].header, "RA1", "%lf", 1, region[0].RA[1]);
+  fits_modify (&catalog[0].header, "DEC1", "%lf", 1, region[0].DEC[1]);
+  gettimeofday (&now, NULL);
+  local = localtime (&now.tv_sec);
+  sprintf (line, "%02d/%02d/%02d\0", local[0].tm_year, local[0].tm_mon + 1, local[0].tm_mday); 
+  fits_modify (&catalog[0].header, "DATE", "%s", 1, line);
+  strcpy (filename, CatTemplate);
+  ALLOCATE (catalog[0].average, Average, 1);
+  ALLOCATE (catalog[0].measure, Measure, 1);
+  ALLOCATE (catalog[0].missing, Missing, 1);
+  catalog[0].Naverage = catalog[0].Nmeasure = catalog[0].Nmissing = 0;
+
+  /* setup secondary filters to match photcodes */
+  ALLOCATE (catalog[0].secfilt, SecFilt, 1);
+  catalog[0].Nsecfilt = GetPhotcodeNsecfilt ();
+
+  /* Nsecfilt is number of filters.  Number of entries in array is
+     Nsecfilt * Naverage.  At this point, N entries == 0 */
+
+}
Index: /trunk/Ohana/src/getstar/src/old/ForkToServer.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/ForkToServer.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/ForkToServer.c	(revision 2490)
@@ -0,0 +1,77 @@
+# include <ohana.h>
+
+int ForkToServer (int argc, char **argv, char *database, char *server) {
+
+  int i, fd, N, pid, status;
+  char **arglist, *p;
+  char hostname[1025];
+  struct timeval now, then;  
+  double dtime;
+
+  /* get local hostname */
+  if (gethostname (hostname, 1024)) {
+    fprintf (stderr, "ERROR: can't get hostname\n");
+    exit (1);
+  }
+
+  /* lock database file */
+  fd = setlockfile (database, 60.0, TRUE);
+  if (fd == -1) {
+    fprintf (stderr, "ERROR: can't set lock on %s\n", database);
+    exit (1);
+  }
+
+  if ((p = strchr (server, '.')) != (char *) NULL) *p = 0;
+  if ((p = strchr (hostname, '.')) != (char *) NULL) *p = 0;
+
+  if (!strcasecmp (hostname, server)) return (fd);
+
+  if (!strlen (server)) {
+    fprintf (stderr, "ERROR: no Database Server defined\n");
+    clearlockfile (database, fd, TRUE);
+    exit (1);
+  }
+
+  /* get start of fork time */
+  gettimeofday (&then, (void *) NULL);
+  pid = fork ();
+  if (!pid) { 
+    /* must be child process, fork to remote machine */
+
+    /* create argument list */
+    N = argc + 4;
+    ALLOCATE (arglist, char *, N);
+
+    arglist[0] = strcreate ("rsh");
+    arglist[1] = strcreate (server);
+    arglist[2] = strcreate (argv[0]);
+    arglist[3] = strcreate ("-remote");
+    for (i = 4; i < N; i++) {
+      arglist[i] = strcreate (argv[i-3]);
+    }
+    fprintf (stderr, "starting remote process on %s\n", server);
+    status = execvp ("rsh", arglist);
+    fprintf (stderr, "ERROR: can't start remote shell process\n");
+    exit (1);
+  }
+  /* it would be good to put rsh in the config file */
+
+  /* block until child exits */
+  wait (0);
+  
+  /*****  
+       inetd has a maximum connection rate of 40 / 60 seconds it will
+       block for 10 min if this rate is exceeded.  this is here because
+       we have to hold the lock long enough that the connection rate does
+       not get exceeded.  We actually use 3.0 seconds to avoid stealing
+       too many rsh slots. 
+  *****/
+  
+  gettimeofday (&now, (void *) NULL);
+  dtime = 1e6*(3.0 - DTIME(now,then));
+  if (dtime > 0) usleep (dtime);
+  
+  clearlockfile (database, fd, TRUE);
+  exit (0);
+  
+}
Index: /trunk/Ohana/src/getstar/src/old/add_unfound.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/add_unfound.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/add_unfound.c	(revision 2490)
@@ -0,0 +1,35 @@
+  /* incorporate unmatched image stars -- after all catalogs searched... */
+  for (i = 0; i < Nstars; i++) {
+    if (!found[i]) {
+      catalog[0].average[Nave].R = stars[N1[i]].R;
+      catalog[0].average[Nave].D = stars[N1[i]].D;
+      catalog[0].average[Nave].M = 1000.0*stars[N1[i]].M;
+      catalog[0].average[Nave].Nm = 1;
+      catalog[0].average[Nave].Xp = catalog[0].average[Nave].Xm = 0.0;
+      catalog[0].average[Nave].offset = Nmeas;
+      catalog[0].measure[Nmeas].dR  = 0.0;
+      catalog[0].measure[Nmeas].dD  = 0.0;
+      catalog[0].measure[Nmeas].M   = 1000.0*stars[N1[i]].M;
+      catalog[0].measure[Nmeas].dM  = stars[N1[i]].dM;
+      catalog[0].measure[Nmeas].t  = 3600.0 + stars[N1[i]].Y*0.1;
+      catalog[0].measure[Nmeas].average = (0x00ffffff & Nave);
+      /* time of star = time of image + offset + Y*rate */
+      Nave ++;
+      if (Nave == 0x1000000) {
+	fprintf (stderr, "too many stars in catalog\n");
+	clear_lockfile ();
+	exit (0);
+      }
+      if (Nave == NAVE) {
+	NAVE = Nave + 1000;
+	REALLOCATE (next, int, NAVE);
+	REALLOCATE (catalog[0].average, Average, NAVE);
+      }
+      Nmeas ++;
+      if (Nmeas == NMEAS) {
+	NMEAS = Nmeas + 1000;
+	REALLOCATE (next, int, NMEAS);
+	REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      }
+    }
+  }
Index: /trunk/Ohana/src/getstar/src/old/check_lockfile.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/check_lockfile.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/check_lockfile.c	(revision 2490)
@@ -0,0 +1,46 @@
+# include "addstar.h"
+
+check_lockfile ()
+{
+  
+  FILE *f;
+  char filename[128];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    fprintf (stderr, "ERROR: catalog %s is locked, try again later\n", CATDIR);
+    sprintf (filename, "%s/kill\0", CATDIR);
+    f = fopen (filename, "w");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "ERROR: can't set kill file %s\n", filename);
+      exit (0);
+    }
+    fclose (f);
+    exit (0);
+  }
+
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock file %s\n", filename);
+    exit (0);
+  }
+  fclose (f);
+
+}
+
+clear_lockfile ()
+{
+  
+  char filename[128], line[256];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    sprintf (line, "rm %s\0", filename);
+    system (line);
+  } else {
+    fprintf (stderr, "can't remove lockfile, why not?\n");
+  }
+
+}
Index: /trunk/Ohana/src/getstar/src/old/config.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/config.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/config.c	(revision 2490)
@@ -0,0 +1,110 @@
+# include <ohana.h>
+# define D_NBYTES 4096
+
+char *LoadConfigFile (filename) 
+char *filename; 
+{
+  
+  FILE *f;
+  int i, done, Nbytes, NBYTES, size;
+  char *config;
+  
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "couldn't find %s\n", filename);
+    return ((char *) NULL);
+  }
+ 
+  NBYTES = D_NBYTES;
+  ALLOCATE (config, char, NBYTES);
+ 
+  size = 0;
+  done = FALSE;
+  for (i = 0; !done; i++) {
+    Nbytes = Fread (&config[i*D_NBYTES], sizeof(char), D_NBYTES, f, "char");
+    size += Nbytes;
+    if (Nbytes < D_NBYTES) 
+      done = TRUE;
+    else {
+      NBYTES += D_NBYTES;
+      REALLOCATE (config, char, NBYTES);
+    }
+  }
+  
+  config[size] = '\n';
+  config[size+1] = 0;
+  REALLOCATE (config, char, size + 2);
+ 
+  fclose (f);
+
+  return (config);
+}
+
+int ScanConfig /* we expect one more field: the pointer to the value requested */
+# ifndef ANSI
+(config, field, mode, va_alist) 
+ char *config; char *field, *mode; va_dcl
+# else
+(char       config[],
+ char       field[],
+ char       mode[],...)
+# endif
+{
+ 
+  int i, j;
+  char *p, *p2, tmp[256];
+  va_list argp;
+  double value;
+  
+# ifndef ANSI
+  va_start (argp);
+# else
+  va_start (argp, N);
+# endif
+  
+  /* find the correct line with field */
+  p2 = config;
+  for (i = 0; ; i++) {
+    if (!strncmp (field, p2, strlen(field))) {
+      p = p2 + strlen (field);
+      break;
+    }
+    else {
+      p2 = strchr (p2, '\n');
+      if (p2 == (char *) NULL) {
+	fprintf (stderr, "entry %s not found in config file\n", field);
+	return (FALSE);
+      }
+      else p2++;
+    }
+  }
+  if (!strcmp (mode, "%s")) {
+    p2 = strchr (p, '\n');
+    if (p2 == (char *) NULL)
+      p2 = config + strlen(config);
+    bcopy (p, tmp, (p2-p));
+    tmp[(p2-p)] = 0;
+    stripwhite (tmp);
+    p2 = va_arg (argp, char *);
+    strcpy (p2, tmp);
+  }
+  else {
+ 
+    /* try to get a numerical value from the field */
+    value = strtod (p, &p2);
+    if ((*p2 == 'd') || (*p2 == 'D')) 
+      value *= pow (10.0, atof (p2 + 1));
+    
+    if (!strcmp (mode, "%d"))  *va_arg (argp, int *)       = value;
+    if (!strcmp (mode, "%u"))  *va_arg (argp, unsigned *)  = value;
+    if (!strcmp (mode, "%ld")) *va_arg (argp, long *)      = value;
+    if (!strcmp (mode, "%hd")) *va_arg (argp, short *)     = value;
+    if (!strcmp (mode, "%f"))  *va_arg (argp, float *)     = value;
+    if (!strcmp (mode, "%lf")) *va_arg (argp, double *)    = value;
+    
+  }
+ 
+  va_end (argp);
+  return (TRUE);
+  
+}
Index: /trunk/Ohana/src/getstar/src/old/dumpcat.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/dumpcat.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/dumpcat.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  int i, j, Nstars, Nimage, Nregions;
+  Average *average;
+  Measure *measure;
+  Missing *missing;
+  Catalog catalog;
+  GSCRegion region;
+  FILE *f;
+  
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: dumpcat catalog output mode(0,1,2,3)\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  strcpy (region.filename, argv[1]);
+
+  gcatalog (&region, &catalog);
+
+  f = fopen (argv[2], "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "failed to open file %s for write\n", argv[2]);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  average = catalog.average;
+  for (i = 0; i < catalog.Naverage; i++) {
+    fprintf (f, "%10.6f %10.6f %7.3f %3d %3d %8d %d\n", average[i].R, average[i].D, 
+	     0.001*average[i].M, average[i].Nm, average[i].Nn, average[i].offset, catalog.measure[average[i].offset].t);
+    if ((atof(argv[3]) == 1) || (atof(argv[3]) == 3)) {
+      measure = &catalog.measure[average[i].offset];
+      for (j = 0; j < average[i].Nm; j++) {
+	fprintf (f, "  %d %d %f %f %d\n", measure[j].dR, measure[j].dD, 0.001*measure[j].M, 
+		  measure[j].t, measure[j].average);
+      }
+    }
+    if ((atof(argv[3]) == 2) || (atof(argv[3]) == 3)) {
+      if (average[i].Nn > 0) {
+	missing = &catalog.missing[average[i].missing];
+	for (j = 0; j < average[i].Nn; j++) {
+	  fprintf (f, "  %f\n", missing[j].t);
+	}
+      } else { 
+	fprintf (f, "no missing obs\n");
+      }
+    }
+  }
+
+    
+
+  fclose (f);
+    
+
+}
Index: /trunk/Ohana/src/getstar/src/old/gstars1.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/gstars1.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/gstars1.c	(revision 2490)
@@ -0,0 +1,273 @@
+# include "addstar.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 31
+# define BLOCK 1000
+#include <sys/time.h>
+#include <time.h>
+
+Stars *gstars (file, NSTARS, image) 
+char file[];
+int *NSTARS;
+Image *image;
+{
+
+  FILE *f;
+  Header header;
+  int j, N, Ninstar;
+  int nbytes, Nbytes;
+  Stars *stars;
+  char *buffer;
+  double tmp;
+  int done, doneread, Nskip, Nextra, itmp;
+  char  *c, *c2;
+  unsigned short int Nc;
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", file);
+    clearlockfile (ImageCat, -1);
+    exit(0);
+  }
+
+  /* open file */
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", file);
+    clearlockfile (ImageCat, -1);
+    exit(0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* find image rootname */
+  c = strrchr (file, 0x2f);
+  if (c == (char *) NULL) {
+    strcpy (image[0].name, file);
+  } else { 
+    strcpy (image[0].name, (c+1));
+  }
+
+  /* get astrometry information */
+  if (!GetCoords (&image[0].coords, &header)) {
+    fprintf (stderr, "ERROR: no astrometric solution in header\n");
+    clearlockfile (ImageCat, -1);
+    exit (0);
+  }
+  while (image[0].coords.crval1 < 0) image[0].coords.crval1 += 360.0;
+  while (image[0].coords.crval1 > 360.0) image[0].coords.crval1 -= 360.0;
+  itmp = 0;
+  fits_scan (&header, "NASTRO",   "%d", 1, &itmp);
+  if (itmp == 0) {
+    fprintf (stderr, "ERROR: bad astrometric solution in header\n");
+    clearlockfile (ImageCat, -1);
+    exit (0);
+  }
+    
+  /* CERROR in data file is in arcsec */
+  fits_scan (&header, "CERROR",   "%lf", 1, &tmp);
+  image[0].cerror = tmp * 50.0;
+  fits_scan (&header, "NAXIS1",   "%hd", 1, &image[0].NX); 
+  fits_scan (&header, "NAXIS2",   "%hd", 1, &image[0].NY);
+  fits_scan (&header, "PHOTCODE", "%hd", 1, &image[0].source);
+  if (NEWPHOTCODE) {
+    image[0].source = PHOTCODE;
+  }
+  if ((image[0].source < 0) || (image[0].source > 0xffff)) {
+    fprintf (stderr, "error: invalid photcode\n");
+    exit (0);
+  }
+  Nc = photcodes.hashcode[image[0].source];
+  if (Nc < 0) {
+    fprintf (stderr, "ERROR: image has invalid photcode value\n");
+    exit (0);
+  }
+  thiscode = &photcodes.code[Nc];
+
+  image[0].NX -= XOVERSCAN;
+  image[0].NY -= YOVERSCAN;
+  fits_scan (&header, "EXPTIME",  "%lf", 1, &tmp);
+  image[0].exptime = tmp;
+  
+  tmp = 0;
+  fits_scan (&header, "APMIFIT",  "%lf", 1, &tmp);
+  image[0].apmifit = tmp * 1000.0;
+
+  tmp = 0;
+  fits_scan (&header, "dAPMIFIT", "%lf", 1, &tmp);
+  image[0].dapmifit = tmp * 1000.0;
+
+  tmp = 0;
+  fits_scan (&header, "FLIMIT",   "%lf", 1, &tmp);
+  image[0].detection_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FSATUR",   "%lf", 1, &tmp);
+  image[0].saturation_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FWHM_X",   "%lf", 1, &tmp);
+  image[0].fwhm_x = tmp * 25.0 * image[0].coords.cdelt1 * 3600.0;
+
+  tmp = 0;
+  fits_scan (&header, "FWHM_Y",   "%lf", 1, &tmp);
+  image[0].fwhm_y = tmp * 25.0 * image[0].coords.cdelt1 * 3600.0;
+
+  if (!fits_scan (&header, "TZERO",   "%d",  1, &image[0].tzero)) {
+    image[0].tzero = parse_time (&header);
+  }
+
+  tmp = 0;
+  fits_scan (&header, "TRATE",   "%lf", 1, &tmp);
+  image[0].trate = 10000 * tmp;
+
+  tmp = 0;
+  fits_scan (&header, "AIRMASS", "%lf", 1, &tmp);
+  image[0].secz = 1000*tmp;
+
+  if (!fits_scan (&header, "IMAGEID", "%d", 1, &itmp)) {
+    image[0].ccdnum = 0xff;
+  } else {
+    image[0].ccdnum = itmp;
+  }
+
+  fits_scan (&header, "ZERO_PT", "%lf", 1, &ZeroPt);
+
+  /* secz is in units milli-airmass */
+  image[0].Mcal =  ALPHA*(image[0].secz - 1000);
+  image[0].Xm   = 30.0;
+  image[0].code = 0;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+
+  /* find expected number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar);
+  if (image[0].nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    clearlockfile (ImageCat, -1);
+    exit (0);
+  }
+  ALLOCATE (stars, Stars, image[0].nstar);
+
+  /* load in stars by blocks of 1000 */
+  N = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR) + 1);
+  buffer[BLOCK*BYTES_STAR] = 0;
+  Nextra = 0;
+  doneread = FALSE;
+  while (!doneread) {
+    Nbytes = BYTES_STAR * BLOCK - Nextra;
+    nbytes = Fread (&buffer[Nextra], 1, Nbytes, f, "char");
+    if (nbytes == 0) {
+      doneread = TRUE;
+      continue;
+    }
+    nbytes += Nextra;
+    /* check line-by-line integrity */
+    c = buffer;
+    done = FALSE;
+    while ((c < buffer + nbytes) && (!done)) { 
+      for (c2 = c; *c2 == '\n'; c2++);
+      if (c2 > c) { /* extra return chars */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+	if (VERBOSE) fprintf (stderr, "deleted %d extra return chars\n", Nskip);
+      }
+      c2 = strchr (c, '\n');
+      if (c2 == (char *) NULL) {
+	done = TRUE;	
+	continue;
+      }
+      c2++;
+      if ((c2 - c) != BYTES_STAR) { /* bad line, delete it */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+	if (VERBOSE) fprintf (stderr, "deleted line, %d extra chars\n", Nskip);
+      } else {
+	c = c2;
+      }
+    }
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (j = 0; j < Ninstar; j++, N++) {
+      dparse (&stars[N].X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].M,  3, &buffer[j*BYTES_STAR]);
+      dparse (&stars[N].dM, 4, &buffer[j*BYTES_STAR]);
+      XY_to_RD (&stars[N].R, &stars[N].D, stars[N].X, stars[N].Y, &image[0].coords);
+      while (stars[N].R < 0.0) stars[N].R += 360.0;
+      while (stars[N].R >= 360.0) stars[N].R -= 360.0;
+      dparse (&tmp, 5, &buffer[j*BYTES_STAR]);
+      stars[N].dophot = tmp;
+      stars[N].found = -1;
+    }
+  }
+
+  image[0].nstar = N;
+  REALLOCATE (stars, Stars, image[0].nstar);
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+  *NSTARS = image[0].nstar;
+
+  return (stars);
+}
+
+
+
+
+# if (0)
+  /* left over fraction of a block */
+  nbytes = Fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f, "char");
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    clearlockfile (ImageCat, -1);
+    exit (0);
+  }
+  /* check line-by-line integrity */
+  Nnew = 0;
+  c = buffer;
+  done = FALSE;
+  while ((c < buffer + nbytes) && (!done)) { 
+    for (c2 = c; *c2 == '\n'; c2++);
+    if (c2 > c) { /* extra return chars */
+      memmove (c, c2, (int)(buffer + nbytes - c2));
+      Nnew += c2 - c;
+      fprintf (stderr, "deleting %d extra return chars\n", (int)(c2-c));
+    }
+    c2 = strchr (c, '\n');
+    if (c2 == (char *) NULL) {
+      if (Nnew > 0) {
+	nnew = Fread (&buffer[nbytes-Nnew], 1, Nnew, f, "char");
+	if (nnew != Nnew) {
+	  fprintf (stderr, "ERROR: failed to read in stars (1)\n");
+	  exit (0);
+	}
+      } else {
+	done = TRUE;	
+      }
+      continue;
+    }
+    c2++;
+    if ((c2 - c) != BYTES_STAR) {
+      /* this is a bad line, delete it, adjust data in buffer, 
+	 and be ready to read the rest of the last line */
+      memmove (c, c2, (int)(buffer + nbytes - c2));
+      Nnew += c2 - c;
+      fprintf (stderr, "deleting bad line with %d chars\n", (int)(c2-c));
+    } else {
+      c = c2;
+    }
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstar++, N++) {
+    dparse (&stars[N].X, 1, &buffer[j*BYTES_STAR]);
+    dparse (&stars[N].Y, 2, &buffer[j*BYTES_STAR]);
+    dparse (&stars[N].M, 3, &buffer[j*BYTES_STAR]);
+    dparse (&stars[N].dM, 4, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&stars[N].R, &stars[N].D, stars[N].X, stars[N].Y, &image[0].coords);
+    while (stars[N].R < 0.0) stars[N].R += 360.0;
+    while (stars[N].R >= 360.0) stars[N].R -= 360.0;
+    dparse (&tmp, 5, &buffer[j*BYTES_STAR]);
+    stars[N].dophot = tmp;
+    stars[N].found = -1;
+  }
+
+# endif
Index: /trunk/Ohana/src/getstar/src/old/sort_stars.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/sort_stars.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/sort_stars.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "relphot.h"
+
+void sort_stars (radec, stars, Nstars)
+int  **radec;
+Star  *stars;
+int    Nstars;
+{
+  
+  int i;
+  double *RAs;
+
+  ALLOCATE (radec[0], int, Nstars);
+  ALLOCATE (RAs, double, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    radec[0][i] = i;
+    RAs[i] = stars[i].RA;
+  }
+
+  sort_seq (radec[0], RAs, Nstars);
+  free (RAs);
+
+}
+
+
+void sort_seq (seq, value, N) 
+int *seq;
+double *value;
+int N;
+{
+  int l,j,ir,i;
+  int temp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = seq[--l];
+    }
+    else {
+      temp = seq[ir];
+      seq[ir] = seq[0];
+      if (--ir == 0) {
+	seq[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[seq[j]] < value[seq[j+1]]) ++j;
+      if (value[temp] < value[seq[j]]) {
+	seq[i]=seq[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
+
+
Index: /trunk/Ohana/src/getstar/src/old/string.c
===================================================================
--- /trunk/Ohana/src/getstar/src/old/string.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/old/string.c	(revision 2490)
@@ -0,0 +1,64 @@
+# include <stdio.h>
+# include <math.h>
+# define TRUE  1
+# define FALSE 0
+
+int scan_line (f, line) 
+FILE *f;
+char line[];
+{
+
+  int i, status;
+  char c;
+  
+  status = EOF + 1;
+  
+  for (i = 0, c = 0; (c != '\n') && (status != EOF); i++) {
+    status = fscanf (f, "%c", &c);
+    line[i] = c;
+  }
+  line[i - 1] = 0;  /* this could make things crash! */
+
+  if (i > 1) {
+    status = EOF + 1;
+  }
+
+  return (status);
+
+}
+
+char *_parse_nextword(string)
+char *string;
+{
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (; isspace (*string); string++);
+  for (; (*string != 0) && !isspace (*string); string++);
+  for (; isspace (*string); string++);
+  return (string);
+}
+
+int dparse (X, NX, line)
+double *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
Index: /trunk/Ohana/src/getstar/src/parse_time.c
===================================================================
--- /trunk/Ohana/src/getstar/src/parse_time.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/parse_time.c	(revision 2490)
@@ -0,0 +1,126 @@
+# include "addstar.h"
+
+parse_time (Header *header) {
+
+  double jd;
+  int Ny, Nf, mode;
+  int Nsec, hour, min, sec, year, month, day;
+  char *py, *pm, *pd, *c;
+  char line[256];
+
+  /* we want to find JD or MJD to get Nsec (seconds since 01/01/1970) */
+
+  /* try JD first */
+  if (strcasecmp (JDKeyword, "NONE")) {
+    uppercase (JDKeyword);
+    fits_scan (header, JDKeyword, "%lf", 1, &jd);
+    Nsec = (jd - 2440587.5)*86400;
+    return (Nsec);
+  }
+
+  /* try MJD next */
+  if (strcasecmp (MJDKeyword, "NONE")) {
+    uppercase (MJDKeyword);
+    fits_scan (header, MJDKeyword, "%lf", 1, &jd);
+    Nsec = (jd - 40587.0)*86400;
+    return (Nsec);
+  }
+    
+  /* get UT and DATE */
+  uppercase (UTKeyword);
+  fits_scan (header, UTKeyword, "%s", 1, line);
+  /* remove ':' characters */
+  for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (line, 0x3a)) { *c = ' '; }
+  sscanf (line, "%d %d %d", &hour, &min, &sec);
+
+  /* parse mode line */
+  uppercase (DateMode);
+  for (Ny = 0, c = strchr (DateMode, 'Y'); c != (char ) NULL; c = strchr (c + 1, 'Y'), Ny++);
+  if ((Ny != 2) && (Ny != 4)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  py = strchr (DateMode, 'Y');
+  pm = strchr (DateMode, 'M');
+  pd = strchr (DateMode, 'D');
+  if ((py == (char *) NULL) || (pm == (char *) NULL) || (pd == (char *) NULL)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  if ((py > pm) && (py < pd)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  if ((py > pd) && (py < pm)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  mode = 0;
+  if ((py < pm) && (pm < pd)) { mode = 1; }  /* yyyy-mm-dd */
+  if ((py < pm) && (pm > pd)) { mode = 2; }  /* yyyy-dd-mm */
+  if ((py > pm) && (pm < pd)) { mode = 3; }  /* mm-dd-yyyy */
+  if ((py > pm) && (pm > pd)) { mode = 4; }  /* dd-mm-yyyy */
+  if (!mode) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+
+  /* parse date entry */
+  uppercase (DateKeyword);
+  fits_scan (header, DateKeyword, "%s",  1, line);
+  /* remove possible separators: ':', '/' '.', '-' */
+  for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (line, 0x3a)) { *c = ' '; }
+  for (c = strchr (line, 0x2f); c != (char *) NULL; c = strchr (line, 0x2f)) { *c = ' '; }
+  for (c = strchr (line, 0x2e); c != (char *) NULL; c = strchr (line, 0x2e)) { *c = ' '; }
+  for (c = strchr (line, 0x2d); c != (char *) NULL; c = strchr (line, 0x2d)) { *c = ' '; }
+
+  switch (mode) {
+  case 1:
+    Nf = sscanf (line, "%d %d %d", &year, &month, &day);
+    break;
+  case 2:
+    Nf = sscanf (line, "%d %d %d", &year, &day, &month);
+    break;
+  case 3:
+    Nf = sscanf (line, "%d %d %d", &month, &day, &year);
+    break;
+  case 4:
+    Nf = sscanf (line, "%d %d %d", &day, &month, &year);
+    break;
+  }
+  if (Nf != 3) {
+    fprintf (stderr, "error in date entry (%s) or DATE-MODE format (%s)\n", line, DateMode);
+    exit (1);
+  }
+
+  if (year > 1000) {
+    if (Ny == 2) {
+      fprintf (stderr, "warning: mode line claims 2 digit year, but 4 digit year found\n");
+    }
+  } else {
+    if (Ny == 4) {
+      fprintf (stderr, "warning: mode line claims 4 digit year, but 2 digit year found\n");
+    }
+    if (year < 50) year += 100;
+    year += 1900;
+  }    
+
+  /* convert yy.mm.dd hh.mm.ss to Nsec since 1970 (jd = 2440587.5) */
+  /* note that in this section, tm_mon has range 1-12, unlike for gmtime () */
+  jd = day - 32075 + (int)(1461*(year + 4800 + (int)(((month)-14)/12))/4)
+    + (int)(367*((month) - 2 - (int)(((month) - 14)/12)*12)/12)
+    - (int)(3*(int)((year + 4900 + (int)(((month) - 14)/12))/100)/4) - 0.5;
+  /* jd is the julian day of the whole day only not the time */
+  Nsec = (jd - 2440587.5)*86400 + 3600.0*hour + min*60.0 + sec;
+  
+  return (Nsec);
+
+}
+
+uppercase (char *string) {
+
+  int i;
+    
+  for (i = 0; i < strlen (string); i++) string[i] = toupper (string[i]);
+
+}
Index: /trunk/Ohana/src/getstar/src/sort_lists.c
===================================================================
--- /trunk/Ohana/src/getstar/src/sort_lists.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/sort_lists.c	(revision 2490)
@@ -0,0 +1,82 @@
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+fsort (float *X, int N) {
+
+  int l,j,ir,i;
+  float tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+  }
+}
Index: /trunk/Ohana/src/getstar/src/wcatalog.c
===================================================================
--- /trunk/Ohana/src/getstar/src/wcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/wcatalog.c	(revision 2490)
@@ -0,0 +1,37 @@
+# include "addstar.h"
+
+wcatalog (Catalog *catalog) {
+  
+  int status;
+
+  /* we'll leave these for now, but they are LONEOS specific */
+  fits_modify (&catalog[0].header, "MARKSTAR", "%t", 1, FALSE);
+  fits_modify (&catalog[0].header, "ADDUSNO", "%t", 1, FALSE);
+  fits_modify (&catalog[0].header, "MARKROCK", "%t", 1, FALSE);
+
+  if (!save_catalog (catalog, VERBOSE)) {
+    fprintf (stderr, "ERROR: failure saving catalog\n");
+    exit (1);
+  }
+
+  /* free, initialize data structures */
+
+  if (catalog[0].Naverage) {
+    free (catalog[0].average); 
+    catalog[0].Naverage = 0;
+  }
+  if (catalog[0].Nmeasure) {
+    free (catalog[0].measure); 
+    catalog[0].Nmeasure = 0;
+  }
+  if (catalog[0].Nmissing) {
+    free (catalog[0].missing); 
+    catalog[0].Nmissing = 0;
+  }
+  if (catalog[0].Nsecfilt) {
+    free (catalog[0].secfilt); 
+    catalog[0].Nsecfilt = 0;
+  }
+  fits_free_header (&catalog[0].header);
+}
+
Index: /trunk/Ohana/src/getstar/src/wimage.c
===================================================================
--- /trunk/Ohana/src/getstar/src/wimage.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/wimage.c	(revision 2490)
@@ -0,0 +1,52 @@
+# include "getstar.h"
+
+wimage (FILE *f, int dbstate, Image *image, int Nstars) {
+  
+  int Nimages, status, mode;
+  Header header;
+
+  /* place file pointer at beginning of file */
+  fseek (f, 0, SEEK_SET);
+
+  if (dbstate == LCK_EMPTY) {
+    if (VERBOSE) fprintf (stderr, "can't find %s, creating a new one\n", ImageCat);
+    if (!fits_read_header (ImageTemplate, &header)) {
+      fprintf (stderr, "ERROR: can't find template header %s\n", ImageTemplate);
+      exit (1);
+    }
+    /* assign Zero Point provided by first image in dB */
+    fits_modify (&header, "ZERO_PT", "%lf", 1, ZeroPt);
+  } else {
+    if (!fits_load_header (f, &header)) {
+      fprintf (stderr, "ERROR: can't read image header %s\n", ImageCat);
+      exit (1);
+    }
+  }
+  
+  Nimages = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimages);
+  Nimages ++;
+  fits_modify (&header, "NIMAGES", "%d", 1, Nimages);
+
+  /* position to begining of file to write header */
+  fseek (f, 0, SEEK_SET);
+  status = Fwrite (header.buffer, 1, header.size, f, "char");
+  if (status != header.size) {
+    fprintf (stderr, "ERROR: failed writing data to image header\n");
+    exit (1);
+  }
+
+  /* position to end of file for new image data */
+  fseek (f, 0, SEEK_END);
+  status = Fwrite (image, sizeof(Image), 1, f, "image");
+  if (status != 1) {
+    fprintf (stderr, "ERROR: failed writing data to image catalog\n");
+    exit (1);
+  }
+}
+
+/* the image we add in this routine is always a new image.  
+   We only need to do two things:
+     1) append the data for the image to the end of the file
+     2) update the NIMAGES field in the header (which means, read in header, re-write)
+ */
Index: /trunk/Ohana/src/getstar/src/wstars.c
===================================================================
--- /trunk/Ohana/src/getstar/src/wstars.c	(revision 2490)
+++ /trunk/Ohana/src/getstar/src/wstars.c	(revision 2490)
@@ -0,0 +1,146 @@
+# include "getstar.h"
+# define NCHAR 66 /* 65 char EXCLUDING return */
+
+int wstars (char *filename, Stars *stars, int Nstars, Image *image) {
+
+  /* construct a header from the image structure */
+  /* write out header */
+  /* write out data lines */
+
+  int i, Nchar, Ny, mode;
+  double scale;
+  char *photcode, *c, *py, *pm, *pd, datestr[64], timestr[64];
+  struct tm *gmt;
+  Header header;
+  FILE *f;
+  char line[NCHAR];
+
+  fits_init_header (&header);
+  header.Naxis[0] = image[0].NX + XOVERSCAN;
+  header.Naxis[1] = image[0].NY + YOVERSCAN;
+  header.bitpix   = 16;
+  header.Naxes    = 2;
+  fits_create_header (&header);
+
+  /* astrometric data */
+  fits_print (&header, "CTYPE1",  "%s", 1, "RA---SIN");
+  fits_print (&header, "CTYPE2",  "%s", 1, "DEC--SIN");
+
+  fits_print (&header, "CRVAL1", "%f", 1, image[0].coords.crval1);
+  fits_print (&header, "CRVAL2", "%f", 1, image[0].coords.crval2);
+
+  fits_print (&header, "CRPIX1", "%f", 1, image[0].coords.crpix1);
+  fits_print (&header, "CRPIX2", "%f", 1, image[0].coords.crpix2);
+
+  fits_print (&header, "PC001001",  "%f", 1, image[0].coords.pc1_1);
+  fits_print (&header, "PC001002",  "%f", 1, image[0].coords.pc1_2);
+  fits_print (&header, "PC002001",  "%f", 1, image[0].coords.pc2_1);
+  fits_print (&header, "PC002002",  "%f", 1, image[0].coords.pc2_2);
+
+  fits_print (&header, "CDELT1",  "%f", 1, image[0].coords.cdelt1);
+  fits_print (&header, "CDELT2",  "%f", 1, image[0].coords.cdelt2);
+  
+  fits_print (&header, "NASTRO", "%d", 1, 1); /* TBD */
+  fits_print (&header, "EQUINOX", "%f", 1, 2000.0); /* TBD */
+  
+  fits_print (&header, "CERROR", "%f", 1, 0.02*image[0].cerror);
+
+  photcode = GetPhotcodeNamebyCode (image[0].source);
+  fits_print (&header, "PHOTCODE", "%s", 1, photcode);
+
+  fits_print (&header, ExptimeKeyword, "%f", 1, image[0].exptime);
+  
+  fits_print (&header, "FLIMIT",   "%lf", 1, 0.1*image[0].detection_limit);
+  fits_print (&header, "FSATUR",   "%lf", 1, 0.1*image[0].saturation_limit);
+
+  scale = image[0].coords.cdelt1*25.0*3600.0;
+  fits_print (&header, "FWHM_X",   "%lf", 1, image[0].fwhm_x / scale);
+  fits_print (&header, "FWHM_Y",   "%lf", 1, image[0].fwhm_y / scale);
+	      
+  fits_print (&header, "TRATE",   "%lf", 1, image[0].trate/10000.0);
+  fits_print (&header, AirmassKeyword, "%lf", 1, 0.001*image[0].secz);
+
+  if (image[0].ccdnum != 0xff) {
+    fits_print (&header, CCDNumKeyword, "%d", 1, image[0].ccdnum);
+  }
+
+  /* parse date-mode line */
+  uppercase (DateMode);
+  for (Ny = 0, c = strchr (DateMode, 'Y'); c != (char ) NULL; c = strchr (c + 1, 'Y'), Ny++);
+  if ((Ny != 2) && (Ny != 4)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  py = strchr (DateMode, 'Y');
+  pm = strchr (DateMode, 'M');
+  pd = strchr (DateMode, 'D');
+  if ((py == (char *) NULL) || (pm == (char *) NULL) || (pd == (char *) NULL)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  if ((py > pm) && (py < pd)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  if ((py > pd) && (py < pm)) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+  mode = 0;
+  if ((py < pm) && (pm < pd)) { mode = 1; }  /* yyyy-mm-dd */
+  if ((py < pm) && (pm > pd)) { mode = 2; }  /* yyyy-dd-mm */
+  if ((py > pm) && (pm < pd)) { mode = 3; }  /* mm-dd-yyyy */
+  if ((py > pm) && (pm > pd)) { mode = 4; }  /* dd-mm-yyyy */
+  if (!mode) {
+    fprintf (stderr, "error in DATE-MODE format: %s\n", DateMode);
+    exit (1);
+  }
+
+  gmt = gmtime ((unsigned long *)&image[0].tzero);
+
+  switch (mode) {
+  case 1:
+    sprintf (datestr, "%04d/%02d/%02d", 1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday);
+    break;
+  case 2:
+    sprintf (datestr, "%04d/%02d/%02d", 1900 + gmt[0].tm_year, gmt[0].tm_mday, gmt[0].tm_mon+1);
+    break;
+  case 3:
+    sprintf (datestr, "%02d/%02d/%04d", gmt[0].tm_mon+1, gmt[0].tm_mday, 1900 + gmt[0].tm_year);
+    break;
+  case 4:
+    sprintf (datestr, "%02d/%02d/%04d", gmt[0].tm_mday, gmt[0].tm_mon+1, 1900 + gmt[0].tm_year);
+    break;
+  }
+  sprintf (timestr, "%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  fits_print (&header, UTKeyword, "%s", 1, timestr);
+  fits_print (&header, DateKeyword, "%s", 1, datestr);
+
+  fits_print (&header, "ZERO_PT", "%lf", 1, ZeroPt);
+  fits_print (&header, "NSTARS", "%d", 1, Nstars);
+  
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't create output file %s\n", filename);
+    exit (1);
+  }
+
+  fwrite (header.buffer, 1, header.size, f);
+
+  for (i = 0; i < Nstars; i++) {
+    Nchar = snprintf (line, NCHAR, "%6.1f %6.1f %6.3f %03d %2d %3.1f %6.3f %6.3f %6.2f %6.2f %5.1f", 
+		      stars[i].X, stars[i].Y, stars[i].M, 
+		      (int)(stars[i].dM), stars[i].dophot, stars[i].sky, 
+		      stars[i].Mgal, stars[i].Map, stars[i].fx, stars[i].fy, stars[i].df);
+    fprintf (f, "%s\n", line);
+  }
+  fclose (f);
+}
+
+uppercase (char *string) {
+
+  int i;
+    
+  for (i = 0; i < strlen (string); i++) string[i] = toupper (string[i]);
+
+}
Index: /trunk/Ohana/src/lightcurve/Makefile
===================================================================
--- /trunk/Ohana/src/lightcurve/Makefile	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/Makefile	(revision 2490)
@@ -0,0 +1,53 @@
+include ../../Configure
+PROGRAM =	lightcurve
+HOME 	=	$(ROOT)/lightcurve
+
+default: $(PROGRAM)
+
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC) -I$(LINC)/$(ARCH)
+LIBS	= 	-L$(LLIB) -lohana -lFITS -lm 
+CFLAGS	=	-o $*.o $(INCS) 
+CCFLAGS	=	$(INCS) $(LIBS) 
+
+OBJS = \
+$(SRC)/args.o 		$(SRC)/get_names.o \
+$(SRC)/get_stars.o 	$(SRC)/sort_stars.o \
+$(SRC)/get_unique.o 	$(SRC)/get_sources.o \
+$(SRC)/get_info.o 	$(SRC)/make_table.o \
+$(SRC)/lightcurve.o	\
+$(SRC)/sort_seq.o	\
+$(SRC)/help.o 
+
+$(OBJS): $(INC)/lightcurve.h
+
+$(PROGRAM):	$(BIN)/$(PROGRAM)
+
+$(BIN)/$(PROGRAM): $(OBJS)
+	$(CC) $(OBJS) -o $(BIN)/$(PROGRAM) $(CCFLAGS)
+
+# -----------------------
+install:
+	rm -f $(DESTBIN)/$(PROGRAM)
+#	rm -f $(DESTMAN)/$(PROGRAM).1
+	cp $(BIN)/$(PROGRAM)   $(DESTBIN)/
+#	cp $(MAN)/$(PROGRAM).1 $(DESTMAN)/
+
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+dist: clean
+	rm -f $(BIN)/$(PROGRAM)
+
Index: /trunk/Ohana/src/lightcurve/include/lightcurve.h
===================================================================
--- /trunk/Ohana/src/lightcurve/include/lightcurve.h	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/include/lightcurve.h	(revision 2490)
@@ -0,0 +1,67 @@
+# include <ohana.h>
+
+# define EMPTY          -1   
+# define END            (star_data_type *) -1
+
+# define C_LAMBDA       23.0
+# define MCAL(I,dR,dD) (((I.Mcal) + (dR)*(I.McalR) + (dD)*(I.McalD) + (dR)*(dR)*(I.McalR2) + (dD)*(dD)*(I.McalD2) + (dD)*(dR)*(I.McalRD)))
+
+int PRINT;
+int MIDAS;
+int EXTRASTARS;
+int PIXELS;
+int NLOOP;
+double RADIUS;
+double A_LAMBDA;
+double SIG;
+double COS;
+double MCUTOFF;
+char OUTFILE[100];
+char IMAGES[100];
+
+typedef struct Star {
+  double RA, Dec;
+  double ap, m, dm;
+  struct Star *next_this_unique;
+  struct Star *next_this_image;
+  int    image_number, star_number, unique_number;
+} Star;
+
+typedef struct {
+  char    name[50];
+  int     Nunique, Nstars;
+  int     fixed, empty;
+  Star   *first_this_image;
+  double  Mcal, dMcal;
+  double  exptime, airmass, clouds, Mtime, AmF, dAmF, JD;
+  double  RA_O, RA_X, RA_Y, DEC_O, DEC_X, DEC_Y;
+  double  McalR, McalD, McalR2, McalD2, McalRD;
+} Image;
+
+typedef struct {
+  double  Mrel, dMrel;
+  int     Nmeasurements;
+  Star   *first_this_unique;
+} Unique;
+
+
+/******************** PROTOTYPES ********************/
+void args             PROTO((int, char **));
+void get_names        PROTO((Image **, int  *));
+void get_sources      PROTO((Star **, int *));
+void get_stars        PROTO((Star  **, int  *, Image  *, int));
+void sort_stars       PROTO((int  **, Star *, int));
+void get_unique       PROTO((Unique **, int    *, Star *, int *, int, Star *, int));
+void count_unique     PROTO((Image *, int, int));
+void set_Mcal         PROTO((Image *, int));
+void get_Mrel         PROTO((Unique *, Image *, int)); 
+void get_Mcal         PROTO((Image *, Unique *, int));
+void ChiSquare        PROTO((Unique *, Image *, int, int));
+void get_Alam         PROTO((Unique *, Image *, int, int));
+void alter_headers    PROTO((Image *, int));
+void make_table       PROTO((Star *, int, Unique *, Image *, int));
+void get_info         PROTO((Image *));
+char *nextword        PROTO((char *));
+
+extern double hypot PROTO((double, double));
+
Index: /trunk/Ohana/src/lightcurve/src/ChiSquare.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/ChiSquare.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/ChiSquare.c	(revision 2490)
@@ -0,0 +1,30 @@
+# include "lightcurve.h"
+
+void ChiSquare (unique, images, Nunique, Nimages)
+Unique    *unique;
+Image     *images;
+int        Nunique;
+int        Nimages;
+{
+
+  int    i, j;
+  Star   *this_star;
+  double m, dm, Mcal, Mrel, ChiSquare, Ndof;
+
+  Ndof = ChiSquare = 0.0;
+  for (i = 0; i < Nunique; i ++) {
+    this_star = unique[i].first_this_unique;
+    for (j = 0; j < unique[i].Nmeasurements; j ++) {
+      dm   = this_star[0].dm;
+      m    = this_star[0].m;
+      Mcal = images[this_star[0].image_number].Mcal;
+      Mrel = unique[i].Mrel;
+      Ndof += 1.0;
+      ChiSquare += SQ (m - Mcal - Mrel) / SQ (dm);
+      this_star = this_star[0].next_this_unique;
+    }
+  }
+  Ndof = Ndof - Nunique - Nimages;
+  fprintf (stderr, "Chi Square %9.2f  Ndof %6.0f  Reduced %6.3f  A_LAMBDA  %6.4f\n", 
+	   ChiSquare, Ndof, ChiSquare/Ndof, A_LAMBDA);
+}
Index: /trunk/Ohana/src/lightcurve/src/alter_headers.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/alter_headers.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/alter_headers.c	(revision 2490)
@@ -0,0 +1,57 @@
+# include "relphot.h"
+
+void alter_headers  (images, Nimages)
+Image  *images;
+int     Nimages;
+{
+
+  int i;
+  Header header;
+  char line[1000], head[1000];
+  double clouds;
+  FILE *f;
+
+  if (!strcmp(IMFILE, "-")) {
+    fprintf (stderr, "using stderr\n");
+    f = stderr;
+  }
+  else {
+    fprintf (stderr, "using %s for image stats\n", IMFILE);
+    f = fopen (IMFILE, "w");
+    if (f == NULL) {
+      fprintf (stderr, "could not open output file, using stderr\n");
+      f = stderr;
+    }
+  }
+  
+  fprintf (f, "# name                Mcal    dMcal   [time]  airmass   clouds <ap-fit> Nstars  Nunique  fixed  empty\n");
+  for (i = 0; i < Nimages; i++) {
+    strcpy (head, images[i].name);
+    strcpy (strchr(head, '.'), ".head");
+    fits_read_header (head, &header);
+
+    sprintf (line, "mv %s %s~\0", head, head);
+    system (line);
+
+    images[i].clouds = images[i].Mcal + C_LAMBDA - A_LAMBDA*images[i].airmass + images[i].AmF;
+
+    fprintf (f, "%s  %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f  %6d   %6d      %1d      %1d\n",  
+	     images[i].name, images[i].Mcal, images[i].dMcal, images[i].Mtime, 
+	     images[i].airmass, images[i].clouds, images[i].AmF, images[i].Nstars, 
+	     images[i].Nunique, images[i].fixed, images[i].empty);
+
+    fits_modify (&header, "Mcal",   "%lf", 1, images[i].Mcal);
+    fits_modify (&header, "dMcal",  "%lf", 1, images[i].dMcal);
+    fits_modify (&header, "clouds", "%lf", 1, images[i].clouds);
+    fits_modify (&header, "NMcal",  "%d", 1,  images[i].Nstars);
+
+    fits_modify (&header, "Mcal",   "%C", 1, "relphot: calibration magnitude");
+    fits_modify (&header, "dMcal",  "%C", 1, "relphot: calibration error");
+    fits_modify (&header, "clouds", "%C", 1, "relphot: cloud level");
+    fits_modify (&header, "NMcal",  "%C", 1, "relphot: number of stars");
+
+    fits_write_header (head, &header);
+    fits_free_header (&header);
+  }
+  fclose (f);
+}
Index: /trunk/Ohana/src/lightcurve/src/args.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/args.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/args.c	(revision 2490)
@@ -0,0 +1,78 @@
+# include "lightcurve.h"
+# define NARGS 1
+
+void args (argc, argv)
+int      argc;
+char   **argv;
+{
+  
+  int N;
+
+  /** mandatory arguments (see help.c) **/
+  if (N = get_argument (argc, argv, "-P")) {
+    remove_argument (N, &argc, argv);
+    RADIUS = atof (argv[N]);
+    PIXELS = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  else {
+    if (N = get_argument (argc, argv, "-A")) {
+      remove_argument (N, &argc, argv);
+      RADIUS = atof (argv[N]) / 3600.0;
+      PIXELS = FALSE;
+      remove_argument (N, &argc, argv);
+    }
+    else 
+      help (argv[0]);
+  }
+  
+  if (N = get_argument (argc, argv, "-im")) {
+    remove_argument(N, &argc, argv);
+    strcpy (IMAGES, argv[N]);
+    remove_argument(N, &argc, argv);
+  }
+  else
+    help (argv[0]);
+
+  /**** optional arguments (see help.c) ****/
+  if (N = get_argument (argc, argv, "-o")) {
+    remove_argument(N, &argc, argv);
+    strcpy (OUTFILE, argv[N]);
+    remove_argument(N, &argc, argv);
+  }
+  else
+    strcpy (OUTFILE, "-");
+
+  if (N = get_argument (argc, argv, "-midas")) {
+    remove_argument(N, &argc, argv);
+    MIDAS = TRUE;
+  }
+  else
+    MIDAS = FALSE;
+
+  if (N = get_argument (argc, argv, "-m")) {
+    remove_argument(N, &argc, argv);
+    MCUTOFF = atof(argv[N]);
+    remove_argument(N, &argc, argv);
+  }
+  else 
+    MCUTOFF = 0.05;
+
+  if (N = get_argument (argc, argv, "-X")) {
+    remove_argument(N, &argc, argv);
+    EXTRASTARS = TRUE;
+  }
+  else 
+    EXTRASTARS = FALSE;
+
+  if (remove_argument(get_argument (argc, argv, "-h"), &argc, argv) ||
+      remove_argument(get_argument (argc, argv, "-help"), &argc, argv))
+    help(argv[0]);
+
+  if (argc != NARGS) {
+    fprintf (stderr,  "%s%s%s", "USAGE: ", 
+	     argv[0], " (-P / -A) radius  (-im images) [-o file] [-midas]\n");
+    exit (0);
+  }
+}
+
Index: /trunk/Ohana/src/lightcurve/src/count_unique.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/count_unique.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/count_unique.c	(revision 2490)
@@ -0,0 +1,23 @@
+# include "lightcurve.h"
+
+void count_unique (images, Nimages, Nstars)
+Image *images;
+int    Nimages; 
+int    Nstars;
+{
+
+  int i, j;
+  Star *this_star;
+
+  for (i = 0; i < Nimages; i++) {
+    images[i].Nunique = 0;
+    this_star = images[i].first_this_image;
+    for (j = 0; j < images[i].Nstars; j++) {
+      if (this_star[0].unique_number != EMPTY)
+	images[i].Nunique ++;
+      this_star = this_star[0].next_this_image;
+    }
+  }
+}
+
+    
Index: /trunk/Ohana/src/lightcurve/src/fix_header.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/fix_header.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/fix_header.c	(revision 2490)
@@ -0,0 +1,59 @@
+# include "lightcurve.h"
+
+/* this repairs headers screwed up in the very specific way of 
+   astro_again: not 80 chars per line on new lines, and no padding
+   of the buffer.
+
+*/
+
+void
+  fix_header 
+  (Header     *header)
+{
+
+  int i, j, Nbytes, N;
+  char *p1, *p2;
+
+  Nbytes = 2880 * (int) (header[0].size / 2880 + 1);
+  reallocate (header[0].buffer, char, Nbytes);
+  bzero (&header[0].buffer[header[0].size], Nbytes - header[0].size - 1);
+
+  p1 = header[0].buffer - 1;
+  p2 = strchr (p1 + 1, RETURN);
+
+  while (p2 != NULL) {
+    if ((N = p2 - p1) != 80) {
+      bcopy (p2, p1 + 80, header[0].size - (p2 - header[0].buffer));
+      for (i = 0; i < 80 - N; i++) {
+	*(p2 + i) = ' ';
+      }
+      header[0].size += 80 - N;
+    }
+    p1 = strchr (p1 + 1, RETURN);
+    p2 = strchr (p1 + 1, RETURN);
+  }
+
+  header[0].size = Nbytes;
+  p1 = fits_header_field (header, "END", 1);
+  for (i = 3; i < 79; i++) 
+    *(p1 + i) = ' ';
+  *(p1 + 79) = RETURN;
+  
+  Nbytes = header[0].size - (p1 - header[0].buffer) - 80;
+  
+  for (i = 0; i < Nbytes; i++) {
+    for (j = 0; j < 79; j++, i++) 
+      *(p1 + i + 80) = '.';
+    *(p1 + i + 80) = RETURN;
+  }
+
+  Nbytes = header[0].size - (p1 - header[0].buffer) - 80;
+  while (Nbytes >= 2880) {
+    header[0].size -= 2880;
+    Nbytes = header[0].size - (p1 - header[0].buffer) - 80;
+  }
+
+  reallocate (header[0].buffer, char, header[0].size);
+}
+
+
Index: /trunk/Ohana/src/lightcurve/src/get_Alam.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_Alam.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_Alam.c	(revision 2490)
@@ -0,0 +1,47 @@
+# include "lightcurve.h"
+
+void get_Alam (unique, images, Nunique, Nimages)
+Unique    *unique;
+Image     *images;
+int        Nunique;
+int        Nimages;
+{
+
+  int    i, j;
+  Star   *this_star;
+  double m, dm, Mcal, Mrel, Alm, R, zeta, clouds;
+  double Clouds, dClouds, R2, N;
+
+  R = R2 = N = 0.0;
+  for (i = 0; i < Nimages; i++) {
+    images[i].clouds = images[i].Mcal + C_LAMBDA - A_LAMBDA * images[i].airmass + images[i].AmF;
+    if (!images[i].empty && images[i].fixed) {
+      R  +=     images[i].clouds;
+      R2 += SQ (images[i].clouds);
+      N  += 1.0;
+    }
+  }
+
+  Clouds  = R / N;
+  dClouds = sqrt (R2 / N - Clouds*Clouds);
+  dClouds = MAX (0.0001, dClouds);
+
+  R = Alm = 0.0;
+  for (i = 0; i < Nunique; i ++) {
+    this_star = unique[i].first_this_unique;
+    for (j = 0; j < unique[i].Nmeasurements; j ++) {
+      dm   = this_star[0].dm;
+      m    = this_star[0].m;
+      Mrel = unique[i].Mrel;
+      zeta = images[this_star[0].image_number].airmass;
+      clouds = images[this_star[0].image_number].clouds;
+      if (fabs(clouds - Clouds) > SIG*dClouds) {
+	R   +=   zeta / SQ(dm);
+	Alm += zeta * (m + C_LAMBDA - clouds - Mrel) / SQ (dm);
+      }
+      this_star = this_star[0].next_this_unique;
+    }
+  }
+  if (R > 0) 
+    A_LAMBDA = (9.0*A_LAMBDA + Alm / R) / 10.0;
+}
Index: /trunk/Ohana/src/lightcurve/src/get_Mcal.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_Mcal.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_Mcal.c	(revision 2490)
@@ -0,0 +1,43 @@
+# include "lightcurve.h"
+
+void get_Mcal (images, unique, Nimages)
+Image  *images;
+Unique *unique;
+int     Nimages;
+{
+  
+  int    i, j;
+  Star  *this_star;
+  double m, dm, Mrel, r, R, M, M2, N;
+  
+  for (i = 0; i < Nimages; i++) {
+    N = M = M2 = R = 0;
+    this_star = images[i].first_this_image;
+    for (j = 0; j < images[i].Nstars; j++) {
+      if (this_star[0].unique_number != EMPTY) {
+	dm   = this_star[0].dm;
+	m    = this_star[0].m;
+	Mrel = unique[this_star[0].unique_number].Mrel;
+	r    = 1.0 / (dm*dm);
+	R   += r;
+	M   +=    (m - Mrel) * r;
+	M2  +=  SQ(m - Mrel) * r;
+	N   += 1.0;
+      }
+      this_star = this_star[0].next_this_image;
+    }
+    if (R != 0) {
+      images[i].Mcal  = M / R;
+      images[i].dMcal = sqrt(fabs(M2 / R - SQ(M/R))) / sqrt (N);
+    }
+    else {
+      /* no multiple detections on this image! */
+      images[i].empty = TRUE;
+      images[i].Mcal  = 9.999;
+      images[i].dMcal = 9.999;
+    }
+  }
+}
+
+/* m (instrumental) = Mrel (star) + Mcal (image) */
+
Index: /trunk/Ohana/src/lightcurve/src/get_Mrel.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_Mrel.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_Mrel.c	(revision 2490)
@@ -0,0 +1,46 @@
+# include "relphot.h"
+
+void get_Mrel (unique, images, Nunique)
+Unique   *unique;
+Image    *images;
+int       Nunique;
+{
+  
+  int    i, j;
+  Star  *this_star;
+  double dm, m, r, R, M, M2, Mcal, N;
+
+  for (i = 0; i < Nunique; i++) {
+    N = M = M2 = R = 0;
+    this_star = unique[i].first_this_unique;
+    for (j = 0; j < unique[i].Nmeasurements; j ++) {
+      dm   = this_star[0].dm;
+      m    = this_star[0].m;
+      Mcal = images[this_star[0].image_number].Mcal;
+      r    = 1.0 / (dm*dm);
+      R   += r;
+      M   +=    (m - Mcal) * r;
+      M2  +=  SQ(m - Mcal) * r;
+      N   += 1.0;
+      this_star = this_star[0].next_this_unique;
+    }
+    unique[i].Mrel  = M / R;
+    unique[i].dMrel = sqrt(fabs(M2 / R - SQ(M/R))) / sqrt (N);
+  }
+
+  for (i = 0; i < Nunique; i++) {
+    N = X2 = 0;
+    Mrel = unique[i].Mrel;
+    this_star = unique[i].first_this_unique;
+    for (j = 0; j < unique[i].Nmeasurements; j ++) {
+      dm   = this_star[0].dm;
+      m    = this_star[0].m;
+      Mcal = images[this_star[0].image_number].Mcal;
+      X2  += SQ((m - Mcal - Mrel) / dm);
+      this_star = this_star[0].next_this_unique;
+    }
+    unique[i].ChiSq = X2 / (N - 1);
+  }
+}
+
+/* m (instrumental) = Mrel (star) + Mcal (image) */
Index: /trunk/Ohana/src/lightcurve/src/get_argument.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_argument.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_argument.c	(revision 2490)
@@ -0,0 +1,19 @@
+# include "lightcurve.h"
+
+int get_argument (argc, argv, arg)
+int    argc;
+char **argv;
+char  *arg;
+{
+
+  int i;
+
+  for (i = 0; i < argc; i++) {
+    if (!strcmp(argv[i], arg))
+      return (i);
+  }
+  
+  return ((int)NULL);
+}
+
+
Index: /trunk/Ohana/src/lightcurve/src/get_info.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_info.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_info.c	(revision 2490)
@@ -0,0 +1,128 @@
+# include "lightcurve.h"
+
+void  get_info (images)
+Image *images;
+{
+
+  char head[500], line[500];
+  Header header;
+  int i, status;
+  double jd, days, hrs, min, sec, atof();
+
+  status = TRUE;
+
+  strcpy (head, images[0].name);
+  strcpy (strchr(head, '.'), ".head");
+
+  status = fits_read_header (head, &header);
+  if (!status) {
+    fprintf (stderr, "could not open header file %s\n", head);
+    exit (0);
+  }
+  status = TRUE;
+
+  switch (PIXELS) {
+  case 0:
+    status &= fits_scan (&header, "RA_O",    "%lf", 1, &images[0].RA_O);
+    status &= fits_scan (&header, "RA_X",    "%lf", 1, &images[0].RA_X);
+    status &= fits_scan (&header, "RA_Y",    "%lf", 1, &images[0].RA_Y);
+    status &= fits_scan (&header, "DEC_O",   "%lf", 1, &images[0].DEC_O);
+    status &= fits_scan (&header, "DEC_X",   "%lf", 1, &images[0].DEC_X);
+    status &= fits_scan (&header, "DEC_Y",   "%lf", 1, &images[0].DEC_Y);
+    COS = cos (RAD_DEG * images[0].DEC_O);
+    break;
+
+  case 1:
+    status &= fits_scan (&header, "X_O",    "%lf", 1, &images[0].RA_O);
+    status &= fits_scan (&header, "X_X",    "%lf", 1, &images[0].RA_X);
+    status &= fits_scan (&header, "X_Y",    "%lf", 1, &images[0].RA_Y);
+    status &= fits_scan (&header, "Y_O",    "%lf", 1, &images[0].DEC_O);
+    status &= fits_scan (&header, "Y_X",    "%lf", 1, &images[0].DEC_X);
+    status &= fits_scan (&header, "Y_Y",    "%lf", 1, &images[0].DEC_Y);
+    COS = 1;
+    break;
+  }
+  
+  fits_scan (&header, "ORIGIN", "%s", 1, line);
+  /* interpret the silly way ESO / La Palma stores exposure time and duration   */
+  if (!strcmp (line, "ESO-MIDAS")) { 
+    status &= fits_scan (&header, "DATE-OBS", "%s", 1, line);
+    stripwhite (line);
+    fprintf (stderr, "date line: %s\n", line);
+    line[2] = 0;
+    jd = atof(line);
+    line[0] = 0;
+    status = fits_scan (&header, "TM-START", "%lf", 1, &sec);
+    fprintf (stderr, "date: %f, sec: %f\n", jd, sec);
+    jd += (sec/86400.0) + 0.5;
+    images[0].JD =  jd;
+    fits_scan (&header, "EXPTIME", "%lf", 1, &images[0].exptime);
+  }
+  else {
+    status &= fits_scan (&header, "JD", "%lf", 1, &images[0].JD);
+    images[0].JD -= 2400000.5;   /* convert to MJD */
+    fits_scan (&header, "EXPTIME", "%lf", 1, &images[0].exptime);
+  }
+
+  status &= fits_scan (&header, "Mcal", "%lf", 1, &images[0].Mcal);
+  status &= fits_scan (&header, "McalR", "%lf", 1, &images[0].McalR);
+  status &= fits_scan (&header, "McalD", "%lf", 1, &images[0].McalD);
+  status &= fits_scan (&header, "McalR2", "%lf", 1, &images[0].McalR2);
+  status &= fits_scan (&header, "McalD2", "%lf", 1, &images[0].McalD2);
+  status &= fits_scan (&header, "McalRD", "%lf", 1, &images[0].McalRD);
+  status &= fits_scan (&header, "dMcal", "%lf", 1, &images[0].dMcal);
+
+  images[0].airmass = 1000;  
+  fits_scan (&header, "SECZ", "%lf", 1, &images[0].airmass);
+  fits_scan (&header, "AIRMASS", "%lf", 1, &images[0].airmass);
+  /* a stupid value as a flag (i hate flags!) but fits_scan will not alter the
+     value if it fails to find the entry.  try a couple possibilities */
+ 
+  fprintf (stderr, "%s: %10.6f %10.6f  %lf  %6.3f %8.2f %5.2f\n", 
+	   head, images[0].RA_O, images[0].DEC_O, images[0].JD, 
+	   images[0].Mcal, images[0].exptime, images[0].airmass);
+   
+  if (!status) {
+    fprintf (stderr, "error getting header info from %s\n", head);
+    exit(0);
+  }
+
+  if (images[0].airmass > 10) {
+    images[0].airmass = 1.1;
+    fprintf (stderr, "warning: no airmass info\n");
+  }
+  
+  images[0].Nstars  = 0;
+  images[0].fixed   = TRUE;
+  images[0].empty   = FALSE;
+  images[0].Mtime   = 2.5*log10(images[0].exptime);
+  images[0].clouds  = 0.0;
+
+  fits_free_header (&header);
+  
+}
+
+
+
+/* airmass formula (only used if needed) */
+/* page 264 of Kitchin */
+
+/*    z = 1 / ( .5294258 * sin(pi * d / 180.0) + .84835625 * cos(pi * d / 180.0) *
+ cos(pi * h / 12.0));
+
+n
+p status
+
+*/
+
+
+/*
+   code for using RA, DEC, ST info, if needed. 
+    status &= fits_scan (&header, "ST", "%lf", 1, &LST);
+    ra  =  info[0].RA_O  + info[0].RA_X *CCD_X/2.0 + info[0].RA_Y *CCD_Y/2.0;
+    dec =  info[0].DEC_O + info[0].DEC_X*CCD_X/2.0 + info[0].DEC_Y*CCD_Y/2.0;
+    temp1 = sin(OBS_LAT*DEG_RAD)*sin(dec*DEG_RAD);
+    temp2 = cos(OBS_LAT*DEG_RAD)*cos(dec*DEG_RAD);
+    temp3 = cos(((360./24.)*LST - ra)*DEG_RAD);
+    (info[0].airmass) = 1.0 / (temp1 + temp2*temp3);
+*/
Index: /trunk/Ohana/src/lightcurve/src/get_names.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_names.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_names.c	(revision 2490)
@@ -0,0 +1,34 @@
+# include "lightcurve.h"
+# define D_NIMAGE 200
+  
+void get_names (images, Nimages)
+Image **images;
+int   *Nimages;
+{
+  
+  int N, i;
+  char line[500];
+  FILE *f;
+
+  f = fopen (IMAGES, "r"); 
+  if (f == NULL) { 
+    fprintf (stderr, "failed to open %s\n", IMAGES); 
+    exit (0); 
+  }
+  N = D_NIMAGE;
+  ALLOCATE (images[0], Image, N);
+
+  for (i = 0; (fscanf (f, "%s", line) != EOF); i++) { 
+    strcpy (images[0][i].name, line);
+    strcpy (strchr(images[0][i].name, '.'), ".obj_out");
+    if (i == N - 1) {
+      N += D_NIMAGE;
+      REALLOCATE (images[0], Image, N);
+    }
+  }
+  *Nimages = i;
+  fprintf (stderr, "Nimages: %d\n", *Nimages);
+  fclose (f);
+}
+
+
Index: /trunk/Ohana/src/lightcurve/src/get_sources.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_sources.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_sources.c	(revision 2490)
@@ -0,0 +1,25 @@
+# include "lightcurve.h"
+# define D_NSOURCES 200
+
+void get_sources (sources, Nsources)
+Star  **sources;
+int    *Nsources;
+{
+  
+  int N, i;
+
+  ALLOCATE (sources[0], Star, D_NSOURCES);
+
+  for (i = 0; (fscanf (stdin, "%lf %lf", &sources[0][i].RA, &sources[0][i].Dec) != EOF); i++) { 
+    sources[0][i].unique_number = EMPTY;
+    if (i == D_NSOURCES - 1) {
+      fprintf (stderr, "No More Sources: %d\n", i);
+      break;
+    }
+  }
+  *Nsources = i;
+  fprintf (stderr, "Nsources: %d\n", *Nsources);
+}
+
+
+  
Index: /trunk/Ohana/src/lightcurve/src/get_stars.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_stars.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_stars.c	(revision 2490)
@@ -0,0 +1,99 @@
+# include "lightcurve.h"
+# define D_NSTARS 1000
+
+void get_stars (stars, Nstars, images, Nimages)
+Star  **stars;
+int    *Nstars;
+Image   images[];
+int     Nimages;
+{
+
+  double type, mag, dmag, X, Y, ap, dap, AmF, A, A2, S;
+  int i, j, image_number;
+  int NSTARS, status, n, nperf;
+  FILE *f;
+  char line[200];
+
+  j = 0;
+  NSTARS = D_NSTARS;
+  ALLOCATE (stars[0], Star, NSTARS);
+
+  for (i = 0; i < Nimages; i++) { 
+    
+    get_info (&images[i]);
+    f = fopen (images[i].name, "r"); 
+    if (f == NULL) { 
+      fprintf (stderr, "failed to open %s\n", images[i].name); 
+      exit (0); 
+    }
+    nperf = A = A2 = S = 0;
+    for (n = 0; scan_line (f, line) != EOF; n++) {
+      status = TRUE;
+      status &= dparse (&type, 2, line);
+      status &= dparse (&X,    3, line);
+      status &= dparse (&Y,    4, line);
+      status &= dparse (&mag,  5, line);
+      status &= dparse (&dmag, 6, line);
+      status &= dparse (&ap,  12, line);
+      status &= dparse (&dap, 13, line);
+      status &= dparse (&AmF, 15, line);
+      if (!status) {
+	fprintf (stderr, "error on line %d in file %s\n", n, images[i].name);
+	continue;  /* go on to the next line */
+      }
+      stars[0][j].ap = 0;
+      if (ap < 99) {
+	nperf ++;
+	A  += AmF/SQ(dap);
+	A2 += SQ(AmF)/SQ(dap);
+	S  += 1.0/SQ(dap);
+	stars[0][j].ap = ap;    /* if the ap mag is good, use it, not the <ap-fit> adjusted value */
+      }
+      if ((dmag < MCUTOFF) && ((type == 1) || (EXTRASTARS && ((type == 2) || (type == 3) || (type == 4) || (type == 5) || (type == 7))))) {  /* for now, this uses only type 1s */
+	stars[0][j].RA  = images[i].RA_O  + X*images[i].RA_X  + Y*images[i].RA_Y;
+	stars[0][j].Dec = images[i].DEC_O + X*images[i].DEC_X + Y*images[i].DEC_Y;
+	stars[0][j].m   = mag + images[i].Mtime;
+	stars[0][j].dm  = sqrt (SQ(dmag) + SQ(images[i].dMcal));
+	
+	stars[0][j].next_this_unique = NULL;
+	stars[0][j].image_number     = i;
+	stars[0][j].star_number      = n;
+	stars[0][j].unique_number    = EMPTY;
+	
+	if (j == NSTARS - 1) {
+	  NSTARS += D_NSTARS;
+	  fprintf (stderr, "!");
+	  REALLOCATE (stars[0], Star, NSTARS);
+	}
+	j ++;
+	images[i].Nstars ++;   /* this is set to 0 in "get_info" */
+      }
+    }
+    if (nperf > 2) {
+      images[i].AmF = A / S;
+      images[i].dAmF = sqrt(A2/S - A*A/SQ(S));
+    }
+    else {
+      images[i].AmF = 0.0;
+      images[i].dAmF = 0.0;
+    }     
+    fclose (f);
+/*    images[i].Mcal    = - C_LAMBDA + A_LAMBDA*images[i].airmass - images[i].AmF; */
+    stars[0][j - 1].next_this_image = NULL;
+  }
+  
+  image_number = 0;
+  for (i = 0; i < j; ) {
+    images[image_number].first_this_image = &stars[0][i];
+    for (i++; ((stars[0][i].image_number == image_number) && (i < j)); i++)  {
+      stars[0][i - 1].next_this_image = &stars[0][i];
+    }
+    stars[0][i - 1].next_this_image = NULL;
+    image_number = stars[0][i].image_number;
+  }
+
+  *Nstars = j;
+  fprintf (stderr, "Nstars: %d\n", *Nstars);
+}
+
+  
Index: /trunk/Ohana/src/lightcurve/src/get_unique.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/get_unique.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/get_unique.c	(revision 2490)
@@ -0,0 +1,186 @@
+# include "lightcurve.h"
+# define D_NUNIQUE 1000;
+
+void get_unique (unique, N, stars, radec, Nstars, sources, Nsources)
+Unique **unique;
+int    *N;
+Star   *stars;
+int    *radec;
+int     Nstars;
+Star   *sources;
+int     Nsources;
+{
+
+  int i, j, link, k, n, confused, Nchain, NUNIQUE, Nunique, first, NTEMP;
+  int Ntemp, Nclump, Nblobs;
+  Unique  temp_unique;
+  int    *templist;
+  Star   *next_unique, *this_unique;
+  double radius, dRA, dDec, RAo, DECo, dRA2, dDec2;
+  double dRo, dDo, dRo2, dDo2;
+
+  NUNIQUE = D_NUNIQUE;
+  ALLOCATE (unique[0], Unique, NUNIQUE);
+  NTEMP = 100;
+  ALLOCATE (templist, int, NTEMP);  
+  Nblobs = dRo = dDo = dRo2 = dDo2 = 0;
+
+  for (i = Nunique = 0; (i < Nstars - 1); i++) {
+    
+    /* check if this star is not already assigned to a clump */
+    if (stars[radec[i]].next_this_unique == NULL) {
+      
+      /* first, find all stars within 2*RADIUS of this star */
+      first = i;
+      Ntemp = 1;
+      dRA = 0;
+      templist[0] = radec[first];  
+      for (j = first + 1; (dRA <= 2.0*RADIUS) && (j < Nstars); j++) {
+	if (stars[radec[j]].next_this_unique != NULL)
+	  continue;
+	dRA  = COS * (stars[radec[j]].RA - stars[radec[first]].RA);  
+	dDec = stars[radec[j]].Dec - stars[radec[first]].Dec;
+	radius = hypot(dRA, dDec);
+	if (radius < 2.0*RADIUS) {
+	  /* add to templist: */
+	  templist[Ntemp] = radec[j];
+	  Ntemp ++;
+	  if (Ntemp == NTEMP - 1) {
+	    NTEMP += 100;
+	    REALLOCATE (templist, int, NTEMP); 
+	  }
+	}
+      }
+	     
+      if (Ntemp < 3) {
+	continue; /* check this pops out of the right level... */
+      }
+
+      /* next, find the centroid of this subset of stars */
+      dRA = dDec = dRA2 = dDec2 = 0;
+      for (j = 0; j < Ntemp; j++) {
+	dRA   += stars[templist[j]].RA;
+	dDec  += stars[templist[j]].Dec;
+	dRA2  += SQ(stars[templist[j]].RA);
+	dDec2 += SQ(stars[templist[j]].Dec);
+      }
+      RAo   = dRA / (double)Ntemp;
+      DECo  = dDec / (double)Ntemp;
+      dRA2  = sqrt(dRA2 / (double)Ntemp - SQ(RAo));
+      dDec2 = sqrt(dDec2 / (double)Ntemp - SQ(DECo));
+
+      /* then, find all stars within 1 RADIUS of this centroid */
+      Nclump = 0;
+      unique[0][Nunique].first_this_unique = (Star *) NULL;
+      for (j = 0; j < Ntemp; j++) {
+	dRA  = COS * (stars[templist[j]].RA - RAo);
+	dDec = stars[templist[j]].Dec - DECo;
+	radius = hypot(dRA, dDec);
+	if (radius < RADIUS) {
+	  if (Nclump != 0) {
+	    this_unique[0].next_this_unique = &stars[templist[j]];
+	    this_unique = &stars[templist[j]];
+	    this_unique[0].unique_number = Nunique;
+	  }
+	  else {
+	    unique[0][Nunique].first_this_unique = &stars[templist[j]];
+	    this_unique = &stars[templist[j]];
+	    this_unique[0].unique_number = Nunique;
+	  }
+	  Nclump ++;
+	}
+      }
+      
+      /* if too few in clump, eliminate, move on */
+      if (Nclump < 5) {
+	this_unique = unique[0][Nunique].first_this_unique;
+	unique[0][Nunique].first_this_unique = NULL;
+	while (this_unique != NULL) {
+	  next_unique = this_unique[0].next_this_unique;
+	  this_unique[0].unique_number = EMPTY;
+	  this_unique[0].next_this_unique = NULL;
+	  this_unique = next_unique;
+	}
+	continue;
+      }
+
+      /* count number of confused stars...
+      this_unique = unique[0][Nunique].first_this_unique;
+      for (j = 0, confused = FALSE; j < Nclump - 1; j++) {
+	next_unique = this_unique[0].next_this_unique;
+	for (k = j + 1; k < Nclump; k++) {
+	  if (this_unique[0].image_number == next_unique[0].image_number) {
+	    confused = TRUE;
+	  }
+	  next_unique = next_unique[0].next_this_unique;
+	}
+	this_unique = this_unique[0].next_this_unique;
+      } 
+       */
+
+      /* if this object is confused, ignore it and move on.  
+	 keep the "next_this_unique" values on, but remove
+	 the "unique_number" */
+
+      /*
+      
+      if (confused) {
+	this_unique = unique[0][Nunique].first_this_unique;
+	unique[0][Nunique].first_this_unique = NULL;
+	while (this_unique != NULL) {
+	  this_unique[0].unique_number = EMPTY;
+	  this_unique = this_unique[0].next_this_unique;
+	}
+	Nblobs ++;
+	continue;
+      }
+      */
+      
+      this_unique = unique[0][Nunique].first_this_unique;
+      for (j = 0; j < Nclump; j++) {
+	dRA   += this_unique[0].RA;
+	dDec  += this_unique[0].Dec;
+	dRA2  += SQ(this_unique[0].RA);
+	dDec2 += SQ(this_unique[0].Dec);
+	next_unique = this_unique[0].next_this_unique;
+      }
+      RAo   = dRA / (double)Nclump;
+      DECo  = dDec / (double)Nclump;
+      for (n = 0; n < Nsources; n++) {
+	dRA = COS * (RAo - sources[n].RA);
+	dDec = (DECo - sources[n].Dec);
+	radius = hypot(dRA, dDec);
+	if (radius < RADIUS) {
+	  sources[n].unique_number = Nunique;
+	  fprintf (stderr, "%d %d  %f %f  %f %f\n", 
+		   n, Nunique, RAo, DECo, sources[n].RA, sources[n].Dec);
+	  break;
+	}
+      } 
+      
+      unique[0][Nunique].Nmeasurements = Nclump;
+      unique[0][Nunique].Mrel = 0.0;
+      /* use only stars which show up on all images */
+      
+      dRo += dRA2;
+      dDo += dDec2;
+      dRo2 += dRA2*dRA2;
+      dDo2 += dDec2*dDec2;
+      Nunique ++;
+      if (Nunique == NUNIQUE - 1) { 
+	NUNIQUE += D_NUNIQUE;
+	REALLOCATE(unique[0], Unique, NUNIQUE);
+      }
+    }
+  } 
+
+  *N = Nunique;
+  dRo = dRo / (double)Nunique;
+  dDo = dDo / (double)Nunique;
+  dRo2 = sqrt(dRo2 / (double)Nunique - SQ(dRo));
+  dDo2 = sqrt(dDo2 / (double)Nunique - SQ(dDo));
+
+  fprintf (stderr, "%f   %f %f %f %f   %4d %3d\n", 3600*RADIUS, dRo, dDo, dRo2, dDo2, Nunique, Nblobs);
+
+}
+
Index: /trunk/Ohana/src/lightcurve/src/help.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/help.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/help.c	(revision 2490)
@@ -0,0 +1,25 @@
+# include "lightcurve.h"
+
+void
+help (name)
+char name[];
+{
+  
+  fprintf (stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+	   "USAGE: ", name, " (-P / -A) radius  \n",
+	   "\n",
+           "  Mandatory Flags:\n",
+           "  -P / -A      one of these must be used: \n",
+           "    -P  pixs     radius of search in pixels -- uses relative astrometry (rastro)\n",
+           "    -A  asec     radius of search in arcsec -- uses absolute astrometry  (astro)\n",
+           "  -im images   file with the list of images to use\n",
+           "\n",
+           "  Optional Flags:\n",
+           "  -o  file  output file for star data\n",
+           "  -midas    use MIDAS format time info from headers\n"
+           "  -h        print this list\n\n",
+	   "  ", name, " expects a series of (Ra,Dec) or (X,Y) pairs\n\n");
+  
+  exit (0);
+  
+}
Index: /trunk/Ohana/src/lightcurve/src/imstats.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/imstats.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/imstats.c	(revision 2490)
@@ -0,0 +1,46 @@
+# include "lightcurve.h"
+
+void main (argc, argv)
+int argc;
+char **argv;
+{
+  
+  Image   *images;
+  Star    *stars, *sources;
+  Unique  *unique;
+  int     *radec;
+  int      Nimages, Nstars, Nunique, Nsources;
+  int      i, j;
+
+  /*** this still needs to be fixed / updated */
+  args (argc, argv);
+
+  get_names (&images, &Nimages);
+  get_sources (&sources, &Nsources);
+  get_stars  (&stars, &Nstars, images, Nimages);
+  sort_stars (&radec, stars, Nstars);
+
+  get_unique (&unique, &Nunique, stars, radec, Nstars, sources, Nsources);
+
+  make_table (sources, Nsources, unique, images, Nimages);
+  
+}
+
+
+/* 
+   list of system wide variables that are (should be) defined in relphot.h:
+
+   RADIUS  (radius of search in pixels or arcsec)
+   A_LAMBDA (airmass extinction coefficient)
+   C_LAMBDA (zero point C_\lambda)
+   NLOOP   (desired number of interations)
+   SIG     (number of sigma for cloudiness criterion)
+   OUTFILE (output file)
+   PRINT   (print processing info?)
+   PIXELS  (RADIUS in pixels (rastro) or degrees (astro))
+   COS     (RA scaling factor = cos(DEC(center of field)) if astro, 
+                              = 1 if rastro )
+
+*/
+
+   
Index: /trunk/Ohana/src/lightcurve/src/jd.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/jd.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/jd.c	(revision 2490)
@@ -0,0 +1,72 @@
+      SUBROUTINE locate(xx,n,x,j)
+      INTEGER j,n
+      REAL x,xx(n)
+      INTEGER jl,jm,ju
+      jl=0
+      ju=n+1
+10    if(ju-jl.gt.1)then
+        jm=(ju+jl)/2
+        if((xx(n).gt.xx(1)).eqv.(x.gt.xx(jm)))then
+          jl=jm
+        else
+          ju=jm
+        endif
+      goto 10
+      endif
+      j=jl
+      return
+      END
+
+      FUNCTION julday(mm,id,iyyy)
+      INTEGER julday,id,iyyy,mm,IGREG
+      PARAMETER (IGREG=15+31*(10+12*1582))
+      INTEGER ja,jm,jy
+      jy=iyyy
+      if (jy.eq.0) pause 'julday: there is no year zero'
+      if (jy.lt.0) jy=jy+1
+      if (mm.gt.2) then
+        jm=mm+1
+      else
+        jy=jy-1
+        jm=mm+13
+      endif
+      julday=int(365.25*jy)+int(30.6001*jm)+id+1720995
+      if (id+31*(mm+12*iyyy).ge.IGREG) then
+        ja=int(0.01*jy)
+        julday=julday+2-ja+int(0.25*ja)
+      endif
+      return
+      END
+
+function mjd(yr,hr,sc)
+	implicit none
+	integer iyr, mn, n, jd, j, julday, idy
+	real*8 yr,hr,sc,mjd
+	real*4 month(12), dy
+	n = 12
+	data month/0,31,59,90,120,151,181,212,243,273,304,334/
+	iyr = yr
+	if((mod(iyr,4).eq.0.and.mod(iyr,100).ne.0).or.(mod(iyr,400).eq.0)) then
+	  dy = int(366.*(yr-iyr)+.0001) + 1
+	  do j = 3, 12
+	    month(j) = month(j) + 1.
+	  end do
+	else
+	  dy = int(365.*(yr-iyr)+.0001) + 1
+	end if
+c 
+c locate, from Numrec library
+c
+	call locate(month,n,dy,mn)
+	dy = dy - month(mn)
+	idy = dy
+c
+c julday, from Numrec library
+c
+	jd = julday(mn,idy,iyr)
+	mjd = jd - 2440000.5
+	mjd = mjd + hr / 24. + sc / 86400. / 2.
+	end
+
+
+z
Index: /trunk/Ohana/src/lightcurve/src/lightcurve.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/lightcurve.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/lightcurve.c	(revision 2490)
@@ -0,0 +1,46 @@
+# include "lightcurve.h"
+
+void main (argc, argv)
+int argc;
+char **argv;
+{
+  
+  Image   *images;
+  Star    *stars, *sources;
+  Unique  *unique;
+  int     *radec;
+  int      Nimages, Nstars, Nunique, Nsources;
+  int      i, j;
+
+  /*** this still needs to be fixed / updated */
+  args (argc, argv);
+
+  get_names (&images, &Nimages);
+  get_sources (&sources, &Nsources);
+  get_stars  (&stars, &Nstars, images, Nimages);
+  sort_stars (&radec, stars, Nstars);
+
+  get_unique (&unique, &Nunique, stars, radec, Nstars, sources, Nsources);
+
+  make_table (sources, Nsources, unique, images, Nimages);
+  
+}
+
+
+/* 
+   list of system wide variables that are (should be) defined in relphot.h:
+
+   RADIUS  (radius of search in pixels or arcsec)
+   A_LAMBDA (airmass extinction coefficient)
+   C_LAMBDA (zero point C_\lambda)
+   NLOOP   (desired number of interations)
+   SIG     (number of sigma for cloudiness criterion)
+   OUTFILE (output file)
+   PRINT   (print processing info?)
+   PIXELS  (RADIUS in pixels (rastro) or degrees (astro))
+   COS     (RA scaling factor = cos(DEC(center of field)) if astro, 
+                              = 1 if rastro )
+
+*/
+
+   
Index: /trunk/Ohana/src/lightcurve/src/make_table.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/make_table.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/make_table.c	(revision 2490)
@@ -0,0 +1,60 @@
+# include "lightcurve.h"
+
+void make_table (sources, Nsources, unique, images, Nimages)
+Star   *sources;
+int     Nsources;
+Unique *unique;
+Image  *images;
+int     Nimages;
+{
+
+  double  N, M, dM;
+  int     i, j, n, im;
+  Star   *next_measurement;
+  FILE   *f;
+  double  dR, dD;
+
+  if (!strcmp(OUTFILE, "-")) {
+    fprintf (stderr, "using stdout\n");
+    f = stdout;
+  }
+  else {
+    fprintf (stderr, "using %s for output\n", OUTFILE);
+    f = fopen (OUTFILE, "w");
+    if (f == NULL) {
+      fprintf (stderr, "could not open output file, using stdout\n");
+      f = stdout;
+    }
+  }
+  
+  fprintf (f, "# This is a table of data from relphot.\n");
+  fprintf (f, "# This table contains the following data:\n");
+  if (PIXELS) 
+    fprintf (f, "# star number, <X> dX  <Y> dY  <Mrel> dMrel  Nstars\n");
+  else
+    fprintf (f, "# star number, <RA> dRA  <Dec> dDec  <Mrel> dMrel  Nstars\n");
+
+  for (j = 0; j < Nsources; j++) {
+    fprintf (f, "%5d %10.6f %10.6f ", j, sources[j].RA, sources[j].Dec);
+    if (sources[j].unique_number == EMPTY) {
+      fprintf (f, "%5d\n", 0.0);
+      continue;
+    }
+    N = unique[sources[j].unique_number].Nmeasurements;
+    fprintf (f, "%5.0f\n", N);
+    next_measurement = unique[sources[j].unique_number].first_this_unique;
+    M = 100.0; dM = 0.0;
+    for (n = 0; n < N; n++) {
+      im = next_measurement[0].image_number;
+      dR = (next_measurement[0].RA - images[im].RA_O);
+      dD = (next_measurement[0].Dec - images[im].DEC_O);
+      M = next_measurement[0].m - MCAL(images[im], dR, dD);
+      dM = next_measurement[0].dm;
+      dR = (next_measurement[0].RA - sources[j].RA);
+      dD = (next_measurement[0].Dec - sources[j].Dec);
+      fprintf (f, "%-40s  %15.6f  %7.3f %7.3f  %7.3f %7.3f\n", images[im].name, images[im].JD, dR, dD, M, dM);
+      next_measurement = next_measurement[0].next_this_unique;
+    }
+  }
+  fclose (f);
+}
Index: /trunk/Ohana/src/lightcurve/src/match_stars.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/match_stars.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/match_stars.c	(revision 2490)
@@ -0,0 +1,84 @@
+# include "relphot.h"
+# define D_NUNIQUE 1000;
+
+void match_stars (unique, N, stars, radec, Nstars, sources, Nsources)
+Unique **unique;
+int    *N;
+Star   *stars;
+int    *radec;
+int     Nstars;
+Source *sources;
+int     Nsources;
+{
+
+  int i, j, link, k, good, Nchain, NUNIQUE, Nunique;
+  Unique  temp_unique;
+  Star   *next_unique, *this_unique;
+  double radius, dRA, dDec;
+
+  NUNIQUE = D_NUNIQUE;
+  ALLOCATE (unique[0], Unique, NUNIQUE);
+
+  for (i = Nunique = 0; (i < Nstars - 1); i++) {
+    
+    dRA = COS * (stars[radec[i+1]].RA - stars[radec[i]].RA);
+
+    if (dRA < 0.0) {
+      fprintf (stderr, "stars out of order!!!  %d  %d  %f  %f\n", 
+	       radec[i+1], radec[i], stars[radec[i+1]].RA, stars[radec[i]].RA);
+    }
+
+    if ((fabs(dRA) < RADIUS) && (stars[radec[i]].next_this_unique == NULL)) {
+
+      /* set up the chain */
+      for (link = i, j = link + 1, Nchain = 1; (fabs(dRA) < RADIUS) && (j < Nstars); j++) {
+	dDec   = stars[radec[j]].Dec - stars[radec[link]].Dec;
+	radius = hypot(dRA, dDec);
+	if (radius < RADIUS) {
+	  stars[radec[link]].next_this_unique = &stars[radec[j]];
+	  link = j;
+	  Nchain ++;
+	}
+	if (j < Nstars - 1)
+	  dRA  = COS * (stars[radec[j + 1]].RA - stars[radec[link]].RA);
+      }
+
+      /* are any 2 links on the same image? */
+      this_unique = &stars[radec[i]];
+      for (j = 0, good = TRUE; j < Nchain - 1; j++) {
+	next_unique = this_unique[0].next_this_unique;
+	for (k = j + 1; k < Nchain; k++) {
+	  if (this_unique[0].image_number == next_unique[0].image_number) {
+	    good = FALSE;
+	    fprintf (stderr, "clump on image %d, stars %d and %d\n", 
+		     this_unique[0].image_number, 
+		     this_unique[0].star_number, 
+		     next_unique[0].star_number);
+	  }
+	  next_unique = next_unique[0].next_this_unique;
+	}
+	this_unique = this_unique[0].next_this_unique;
+      }
+
+      /* if not, add chain to unique[] */
+      if ((good) && (Nchain > 1)) {
+	this_unique = unique[0][Nunique].first_this_unique = &stars[radec[i]];
+	while (this_unique != NULL) {
+	  this_unique[0].unique_number = Nunique;
+	  this_unique = this_unique[0].next_this_unique;
+	}
+	unique[0][Nunique].Nmeasurements = Nchain;
+	Nunique ++;
+	if (Nunique == NUNIQUE - 1) { 
+	  NUNIQUE += D_NUNIQUE;
+	  REALLOCATE(unique[0], Unique, NUNIQUE);
+	}
+      }
+    }
+  } 
+
+  *N = Nunique;
+  fprintf (stderr, "Nunique: %d\n", Nunique);
+
+}
+
Index: /trunk/Ohana/src/lightcurve/src/mjd.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/mjd.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/mjd.c	(revision 2490)
@@ -0,0 +1,42 @@
+# include "lightcurve.h"
+# define GREG (15+31*(10+12*1582))
+
+double mjd (year, hour, second)
+double year, hour, second;
+{
+
+  int iyear;
+  int Months[] = {0,31,59,90,120,151,181,212,243,273,304,334};
+
+  /* convert year, which contains year + day, into year, month, day */
+  iyear = year;
+  if ((!(iyear % 4) && (iyear % 100)) || !(iyear % 400)) { /* leap year */
+    day = 366*(year - iyear) + 1;
+    for (i = 2; i < 12; i++) 
+      Months[i]++;
+  }
+  else {
+    day = 365*(year - iyear) + 1;
+  }
+  for (i = 0; month[i] < day; i++);
+  month = Months[i-1];
+  
+  if (day + 31*(month + 12*iyear) >= GREG) 
+    extra = 2 - (int)(0.01*jy) + (int)(0.25*((int)(0.01*jy)));
+  else 
+    extra = 0;
+
+  if (year == 0) {
+    fprintf (stderr, "error: there is no year zero\n");
+    exit (0);
+  }
+  if (year < 0) 
+    year += 1.0;
+  if (month > 2) 
+    jmonth = month + 1;
+  else {
+    year -= 1;
+    month += 13;
+  }
+
+  julday = (int)(365.25*year)+int(30.6001*jm)+id+1720995
Index: /trunk/Ohana/src/lightcurve/src/parse.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/parse.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/parse.c	(revision 2490)
@@ -0,0 +1,35 @@
+# include "lightcurve.h"
+
+int parse (X, NX, line)
+double *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else
+    return (TRUE);
+}
+
+
+char *nextword(string)
+char *string;
+{
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (; isspace (*string); string++);
+  for (; (*string != 0) && !isspace (*string); string++);
+  for (; isspace (*string); string++);
+  return (string);
+}
+
Index: /trunk/Ohana/src/lightcurve/src/relphot.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/relphot.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/relphot.c	(revision 2490)
@@ -0,0 +1,57 @@
+# include "lightcurve.h"
+
+void main (argc, argv)
+int argc;
+char **argv;
+{
+  
+  Image   *images;
+  Star    *stars;
+  Unique  *unique;
+  int     *radec;
+  int      Nimages, Nstars, Nunique;
+  int      i, j;
+
+  /*** this still needs to be fixed / updated */
+  args (argc, argv);
+
+  get_names  (&images, &Nimages);
+  get_stars  (&stars, &Nstars, images, Nimages);
+  sort_stars (&radec, stars, Nstars);
+
+  get_unique (&unique, &Nunique, stars, radec, Nstars);
+  count_unique (images, Nimages, Nstars);
+
+  for (i = 0; i < NLOOP; i++) {
+    set_Mcal (images, Nimages);
+    get_Mrel (unique, images, Nunique);
+    get_Mcal (images, unique, Nimages);
+    ChiSquare (unique, images, Nunique, Nimages);
+  }  
+ 
+
+  if (PRINT) {
+    alter_headers (images, Nimages);
+    make_table (unique, images, Nunique);
+  }
+  
+}
+
+
+/* 
+   list of system wide variables that are (should be) defined in relphot.h:
+
+   RADIUS  (radius of search in pixels or arcsec)
+   A_LAMBDA (airmass extinction coefficient)
+   C_LAMBDA (zero point C_\lambda)
+   NLOOP   (desired number of interations)
+   SIG     (number of sigma for cloudiness criterion)
+   OUTFILE (output file)
+   PRINT   (print processing info?)
+   PIXELS  (RADIUS in pixels (rastro) or degrees (astro))
+   COS     (RA scaling factor = cos(DEC(center of field)) if astro, 
+                              = 1 if rastro )
+
+*/
+
+   
Index: /trunk/Ohana/src/lightcurve/src/remove_argument.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/remove_argument.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/remove_argument.c	(revision 2490)
@@ -0,0 +1,21 @@
+# include "lightcurve.h"
+
+int remove_argument (N, argc, argv)
+int    N;
+int   *argc;
+char **argv;
+{
+
+  int i;
+
+  if ((N != (int)NULL) && (N != 0)) {
+    (*argc)--;
+    for (i = N; i < *argc; i++) {
+      argv[i] = argv[i+1];
+    }
+  }
+
+  return (N);
+    
+}
+
Index: /trunk/Ohana/src/lightcurve/src/scan_line.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/scan_line.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/scan_line.c	(revision 2490)
@@ -0,0 +1,28 @@
+# include "lightcurve.h"
+
+/*************/
+int
+scan_line (f, line) 
+FILE *f;
+char line[];
+{
+
+  int i, status;
+  char c;
+  
+  status = EOF + 1;
+  
+  for (i = 0, c = 0; (c != '\n') && (status != EOF); i++) {
+    status = fscanf (f, "%c", &c);
+    line[i] = c;
+  }
+  line[i - 1] = 0;  /* this could make things crash! */
+
+  if (i > 1) {
+    status = EOF + 1;
+  }
+
+  return (status);
+
+}
+
Index: /trunk/Ohana/src/lightcurve/src/set_Mcal.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/set_Mcal.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/set_Mcal.c	(revision 2490)
@@ -0,0 +1,53 @@
+# include "lightcurve.h"
+
+void set_Mcal (images, Nimages)
+Image    *images;
+int       Nimages;
+{
+
+  int i;
+  double clouds, Clouds, dClouds, R, R2, N;
+  
+  R = R2 = N = 0.0;
+  for (i = 0; i < Nimages; i++) {
+    images[i].clouds = images[i].Mcal + C_LAMBDA - A_LAMBDA * images[i].airmass + images[i].AmF;
+    if (!images[i].empty && images[i].fixed) {
+      R  +=     images[i].clouds;
+      R2 += SQ (images[i].clouds);
+      N  += 1.0;
+    }
+  }
+
+  Clouds  = R / N;
+  dClouds = sqrt (R2 / N - Clouds*Clouds);
+
+  fprintf (stderr, "Clouds = %f, dClouds = %f, N / Nimages: %f / %d\n", Clouds, dClouds, N, Nimages);
+
+  dClouds = MAX (0.0001, dClouds);
+
+  for (i = 0; i < Nimages; i++) {
+    if (fabs(images[i].clouds - Clouds) > SIG*dClouds) 
+      images[i].fixed = FALSE;
+    else {
+      images[i].fixed  = TRUE;
+      images[i].Mcal   = - C_LAMBDA + A_LAMBDA * images[i].airmass - images[i].AmF;
+      images[i].clouds = 0.0;
+    }
+  }
+}
+
+/*  BIG IMPORTANT NOTE:  equations (3) and (7) in Magnier et al 1992, A&A 96, 379
+    are not consistent with positive defined A_LAMBDA.  
+
+    the equations should read:
+
+    (3)  M_app = c_lambda + m - a_lambda*\zeta ... + clouds    (... is color term)
+    (7)  M_cal = -c_lambda + a_lambda*\zeta
+
+    The point is that a_lambda is a positive coeff, so as \zeta increases, the
+    image is *less* sensitive, so M_cal goes up.  conversely, c_lambda is also
+    a positive defined number, so as c_lambda increases, the image is *more* 
+    sensitive.  Since the a_lambda and c_lambda have opposite senses, they 
+    must have opposite signs.  
+
+*/
Index: /trunk/Ohana/src/lightcurve/src/sort_seq.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/sort_seq.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/sort_seq.c	(revision 2490)
@@ -0,0 +1,39 @@
+# include "lightcurve.h"
+
+void sort_seq (seq, value, N) 
+int *seq;
+double *value;
+int N;
+{
+  int l,j,ir,i;
+  int temp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = seq[--l];
+    }
+    else {
+      temp = seq[ir];
+      seq[ir] = seq[0];
+      if (--ir == 0) {
+	seq[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[seq[j]] < value[seq[j+1]]) ++j;
+      if (value[temp] < value[seq[j]]) {
+	seq[i]=seq[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
+
+
Index: /trunk/Ohana/src/lightcurve/src/sort_stars.c
===================================================================
--- /trunk/Ohana/src/lightcurve/src/sort_stars.c	(revision 2490)
+++ /trunk/Ohana/src/lightcurve/src/sort_stars.c	(revision 2490)
@@ -0,0 +1,24 @@
+# include "lightcurve.h"
+
+void sort_stars (radec, stars, Nstars)
+int  **radec;
+Star  *stars;
+int    Nstars;
+{
+  
+  int i;
+  double *RAs;
+
+  ALLOCATE (radec[0], int, Nstars);
+  ALLOCATE (RAs, double, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    radec[0][i] = i;
+    RAs[i] = stars[i].RA;
+  }
+
+  sort_seq (radec[0], RAs, Nstars);
+  free (RAs);
+
+}
+
+
Index: /trunk/Ohana/src/markrock/Makefile
===================================================================
--- /trunk/Ohana/src/markrock/Makefile	(revision 2490)
+++ /trunk/Ohana/src/markrock/Makefile	(revision 2490)
@@ -0,0 +1,66 @@
+include ../../Configure
+HOME 	=	$(ROOT)/src/markrock
+CONFIG  =	$(ROOT)/config
+PROGRAM =       markrock
+
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC) -I$(LINC)/$(ARCH)
+LIBS	= 	-L$(LLIB) -lohana -lFITS -lm 
+CFLAGS	=	-o $*.$(ARCH).o $(INCS)
+CCFLAGS	=	$(INCS) $(LIBS) 
+
+MARKROCK = \
+$(SRC)/markrock.$(ARCH).o 	$(SRC)/gcatalog.$(ARCH).o   	\
+$(SRC)/coordops.$(ARCH).o	$(SRC)/sorts.$(ARCH).o 		\
+$(SRC)/ConfigInit.$(ARCH).o 	$(SRC)/photometry.$(ARCH).o \
+$(SRC)/check_lockfile.$(ARCH).o \
+$(SRC)/find_rocks.$(ARCH).o 	$(SRC)/wcatalog.$(ARCH).o	\
+$(SRC)/gcatstats.$(ARCH).o	$(SRC)/wrocks.$(ARCH).o 	\
+$(SRC)/check_permissions.$(ARCH).o \
+$(SRC)/gregions.$(ARCH).o \
+$(SRC)/aregion.$(ARCH).o \
+$(SRC)/find_bright_stars.$(ARCH).o \
+$(SRC)/load_gsc_data.$(ARCH).o \
+$(SRC)/count_neighbors.$(ARCH).o
+
+
+OBJ = $(MARKROCK)
+
+default: $(PROGRAM)
+
+$(MARKROCK): $(INC)/markrock.h
+
+# dependancy rules for binary code ##########################
+$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+
+$(BIN)/$(PROGRAM).$(ARCH): $(OBJ)
+	$(CC) $(OBJ) -o $(BIN)/$(PROGRAM).$(ARCH) $(CCFLAGS)
+
+install: $(DESTBIN)/$(PROGRAM)
+
+$(DESTBIN)/$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+	rm -f $(DESTBIN)/$(PROGRAM)
+	cp $(BIN)/$(PROGRAM).$(ARCH) $(DESTBIN)/$(PROGRAM)
+
+# utilities #################################################
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+.SUFFIXES: .$(ARCH).o
+
+.c.$(ARCH).o:
+	$(CC) $(CFLAGS) -c $<
+
+
Index: /trunk/Ohana/src/markrock/doc/example.txt
===================================================================
--- /trunk/Ohana/src/markrock/doc/example.txt	(revision 2490)
+++ /trunk/Ohana/src/markrock/doc/example.txt	(revision 2490)
@@ -0,0 +1,13 @@
+
+rats: foreach f ( */*.cpt )
+foreach? echo $f
+foreach? echo $f >> bright.log
+foreach? (markstar -v $f >> bright.dat) >>& bright.log
+foreach? end
+
+
+
+ echo $f
+ echo $f >> bright.log
+ (markstar -v $f >> bright.dat) >>& bright.log
+ end
Index: /trunk/Ohana/src/markrock/include/markrock.h
===================================================================
--- /trunk/Ohana/src/markrock/include/markrock.h	(revision 2490)
+++ /trunk/Ohana/src/markrock/include/markrock.h	(revision 2490)
@@ -0,0 +1,44 @@
+# include <ohana.h>
+# include <loneos.h>
+
+typedef struct {
+  Coords coords;
+  float *X, *Y;
+  int *N;
+  double RA[2], DEC[2];
+  double Area, density, spacing;
+} CatStats;
+
+typedef struct {
+  double ra[3];
+  double dec[3];
+  double X[3];
+  double Y[3];
+  unsigned int t[3];
+  double mag[3];
+  int N[3];
+} Rocks;
+
+/* global variables set in parameter file */
+
+int    VERBOSE;
+int    RESET;
+int    FORCE_RUN;
+
+char   GSCFILE[256];
+char   GSCDIR[256];
+char   CATDIR[256];
+char   RockCat[256];
+
+double RADIUS;
+double MAX_RADIUS;
+double MAX_SPEED;
+double MAX_DELAY;
+double ZERO_POINT;
+
+double BRIGHT_HALO_MAG;
+double BRIGHT_HALO_SLOPE;
+double ROCK_NEIGHBOR_RADIUS;
+int    ROCK_NEIGHBOR_NMAX;
+
+PhotCodeData photcodes;
Index: /trunk/Ohana/src/markrock/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/markrock/src/ConfigInit.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/ConfigInit.c	(revision 2490)
@@ -0,0 +1,46 @@
+# include "markrock.h"
+
+ConfigInit (int *argc, char **argv) {
+
+  char *config, *file;
+  char PhotCodeFile[256];
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (0);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+  /* used in other pipeline functions */
+  ScanConfig (config, "CATDIR",                 "%s",  0, CATDIR);
+
+  /* unique to markrock */
+  ScanConfig (config, "ROCK_NEIGHBOR_RADIUS",   "%lf", 0, &ROCK_NEIGHBOR_RADIUS);
+  ScanConfig (config, "ROCK_NEIGHBOR_NMAX",     "%d",  0, &ROCK_NEIGHBOR_NMAX);
+
+  ScanConfig (config, "ROCK_RADIUS",            "%lf", 0, &RADIUS);
+  ScanConfig (config, "ROCK_MAX_RADIUS",        "%lf", 0, &MAX_RADIUS);
+  ScanConfig (config, "ROCK_MAX_SPEED",         "%lf", 0, &MAX_SPEED);
+  ScanConfig (config, "ROCK_MAX_DELAY",         "%lf", 0, &MAX_DELAY);
+  ScanConfig (config, "ROCK_CATALOG",           "%s",  0, RockCat);
+  ScanConfig (config, "PHOTCODE_FILE",          "%s",  0, PhotCodeFile);
+
+  ScanConfig (config, "BRIGHT_HALO_MAG",        "%lf", 0, &BRIGHT_HALO_MAG);
+  ScanConfig (config, "BRIGHT_HALO_SLOPE",      "%lf", 0, &BRIGHT_HALO_SLOPE);
+  ScanConfig (config, "GSCFILE",                "%s",  0, GSCFILE);
+  ScanConfig (config, "GSCDIR",                 "%s",  0, GSCDIR);
+  ScanConfig (config, "ZERO_PT",                "%lf", 0, &ZERO_POINT);
+
+  if (!LoadPhotcodes (PhotCodeFile, &photcodes)) {
+    fprintf (stderr, "error loading photcodes\n");
+    exit (0);
+  }
+
+  free (config);
+  free (file);
+
+}
Index: /trunk/Ohana/src/markrock/src/aregion.c
===================================================================
--- /trunk/Ohana/src/markrock/src/aregion.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/aregion.c	(revision 2490)
@@ -0,0 +1,186 @@
+# include "markrock.h"
+
+double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+			 52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+			 0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+			 -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+		       "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+		       "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+		       "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			"n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			"s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			"s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		"disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		"disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+                   0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+/* find region file which contains ra, dec */
+aregion (region, f, ra, dec) 
+GSCRegion region[];
+FILE *f;
+double ra, dec;
+{
+  
+  
+  char buffer[28800], temp[50], file[50];
+  double dr, dd;
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done, nregion;
+  
+  while (ra < 0) { ra += 360.0; }
+  while (ra >= 360.0) { ra -= 360.0; }
+    
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt\0", GSCDIR);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] = -180.0;
+    region[0].RA[1] =  540.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+# ifdef DEBUG
+    fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+# ifdef DEBUG
+      fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+# ifdef DEBUG
+    fprintf (stderr, "%f %f %f  %f %f %f  %s\n", DEC0, dec, DEC1, RA0, ra, RA1, temp);
+# endif
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    exit (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt\0", GSCDIR, Dec2Sections[NBigDec],&temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
+
+
+/**********/
+int hms_to_deg (h0, h1, d0, d1, string) 
+     char *string;
+     double *h0, *h1, *d0, *d1;
+{
+  
+  int flag_d0, flag_d1, flag_h0, flag_h1;
+  double tmp;
+  
+  *d0 = *h0 = *d1 = *h1 = 0;
+
+  flag_h0 = dparse (h0, 1, string);
+  flag_h1 = dparse (h1, 4, string);
+  flag_d0 = dparse (d0, 7, string);
+  flag_d1 = dparse (d1, 9, string);
+  *h0 *= flag_h0;
+  *h1 *= flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  dparse (&tmp, 2, string);
+  *h0 += tmp/60.0;
+  dparse (&tmp, 3, string);
+  *h0 += tmp/3600.0;
+  
+  dparse (&tmp, 5, string);
+  *h1 += tmp/60.0;
+  dparse (&tmp, 6, string);
+  *h1 += tmp/3600.0;
+  
+  dparse (&tmp, 8, string);
+  *d0 += tmp/60.0;
+
+  dparse (&tmp, 10, string);
+  *d1 += tmp/60.0;
+
+  *h0 *= 15*flag_h0;
+  *h1 *= 15*flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  return (TRUE);
+}
+
+
+/*
+      if (buffer[i*48 + 19] == ' ') continue;
+      strncpy (temp, &buffer[i*48 + 19], 20);       temp[20] = 0;
+      hms_to_deg (&RA,  &DEC, temp, ' ', 3);
+
+
+  dBigRA = 360.0 / (int)(0.5 + 48*cos(3.1415927*0.5*(BigDecBounds[NBigDec] + BigDecBounds[NBigDec + 1])/180.0));
+
+  NBigRA = ra / dBigRA;
+
+  NBig = NBigRA;
+  for (i = 0; (i < 12) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+  for (i = 13; (i < 24) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+
+
+  fprintf (stderr, "%d %d %d %d %f %f -> %f %f %f\n", NBigDec, NBigRA, NBigRASections[NBigDec], NBig, ra, dec, BigDecBounds[NBigDec], BigDecBounds[NBigDec + 1], dBigRA);
+*/
Index: /trunk/Ohana/src/markrock/src/check_lockfile.c
===================================================================
--- /trunk/Ohana/src/markrock/src/check_lockfile.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/check_lockfile.c	(revision 2490)
@@ -0,0 +1,39 @@
+# include "markrock.h"
+
+check_lockfile ()
+{
+  
+  FILE *f;
+  char filename[128];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    fprintf (stderr, "ERROR: catalog %s is locked, try again later\n", CATDIR);
+    exit (0);
+  }
+
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock file %s\n", filename);
+    exit (0);
+  }
+  fclose (f);
+
+}
+
+clear_lockfile ()
+{
+  
+  char filename[128], line[256];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    sprintf (line, "rm %s\0", filename);
+    system (line);
+  } else {
+    fprintf (stderr, "can't remove lockfile, why not?\n");
+  }
+
+}
Index: /trunk/Ohana/src/markrock/src/check_permissions.c
===================================================================
--- /trunk/Ohana/src/markrock/src/check_permissions.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/check_permissions.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "markrock.h"
+
+check_permissions (char *basefile) {
+  
+  FILE *f;
+  char *c, dir[256], filename[256];
+  struct stat filestat;
+  uid_t fuid, uid;
+  gid_t fgid, gid;
+  int status;
+
+  uid = getuid();
+  gid = getgid();
+
+  /* check permission to write to directory */
+  sprintf (filename, "%s\0", basefile);
+  c = strrchr (filename, '/');
+  if (c == (char *) NULL) {
+    strcpy (dir, ".");
+  } else {
+    *c = 0;
+    strcpy (dir, filename);
+  }
+  status = stat (dir, &filestat);
+  if (status == -1) {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  } 
+  if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRWXU)) ||
+      ((gid == filestat.st_gid) && (filestat.st_mode & S_IRWXG)) || 
+      (filestat.st_mode & S_IRWXO)) {
+  } else {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  }
+  
+  /* check permission to write to file */
+  sprintf (filename, "%s\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+  /* check permission to write to backup file */
+  sprintf (filename, "%s~\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+}
Index: /trunk/Ohana/src/markrock/src/config.c
===================================================================
--- /trunk/Ohana/src/markrock/src/config.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/config.c	(revision 2490)
@@ -0,0 +1,110 @@
+# include <ohana.h>
+# define D_NBYTES 4096
+
+char *LoadConfigFile (filename) 
+char *filename; 
+{
+  
+  FILE *f;
+  int i, done, Nbytes, NBYTES, size;
+  char *config;
+  
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "couldn't find %s\n", filename);
+    return ((char *) NULL);
+  }
+ 
+  NBYTES = D_NBYTES;
+  ALLOCATE (config, char, NBYTES);
+ 
+  size = 0;
+  done = FALSE;
+  for (i = 0; !done; i++) {
+    Nbytes = Fread (&config[i*D_NBYTES], sizeof(char), D_NBYTES, f, "char");
+    size += Nbytes;
+    if (Nbytes < D_NBYTES) 
+      done = TRUE;
+    else {
+      NBYTES += D_NBYTES;
+      REALLOCATE (config, char, NBYTES);
+    }
+  }
+  
+  config[size] = '\n';
+  config[size+1] = 0;
+  REALLOCATE (config, char, size + 2);
+ 
+  fclose (f);
+
+  return (config);
+}
+
+int ScanConfig /* we expect one more field: the pointer to the value requested */
+# ifndef ANSI
+(config, field, mode, va_alist) 
+ char *config; char *field, *mode; va_dcl
+# else
+(char       config[],
+ char       field[],
+ char       mode[],...)
+# endif
+{
+ 
+  int i, j;
+  char *p, *p2, tmp[256];
+  va_list argp;
+  double value;
+  
+# ifndef ANSI
+  va_start (argp);
+# else
+  va_start (argp, N);
+# endif
+  
+  /* find the correct line with field */
+  p2 = config;
+  for (i = 0; ; i++) {
+    if (!strncmp (field, p2, strlen(field))) {
+      p = p2 + strlen (field);
+      break;
+    }
+    else {
+      p2 = strchr (p2, '\n');
+      if (p2 == (char *) NULL) {
+	fprintf (stderr, "entry %s not found in config file\n", field);
+	return (FALSE);
+      }
+      else p2++;
+    }
+  }
+  if (!strcmp (mode, "%s")) {
+    p2 = strchr (p, '\n');
+    if (p2 == (char *) NULL)
+      p2 = config + strlen(config);
+    bcopy (p, tmp, (p2-p));
+    tmp[(p2-p)] = 0;
+    stripwhite (tmp);
+    p2 = va_arg (argp, char *);
+    strcpy (p2, tmp);
+  }
+  else {
+ 
+    /* try to get a numerical value from the field */
+    value = strtod (p, &p2);
+    if ((*p2 == 'd') || (*p2 == 'D')) 
+      value *= pow (10.0, atof (p2 + 1));
+    
+    if (!strcmp (mode, "%d"))  *va_arg (argp, int *)       = value;
+    if (!strcmp (mode, "%u"))  *va_arg (argp, unsigned *)  = value;
+    if (!strcmp (mode, "%ld")) *va_arg (argp, long *)      = value;
+    if (!strcmp (mode, "%hd")) *va_arg (argp, short *)     = value;
+    if (!strcmp (mode, "%f"))  *va_arg (argp, float *)     = value;
+    if (!strcmp (mode, "%lf")) *va_arg (argp, double *)    = value;
+    
+  }
+ 
+  va_end (argp);
+  return (TRUE);
+  
+}
Index: /trunk/Ohana/src/markrock/src/coordops.c
===================================================================
--- /trunk/Ohana/src/markrock/src/coordops.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/coordops.c	(revision 2490)
@@ -0,0 +1,342 @@
+# include "markrock.h"
+
+XY_to_RD (ra, dec, x, y, coords)
+double *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+# if 1
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+# else
+  {
+# endif
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN")) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+fXY_to_RD (ra, dec, x, y, coords)
+float *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+}
+
+
+RD_to_XY (x, y, ra, dec, coords)
+double *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    /* fprintf (stderr, "approximate to polynomial TAN plane fit\n");  */
+  }
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+fRD_to_XY (x, y, ra, dec, coords)
+float *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+
+  *x = 0;
+  *y = 0;
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    X = X;
+    Y = Y;
+  }
+  
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+ 
+}
+
+
+
+GetCoords (coords, header) 
+Coords coords[];
+Header header[];
+{
+
+  int status;
+  double rotate;
+
+  rotate = 0.0;
+  coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+  coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+  coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+  coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+  strcpy (coords[0].ctype, "NONE");
+
+  status = TRUE; 
+  if (fits_scan (header, "CTYPE2", "%s", 1, coords[0].ctype)) {
+    status  = fits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+    status &= fits_scan (header, "CRPIX1", "%lf", 1, &coords[0].crpix1);
+    status &= fits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+    status &= fits_scan (header, "CRPIX2", "%lf", 1, &coords[0].crpix2);
+    if (fits_scan (header, "CDELT1", "%lf", 1, &coords[0].cdelt1)) {
+      status &= fits_scan (header, "CDELT2", "%lf", 1, &coords[0].cdelt2);
+      if (fits_scan (header, "CROTA2", "%lf", 1, &rotate)) {
+	coords[0].pc1_1 =  cos(rotate*RAD_DEG);
+	coords[0].pc1_2 = -sin(rotate*RAD_DEG);
+	coords[0].pc2_1 =  sin(rotate*RAD_DEG);
+	coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+      }
+      if (fits_scan (header, "PC001001", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "PC001002", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "PC002001", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "PC002002", "%lf", 1, &coords[0].pc2_2);
+      }
+    }
+    else {
+      if (fits_scan (header, "CD1_1", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "CD1_2", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "CD2_1", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "CD2_2", "%lf", 1, &coords[0].pc2_2);
+	coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      }
+      else {
+	status = FALSE;
+      }
+    }
+  }
+  else {
+    if (fits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1)) {
+      status  = fits_scan (header, "RA_X", "%lf", 1, &coords[0].pc1_1);
+      status &= fits_scan (header, "RA_Y", "%lf", 1, &coords[0].pc1_2);
+      status &= fits_scan (header, "DEC_O", "%lf", 1, &coords[0].crval2);  
+      status &= fits_scan (header, "DEC_X", "%lf", 1, &coords[0].pc2_1);
+      status &= fits_scan (header, "DEC_Y", "%lf", 1, &coords[0].pc2_2);
+      coords[0].crpix1 = coords[0].crpix2 = 0.0;
+      coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      strcpy (coords[0].ctype, "GENE");
+    }
+  }
+  if (!status) {
+    fprintf (stderr, "error getting all elements for coordinate mode %d\n", coords[0].ctype);
+    coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+    coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+    coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+    coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+    strcpy (coords[0].ctype, "NONE");
+  }
+}
+
+
+  /* -PLY projection is an extrapolation of the -TAN projection. 
+     In addition to the usual linear terms of CRPIXi, PC00i00j, there are 
+     higher order polynomial terms (up to 3rd order):
+     Axis 1 terms:
+     PCA1X2Y0 = coords.polyterm[0][0] = x^2                                             
+     PCA1X1Y1 = coords.polyterm[1][0] = xy                                          
+     PCA1X0Y2 = coords.polyterm[2][0] = y^2                                             
+     PCA1X3Y0 = coords.polyterm[3][0] = x^3                                             
+     PCA1X2Y1 = coords.polyterm[4][0] = x^2 y                                             
+     PCA1X1Y2 = coords.polyterm[5][0] = x y^2                                             
+     PCA1X0Y3 = coords.polyterm[6][0] = y^2                                              
+     Axis 2 terms:
+     PCA2X2Y0 = coords.polyterm[0][1] = x^2                                               
+     PCA2X1Y1 = coords.polyterm[1][1] = xy                                                
+     PCA2X0Y2 = coords.polyterm[2][1] = y^2                                               
+     PCA2X3Y0 = coords.polyterm[3][1] = x^3                                               
+     PCA2X2Y1 = coords.polyterm[4][1] = x^2 y                                             
+     PCA2X1Y2 = coords.polyterm[5][1] = x y^2                                             
+     PCA2X0Y3 = coords.polyterm[6][1] = y^2                                               
+  */
Index: /trunk/Ohana/src/markrock/src/count_neighbors.c
===================================================================
--- /trunk/Ohana/src/markrock/src/count_neighbors.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/count_neighbors.c	(revision 2490)
@@ -0,0 +1,32 @@
+# include "markrock.h"
+
+count_neighbors (rocks, Nrocks, catalog, catstats)
+Rocks *rocks;
+int Nrocks;
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  float *x, *y;
+  double X, Y, dx, dy, dr;
+  int i, j, k;
+
+  x = catstats[0].X;
+  y = catstats[0].Y;
+
+  for (i = 0; i < Nrocks; i++) {
+    for (k = 0; k < 3; k++) {
+      X = rocks[i].X[k];
+      Y = rocks[i].Y[k];
+      rocks[i].N[k] = 0;
+      for (j = 0; j < catalog[0].Naverage; j++) {
+	if ((dx = X - x[j]) > ROCK_NEIGHBOR_RADIUS) continue;
+	if (dx < -ROCK_NEIGHBOR_RADIUS) break;
+	dy = Y - y[j];
+	dr = hypot (dx, dy);
+	if (dr > ROCK_NEIGHBOR_RADIUS) continue;
+	rocks[i].N[k] ++;
+      }
+    }
+  }
+}
Index: /trunk/Ohana/src/markrock/src/find_bright_stars.c
===================================================================
--- /trunk/Ohana/src/markrock/src/find_bright_stars.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/find_bright_stars.c	(revision 2490)
@@ -0,0 +1,147 @@
+# include "markrock.h"
+
+find_bright_stars (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, n, m, first_j, Nave, Ngsc, Nmark;
+  Catalog GSCdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2;
+  char *mark;
+  double dX, dY, dR, MaxDist, MaxDist1, MaxRadius, radius, radius2;
+
+  load_gsc_data (&GSCdata, catstats);
+
+  Nave = catalog[0].Naverage;
+  Ngsc = GSCdata.Naverage;
+    
+  /* in the function below, it is better to have the catalog with
+     more stars associated with index 2 (j) */ 
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+  ALLOCATE (X1, float, Ngsc);
+  ALLOCATE (Y1, float, Ngsc);
+  ALLOCATE (N1, int, Ngsc);
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Ngsc; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], GSCdata.average[i].R, GSCdata.average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Ngsc > 1) sort_lists (X1, Y1, N1, Ngsc);
+  
+  /* first find stellar halos */
+  /* max radius (mag = -1) */
+  /** the j index moves quickly and is better associated with the catalog with more stars */
+  MaxRadius = BRIGHT_HALO_SLOPE * (-1.0 - BRIGHT_HALO_MAG); 
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*MaxRadius) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*MaxRadius) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    radius = MAX (BRIGHT_HALO_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_HALO_MAG), 0.0);
+    if (radius == 0) {
+      i++; 
+      continue;
+    }
+    radius2 = radius*radius;
+    for (; (dX > -2*radius) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < radius2) {  /* new measurement of this star */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+# if (0)
+  /* next find y spikes */
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -BRIGHT_YTRAIL_WIDTH) {
+      i++;
+      continue;
+    }
+    if (dX >= BRIGHT_YTRAIL_WIDTH) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist = MAX (BRIGHT_YTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_YTRAIL_MAG), 0.0);
+    for (; (dX > -BRIGHT_YTRAIL_WIDTH) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dX) < BRIGHT_YTRAIL_WIDTH) && (fabs(dY) < MaxDist)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find x spikes */
+  /** find catalog stars near GSC stars **/
+  MaxDist = MAX (BRIGHT_XTRAIL_SLOPE * (-1.0 - BRIGHT_XTRAIL_MAG), 0.0);
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -MaxDist) {
+      i++;
+      continue;
+    }
+    if (dX >= MaxDist) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist1 = MAX (BRIGHT_XTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_XTRAIL_MAG), 0.0);
+    for (; (dX > -MaxDist1) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dY) < BRIGHT_XTRAIL_WIDTH) && (fabs(dX) < MaxDist1)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+# endif
+
+  /* done with search, mark selected stars */
+  Nmark = 0;
+  for (i = 0; i < Nave; i++) {
+    if (mark[i]) {
+      Nmark ++;
+      catalog[0].average[N2[i]].code = ID_BLEED;
+    }
+  } 
+  fprintf (stderr, "marked %d stars for bright star\n", Nmark);
+  
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (mark);
+  free (GSCdata.average);
+
+}
+
Index: /trunk/Ohana/src/markrock/src/find_ghosts.c
===================================================================
--- /trunk/Ohana/src/markrock/src/find_ghosts.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/find_ghosts.c	(revision 2490)
@@ -0,0 +1,70 @@
+# include "markrock.h"
+
+find_ghosts (catalog, catstats, filename, image, Nimage)
+Catalog catalog[];
+CatStats catstats[];
+char *filename;
+Image image[];
+int Nimage;
+{
+
+  int i, j, first_j, Nave, Ngsc, Nregions;
+  Catalog GSCdata, Ghostdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2, *match;
+  char *mark;
+  double dX, dY, dR, RADIUS2, BRIGHT_RADIUS, radius, X, Y, R, D;
+  Image timage;
+  GSCRegion *region, *gregions();
+
+  for (i = 0; i < Nimage; i++) {
+    
+    /* coords structure for ghost image */
+    timage = image[i];
+    timage.coords.cdelt1 = -1*image[i].coords.cdelt1;
+    timage.coords.cdelt2 = -1*image[i].coords.cdelt2;
+    timage.coords.crpix1 = 2*OPTICAL_AXIS1 - image[i].coords.crpix1;
+    timage.coords.crpix2 = 2*OPTICAL_AXIS2 - image[i].coords.crpix2;
+
+    region = gregions2 (&timage, &Nregions);
+    
+    /* find ghost stars */
+    load_gsc_data_ghost (&GSCdata, region, Nregions, &timage);
+
+    /* refect ghost stars to find locations of ghosts */
+    ALLOCATE (Ghostdata.average, Average, MAX (GSCdata.Naverage, 1));
+    for (j = 0; j < GSCdata.Naverage; j++) {
+      RD_to_XY (&X, &Y, GSCdata.average[j].R, GSCdata.average[j].D, &timage);
+      fXY_to_RD (&Ghostdata.average[j].R, &Ghostdata.average[j].D, X, Y, &image[i]);
+      Ghostdata.average[j].M = GSCdata.average[j].M;
+    }    
+    Ghostdata.Naverage = GSCdata.Naverage;
+
+    /* match ghosts and image stars, mark ghosts */
+    find_matches (catalog, catstats, &Ghostdata, i);
+
+    free (Ghostdata.average);
+    free (GSCdata.average);
+  }
+
+}
+
+/* 
+
+   just to be clear on some of the terms:
+
+   the "ghost" is the fuzzy patch of light on an image caused by
+     a reflected star
+
+   the "ghost star" is the star in the sky which causes a ghost
+
+   the "ghost image" is the image location on the sky 
+     where ghost stars may come from.
+
+   the "image stars" are observed stars at the location of the
+     ghost - these are detections of the ghost
+
+
+*/
Index: /trunk/Ohana/src/markrock/src/find_group.c
===================================================================
--- /trunk/Ohana/src/markrock/src/find_group.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/find_group.c	(revision 2490)
@@ -0,0 +1,69 @@
+# include "markrock.h"
+
+find_group (catstats, mark, Npts, i, ANGLE)
+     CatStats catstats[];
+     double *ANGLE;
+     int i, Npts;
+     char *mark;
+{
+ 
+  float *R, *D;
+  int j, N, bin, Ndegbin;
+  unsigned short int *A;
+  double Ra, De, dR, dD, angle, limit;
+
+   /* assign some parameter values */
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+  limit = 10.0*sqrt((double)(M_PI*RADIUS*RADIUS*catstats[0].density)/(double)(NBINS));
+  Ndegbin = NBINS / 180.0;
+  ALLOCATE (A, unsigned short int, NBINS)
+  bzero (A, NBINS*sizeof(short));
+
+  /* look for points concentrated in an angle bin */
+  if (mark[i]) return (FALSE);
+  Ra = R[i];
+  De = D[i];
+  N = 0;
+  /* points east */
+  for (j = i + 1; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) 
+	continue;
+      if (angle < 0) angle += M_PI;
+      bin = 1 + angle*DEG_RAD*Ndegbin;
+      A[bin] ++;
+      if (A[bin] > limit) {
+	*ANGLE = (bin - 1.0) / (DEG_RAD*Ndegbin);
+	return (TRUE);
+      }
+      N ++;
+    }
+  }
+  /* points west */
+  for (j = i - 1; (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) 
+	continue;
+      if (angle < 0) angle += M_PI;
+      bin = 1 + angle*DEG_RAD*Ndegbin;
+      A[bin] ++;	
+      if (A[bin] > limit) {
+	*ANGLE = (bin - 1.0) / (DEG_RAD*Ndegbin);
+	return (TRUE);
+      }
+      N ++;
+    }
+  }
+  return (FALSE);
+}
+  
Index: /trunk/Ohana/src/markrock/src/find_rocks.c
===================================================================
--- /trunk/Ohana/src/markrock/src/find_rocks.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/find_rocks.c	(revision 2490)
@@ -0,0 +1,193 @@
+# include "markrock.h"
+
+Rocks *find_rocks (catalog, catstats, nrocks)
+Catalog catalog[];
+CatStats catstats[];
+int *nrocks;
+{
+
+  int i, j, k, n, m, N, M, first_j, NOBJECT, Nobject, Nrocks, NROCKS;
+  double X, Y, RADIUS2;
+  float *X1, *Y1;
+  float dX, dY, dR;
+  float dtime;
+  int *N1, *N0;
+  unsigned int Tref;
+  int *T1, Ttmp;
+  int Nstar, Nghost, Ng;
+  unsigned int flags;
+  unsigned short NotRock, IsProper;
+  Coords *tcoords;
+  double ax, ay, cx, cy, dt, dt1, dt2, dt3, dX1, dX2, speed, distance;
+  Rocks *rocks;
+  struct timeval now, then;  
+  double MaxSeparation;
+
+  gettimeofday (&then, (void *) NULL);
+
+  Nstar = catalog[0].Naverage;
+
+  NOBJECT = 1000;
+  ALLOCATE (X1, float, NOBJECT);
+  ALLOCATE (Y1, float, NOBJECT);
+  ALLOCATE (T1, int,   NOBJECT);
+  ALLOCATE (N1, int,   NOBJECT);
+  Nobject = 0;
+  N0 = catstats[0].N;
+
+  NROCKS = 3000;
+  ALLOCATE (rocks, Rocks, NROCKS);
+  Nrocks = 0;
+
+  Tref = 0;
+  NotRock = (ID_ROCK ^ 0xffff);
+  IsProper = ID_USNO | ID_PROPER;
+  for (i = 0; i < Nstar; i++) {
+    N = N0[i];
+    if (RESET && ((catalog[0].average[N].code & ID_ROCK) == ID_ROCK)) {
+      /* resets both relevant bits */
+      catalog[0].average[N].code &= NotRock;
+    }
+    if (RESET && (catalog[0].average[N].code == ID_COSMIC)) {
+      /* resets both relevant bits */
+      catalog[0].average[N].code = 0;
+    }
+    /* accept a measurement if it is either unmarked or marked as a proper motion star */
+    if ((catalog[0].average[N].Nm == 1) && (catalog[0].average[N].Nn > 0) && ((catalog[0].average[N].code == 0) || ((catalog[0].average[N].code & IsProper) == IsProper))) {
+      if (Tref == 0) Tref = catalog[0].measure[catalog[0].average[N].offset].t;
+      X1[Nobject] = catstats[0].X[i];
+      Y1[Nobject] = catstats[0].Y[i];
+      if (catalog[0].measure[catalog[0].average[N].offset].t > Tref) 
+	T1[Nobject] = catalog[0].measure[catalog[0].average[N].offset].t - Tref;
+      else {
+	Ttmp = Tref - catalog[0].measure[catalog[0].average[N].offset].t;
+	T1[Nobject] = -Ttmp;
+      }      
+      N1[Nobject] = N;
+      Nobject ++;
+      if (Nobject == NOBJECT - 1) {
+	NOBJECT += 1000;
+	REALLOCATE (X1, float, NOBJECT);
+	REALLOCATE (Y1, float, NOBJECT);
+	REALLOCATE (T1, int, NOBJECT);
+	REALLOCATE (N1, int,   NOBJECT);
+      }
+    }
+  }
+  REALLOCATE (X1, float, Nobject);
+  REALLOCATE (Y1, float, Nobject);
+  REALLOCATE (T1, int, Nobject);
+  REALLOCATE (N1, int,   Nobject);
+  if (Nobject > 1) sort_set (X1, Y1, T1, N1, Nobject);
+
+  fprintf (stderr, "Nobj: %d\n", Nobject);
+
+  MaxSeparation = MAX_SPEED * MAX_DELAY;
+  fprintf (stderr, "%f %f %f %f %f\n", MaxSeparation, MAX_RADIUS, RADIUS, MAX_SPEED, MAX_DELAY);
+
+  /** find 3 rocks in a line **/
+  for (i = 0; i < Nobject - 2; i++) {
+    fprintf (stderr, ".");
+    for (j = i + 1; j < Nobject - 1; j++) {
+      if (X1[j] - X1[i] > MaxSeparation) goto NEXTi;
+      if (X1[i] - X1[j] > MaxSeparation) goto NEXTj;
+      if (T1[i] == T1[j]) continue;
+      dt = (int)(T1[j] - T1[i]);
+      if (fabs(dt) > MAX_DELAY) continue;
+      ax = (X1[j] - X1[i])/dt;
+      cx = (X1[i]*T1[j] - X1[j]*T1[i])/dt;
+      ay = (Y1[j] - Y1[i])/dt;
+      cy = (Y1[i]*T1[j] - Y1[j]*T1[i])/dt;
+      speed = hypot (ax, ay);
+      if (speed > MAX_SPEED) continue;
+      for (k = j + 1; k < Nobject; k++) {
+	if (X1[k] - X1[j] > MaxSeparation) goto NEXTj;
+	if (X1[j] - X1[k] > MaxSeparation) goto NEXTk;
+	if (T1[i] == T1[k]) continue;
+	if (T1[j] == T1[k]) continue;
+	dt1 = fabs(dt);
+	dt2 = fabs ((int)(T1[i] - T1[k]));
+	dt3 = fabs ((int)(T1[j] - T1[k]));
+	dt1 = MIN(MIN(dt1,dt2),dt3);
+	dt3 = MAX(MAX(dt1,dt2),dt3);
+	if (fabs(dt3) > MAX_DELAY) continue;
+	/* errors are too large by this point */
+	if (RADIUS * dt3 / dt1 > MAX_RADIUS) continue; 
+	dX1 = T1[k]*ax - X1[k] + cx;
+	dX2 = T1[k]*ay - Y1[k] + cy;
+	distance = hypot (dX1, dX2);
+	/*
+        fprintf (stderr, "%d %d %d %f %f %d %f %f\n", i, j, k, ax, cx, T1[k], X1[k], dX1);
+	if (k > 100) exit (0);
+	*/
+	if (distance < RADIUS){
+	  catalog[0].average[N1[i]].code |= ID_ROCK;
+	  catalog[0].average[N1[j]].code |= ID_ROCK;
+	  catalog[0].average[N1[k]].code |= ID_ROCK;
+
+	  rocks[Nrocks].X[0]     = X1[i];
+	  rocks[Nrocks].Y[0]     = Y1[i];
+	  rocks[Nrocks].ra[0]    = catalog[0].average[N1[i]].R;
+	  rocks[Nrocks].dec[0]   = catalog[0].average[N1[i]].D;
+
+	  m = catalog[0].average[N1[i]].offset;
+	  rocks[Nrocks].mag[0]   = PhotRel (&catalog[0].measure[m], &photcodes, ZERO_POINT);
+	  rocks[Nrocks].t[0]     = catalog[0].measure[m].t;
+
+	  rocks[Nrocks].X[1]     = X1[j];
+	  rocks[Nrocks].Y[1]     = Y1[j];
+	  rocks[Nrocks].ra[1]    = catalog[0].average[N1[j]].R;
+	  rocks[Nrocks].dec[1]   = catalog[0].average[N1[j]].D;
+
+	  m = catalog[0].average[N1[j]].offset;
+	  rocks[Nrocks].mag[1]   = PhotRel (&catalog[0].measure[m], &photcodes, ZERO_POINT);
+	  rocks[Nrocks].t[1]     = catalog[0].measure[m].t;
+
+	  rocks[Nrocks].X[2]     = X1[k];
+	  rocks[Nrocks].Y[2]     = Y1[k];
+	  rocks[Nrocks].ra[2]    = catalog[0].average[N1[k]].R;
+	  rocks[Nrocks].dec[2]   = catalog[0].average[N1[k]].D;
+
+	  m = catalog[0].average[N1[k]].offset;
+	  rocks[Nrocks].mag[2]   = PhotRel (&catalog[0].measure[m], &photcodes, ZERO_POINT);
+	  rocks[Nrocks].t[2]     = catalog[0].measure[m].t;
+
+	  fprintf (stderr, "*");
+	  Nrocks ++;
+	  if (Nrocks >= NROCKS) {
+	    NROCKS += 3000;
+	    REALLOCATE (rocks, Rocks, NROCKS);
+	  }
+	}
+      NEXTk:
+      }
+    NEXTj:
+    }
+    gettimeofday (&now, (void *) NULL);
+    dtime = (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec);
+    if (dtime > 200) {
+      fprintf (stderr, "taking too long to find all rocks, giving up...\n");
+      goto escape_loop;
+    }
+  NEXTi:
+  }
+
+escape_loop:
+  for (i = 0; i < Nobject; i++) {
+    if ((catalog[0].average[N1[i]].code == 0) && (catalog[0].average[N1[i]].Nn >= 2)) {
+      catalog[0].average[N1[i]].code = ID_COSMIC;
+    }
+  }
+
+  fprintf (stderr, "found %d rocks\n", Nrocks);
+
+  free (T1);
+  free (X1);
+  free (Y1);
+  free (N1);
+
+  REALLOCATE (rocks, Rocks, MAX (1, Nrocks));
+  *nrocks = Nrocks;
+  return (rocks);
+
+}
Index: /trunk/Ohana/src/markrock/src/find_slow_rocks.c
===================================================================
--- /trunk/Ohana/src/markrock/src/find_slow_rocks.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/find_slow_rocks.c	(revision 2490)
@@ -0,0 +1,135 @@
+# include "markrock.h"
+
+Rocks *find_slow_rocks (catalog, catstats, nrocks)
+Catalog catalog[];
+CatStats catstats[];
+int *nrocks;
+{
+
+  int i, j, k, m, N, Nm, NOBJECT, Nobject, Nrocks, NROCKS;
+  double RADIUS2;
+  double *R1, *D1, *X1, *Y1, *M1;
+  double R, D, X, Y, M;
+  double dX, dY, dR;
+  int *N1, *N0;
+  unsigned int *T1, T;
+  int Nstar, Nghost, Ng, Nmax;
+  unsigned int flags;
+  Coords *tcoords;
+  double ax, ay, cx, cy, dt, dX1, dX2, speed, distance;
+  Rocks *rocks;
+  unsigned short IsProper;
+
+  Nstar = catalog[0].Naverage;
+
+  NOBJECT = 1000;
+  ALLOCATE (N1, int,   NOBJECT);
+  Nobject = 0;
+  N0 = catstats[0].N;
+
+  NROCKS = 3000;
+  ALLOCATE (rocks, Rocks, NROCKS);
+  Nrocks = 0;
+
+  Nmax = 0;
+  IsProper = ID_USNO | ID_PROPER;
+  for (i = 0; i < Nstar; i++) {
+    N = N0[i];
+    /* accept a measurement if it is either unmarked or marked as a proper motion star and may have multiple measurements */
+    if ((catalog[0].average[N].code == 0) || (catalog[0].average[N].code & IsProper == IsProper)) {
+      Nmax = MAX (catalog[0].average[N].Nm, Nmax);
+      N1[Nobject] = N;
+      Nobject ++;
+      if (Nobject == NOBJECT - 1) {
+	NOBJECT += 1000;
+	REALLOCATE (N1, int,   NOBJECT);
+      }
+    }
+  }
+  REALLOCATE (N1, int,   Nobject);
+  fprintf (stderr, "Nobj: %d\n", Nobject);
+
+  ALLOCATE (R1, double, Nmax);
+  ALLOCATE (D1, double, Nmax);
+  ALLOCATE (X1, double, Nmax);
+  ALLOCATE (Y1, double, Nmax);
+  ALLOCATE (T1, unsigned int, Nmax);
+  ALLOCATE (M1, double, Nmax);
+  /** find multiple measured objects, find additional measurements along that line */
+
+  for (i = 0; i < Nobject; i++) {
+    fprintf (stderr, ",");
+    if (catalog[0].average[N1[i]].Nm > 1) {
+      N = N1[i];
+      Nm = catalog[0].average[N].Nm;
+      m = catalog[0].average[N].offset;
+      for (j = 0; j < 2; j++) {
+	R1[j] = catalog[0].average[N].R - catalog[0].measure[m+j].dR/360000.0;
+	D1[j] = catalog[0].average[N].D - catalog[0].measure[m+j].dD/360000.0;
+	RD_to_XY (&X1[j], &Y1[j], R1[j], D1[j], &catstats[0].coords);
+	T1[j] = catalog[0].measure[m+j].t;
+	M1[j] = catalog[0].measure[m+j].M - catalog[0].measure[m+j].Mcal;
+      }
+      dt = T1[1] - T1[0];
+      ax = (X1[1] - X1[0])/dt;
+      cx = (X1[0]*T1[1] - X1[1]*T1[0])/dt;
+      ay = (Y1[1] - Y1[0])/dt;
+      cy = (Y1[0]*T1[1] - Y1[1]*T1[0])/dt;
+      speed = hypot (ax, ay);
+      for (k = 0; k < Nobject; k++) {
+	N = N1[k];
+	Nm = catalog[0].average[N].Nm;
+	m = catalog[0].average[N].offset;
+	for (j = 0; j < Nm; j++) {
+	  R = catalog[0].average[N].R - catalog[0].measure[m+j].dR/360000.0;
+	  D = catalog[0].average[N].D - catalog[0].measure[m+j].dD/360000.0;
+	  RD_to_XY (&X, &Y, R, D, &catstats[0].coords);
+	  T = catalog[0].measure[m+j].t;
+	  M = catalog[0].measure[m+j].M - catalog[0].measure[m+j].Mcal;
+	  if (T1[0] == T) continue;
+	  if (T1[1] == T) continue;
+	  dX1 = T*ax - X + cx;
+	  dX2 = T*ay - Y + cy;
+	  distance = hypot (dX1, dX2);
+	  if (distance < RADIUS){
+	    catalog[0].average[N1[i]].code |= ID_ROCK;
+	    catalog[0].average[N1[k]].code |= ID_ROCK;
+	    rocks[Nrocks].ra    = R1[0];
+	    rocks[Nrocks].dec   = D1[0];
+	    rocks[Nrocks].mag   = M1[0];
+	    rocks[Nrocks].t     = T1[0];
+	    rocks[Nrocks+1].ra  = R1[1];
+	    rocks[Nrocks+1].dec = D1[1];
+	    rocks[Nrocks+1].mag = T1[1];
+	    rocks[Nrocks+1].t   = M1[1];
+	    rocks[Nrocks+2].ra  = R;
+	    rocks[Nrocks+2].dec = D;
+	    rocks[Nrocks+2].mag = M;
+	    rocks[Nrocks+2].t   = T;
+	    fprintf (stderr, "%f %f %f %d   %f\n", rocks[Nrocks].ra, rocks[Nrocks].dec, rocks[Nrocks].mag, rocks[Nrocks].t, speed);
+	    Nrocks += 3;
+	    if (Nrocks > NROCKS - 3) {
+	      NROCKS += 3000;
+	      REALLOCATE (rocks, Rocks, NROCKS);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  fprintf (stderr, "found %d rocks\n", Nrocks);
+
+  free (R1);
+  free (D1);
+  free (M1);
+  free (T1);
+  free (X1);
+  free (Y1);
+  free (N1);
+
+  REALLOCATE (rocks, Rocks, Nrocks);
+  *nrocks = Nrocks;
+  return (rocks);
+
+}
Index: /trunk/Ohana/src/markrock/src/gcatalog.c
===================================================================
--- /trunk/Ohana/src/markrock/src/gcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/gcatalog.c	(revision 2490)
@@ -0,0 +1,31 @@
+# include "markrock.h"
+
+gcatalog (Catalog *catalog) {
+  
+  char filename[128];
+  int i, status, mode;
+  unsigned int NotTrail;
+  unsigned short NotBad;
+
+  mode = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+  if (!load_catalog (catalog, mode, VERBOSE)) {
+    fprintf (stderr, "ERROR: failure loading catalog\n");
+    exit (1);
+  }
+
+  if (RESET) {
+    NotBad = (0xffff ^ 0xc003);
+    for (i = 0; i < catalog[0].Naverage; i++) {
+      if ((catalog[0].average[i].code & ID_MOVING) &&
+	  (catalog[0].average[i].code & ID_BAD_OBJECT) &&
+	  (catalog[0].average[i].code & 0x0003)) {
+	/* this will set the correct bit for each to 0 */ 
+	catalog[0].average[i].code &= NotBad;
+      }
+    }
+    for (i = 0; i < catalog[0].Nmeasure; i++) {
+      catalog[0].measure[i].flags &= ~PART_OF_TRAIL;
+    }
+  }
+}
Index: /trunk/Ohana/src/markrock/src/gcatstats.c
===================================================================
--- /trunk/Ohana/src/markrock/src/gcatstats.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/gcatstats.c	(revision 2490)
@@ -0,0 +1,54 @@
+# include "markrock.h"
+
+gcatstats (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i;
+  double RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  int *N1;
+  Coords tcoords;
+  
+  fits_scan (&catalog[0].header, "RA0", "%lf", 1, &MinRA);
+  fits_scan (&catalog[0].header, "RA1", "%lf", 1, &MaxRA);
+  fits_scan (&catalog[0].header, "DEC0", "%lf", 1, &MinDEC);
+  fits_scan (&catalog[0].header, "DEC1", "%lf", 1, &MaxDEC);
+
+ /* double check on region RA and DEC ranges */
+  DecCenter = 0.5*(MinDEC + MaxDEC);
+  RaCenter = 0.5*(MinRA + MaxRA);
+
+  catstats[0].RA[0] = MinRA;
+  catstats[0].RA[1] = MaxRA;
+  catstats[0].DEC[0] = MinDEC;
+  catstats[0].DEC[1] = MaxDEC;
+  /* number of stars per square arcsec */
+
+  /** allocate local arrays **/
+  ALLOCATE (catstats[0].X, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].Y, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].N, int,   catalog[0].Naverage);
+
+  /* project onto rectilinear grid with 1 arcsec pixels, sort by X */
+  /* reference for coords is center of field  */
+  catstats[0].coords.crval1 = RaCenter;
+  catstats[0].coords.crval2 = DecCenter;
+  catstats[0].coords.crpix1 = catstats[0].coords.crpix2 = 0.0;
+  catstats[0].coords.cdelt1 = catstats[0].coords.cdelt2 = 1.0 / 3600.0;
+  catstats[0].coords.pc1_1 = catstats[0].coords.pc2_2 = 1.0;
+  catstats[0].coords.pc1_2 = catstats[0].coords.pc2_1 = 0.0;
+  strcpy (catstats[0].coords.ctype, "RA---TAN");
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  for (i = 0; i < catalog[0].Naverage; i++, X1++, Y1++) {
+    fRD_to_XY (X1, Y1, catalog[0].average[i].R, catalog[0].average[i].D, &catstats[0].coords);
+    catstats[0].N[i] = i;
+  }
+  if (catalog[0].Naverage > 1) sort_lists (catstats[0].X, catstats[0].Y, catstats[0].N, catalog[0].Naverage);
+  
+}
+
Index: /trunk/Ohana/src/markrock/src/gregions.c
===================================================================
--- /trunk/Ohana/src/markrock/src/gregions.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/gregions.c	(revision 2490)
@@ -0,0 +1,134 @@
+# include "markrock.h"
+
+GSCRegion *gregions1 (catstats, Nregions)
+CatStats catstats[];
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  int i, j, k, x, y, done, nregion, nregion2, NREGION;
+  double ra, dec, dx, dy, Xo[4], Yo[4];
+  FILE *f;
+
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: could not open GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  nregion = 0;
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+
+  if (catstats[0].DEC[0] == 86.25) { /* pole region */
+    dec = 86.0;
+    for (ra = 0.1; ra < 370; ra+= 30.0) {
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion - 1) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  } else {
+    for (x = 0; x < 2; x++) {
+      for (y = 0; y < 2; y++) {
+	for (dx = -0.1; dx <= 0.1; dx += 0.2) {
+	  for (dy = -0.1; dy <= 0.1; dy += 0.2) {
+	    ra  = catstats[0].RA[x] + dx;
+	    dec = catstats[0].DEC[y] + dy;
+	    aregion (&region[nregion], f, ra, dec);
+	    done = FALSE;
+	    for (j = 0; (j < nregion) && !done; j++) {
+	      if (!strcmp (region[nregion].filename, region[j].filename)) {
+		done = TRUE;
+	      }
+	    }
+	    if (!done) {
+	      nregion ++;
+	    } 
+	    if (nregion == NREGION) {
+	      NREGION += 10;
+	      REALLOCATE (region, GSCRegion, NREGION);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "using %d regions\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "region %d: %f %f  %f %f\n", i, region[i].RA[0], region[i].RA[1], region[i].DEC[0], region[i].DEC[1]);
+    } 
+  }
+
+  REALLOCATE (region, GSCRegion, MAX (nregion, 1));
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
+
+GSCRegion *gregions2 (image, Nregions)
+Image *image;
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dr, dd, dec, ra;
+  int i, j, done, nregion, NREGION;
+  
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "found %d region files:\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "  %d %s\n", i, region[i].filename);
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /trunk/Ohana/src/markrock/src/load_gsc_data.c
===================================================================
--- /trunk/Ohana/src/markrock/src/load_gsc_data.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/load_gsc_data.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "markrock.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+load_gsc_data (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes, Nregions;
+  double R, D, M, MagLimit;
+  FILE *f;
+  GSCRegion *region, *gregions1(), *gregions2();
+  
+  region = gregions1 (catstats, &Nregions);
+
+  MagLimit = 25;
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  Nbytes = BLOCK*BYTES_STAR;
+  
+  for (j = 0; j < Nregions; j++) {
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "GSC file for region %s missing\n", region[j].filename);
+      exit (0);
+    }
+    
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > MagLimit) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+    fclose (f);
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, nstar);
+  catalog[0].Naverage = nstar;
+  
+}
+
Index: /trunk/Ohana/src/markrock/src/markrock.c
===================================================================
--- /trunk/Ohana/src/markrock/src/markrock.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/markrock.c	(revision 2490)
@@ -0,0 +1,80 @@
+# include "markrock.h"
+
+main (int argc, char **argv) {
+  
+  int i, Nrocks1, Nrocks2;
+  Catalog catalog;
+  CatStats catstats;
+  Rocks *rocks1, *rocks2, *find_rocks(), *find_slow_rocks();
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (&argc, argv);
+  
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  FORCE_RUN = FALSE;
+  if ((i = get_argument (argc, argv, "-f"))) {
+    FORCE_RUN = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  RESET = FALSE;
+  if ((i = get_argument (argc, argv, "-reset"))) {
+    RESET = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: markstar (catalog)\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_permissions (argv[1]);
+  check_permissions (RockCat);
+
+  catalog.filename = argv[1];
+  switch (lock_catalog (&catalog, LCK_XCLD)) {
+  case 0:
+    fprintf (stderr, "ERROR: can't lock file\n");
+    exit (1);
+  case 1:
+    gcatalog (&catalog); /* load from disk */
+    break;
+  case 2:
+    fprintf (stderr, "no data in %s, skipping\n", catalog.filename);
+    catalog.Naverage = 0;
+    catalog.Nmeasure = 0;
+    unlock_catalog (&catalog);
+    exit (0);
+  default:
+    fprintf (stderr, "weird lock_catalog exit state\n");
+    exit (1);
+  }
+
+  gcatstats (&catalog, &catstats);
+
+  find_bright_stars (&catalog, &catstats); 
+
+  rocks1 = find_rocks (&catalog, &catstats, &Nrocks1); 
+  count_neighbors (rocks1, Nrocks1, &catalog, &catstats);
+
+  /* rocks2 = find_slow_rocks (&catalog, &catstats, &Nrocks2);  */
+
+  wcatalog (&catalog);
+  wrocks (rocks1, Nrocks1);
+
+  unlock_catalog (&catalog);
+  /* wrocks (rocks2, Nrocks2); */
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+
+  fprintf (stderr, "SUCCESS\n");
+}
+
Index: /trunk/Ohana/src/markrock/src/old/add_unfound.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/add_unfound.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/add_unfound.c	(revision 2490)
@@ -0,0 +1,35 @@
+  /* incorporate unmatched image stars -- after all catalogs searched... */
+  for (i = 0; i < Nstars; i++) {
+    if (!found[i]) {
+      catalog[0].average[Nave].R = stars[N1[i]].R;
+      catalog[0].average[Nave].D = stars[N1[i]].D;
+      catalog[0].average[Nave].M = 1000.0*stars[N1[i]].M;
+      catalog[0].average[Nave].Nm = 1;
+      catalog[0].average[Nave].Xp = catalog[0].average[Nave].Xm = 0.0;
+      catalog[0].average[Nave].offset = Nmeas;
+      catalog[0].measure[Nmeas].dR  = 0.0;
+      catalog[0].measure[Nmeas].dD  = 0.0;
+      catalog[0].measure[Nmeas].M   = 1000.0*stars[N1[i]].M;
+      catalog[0].measure[Nmeas].dM  = stars[N1[i]].dM;
+      catalog[0].measure[Nmeas].t  = 3600.0 + stars[N1[i]].Y*0.1;
+      catalog[0].measure[Nmeas].average = (0x00ffffff & Nave);
+      /* time of star = time of image + offset + Y*rate */
+      Nave ++;
+      if (Nave == 0x1000000) {
+	fprintf (stderr, "too many stars in catalog\n");
+	clear_lockfile ();
+	exit (0);
+      }
+      if (Nave == NAVE) {
+	NAVE = Nave + 1000;
+	REALLOCATE (next, int, NAVE);
+	REALLOCATE (catalog[0].average, Average, NAVE);
+      }
+      Nmeas ++;
+      if (Nmeas == NMEAS) {
+	NMEAS = Nmeas + 1000;
+	REALLOCATE (next, int, NMEAS);
+	REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      }
+    }
+  }
Index: /trunk/Ohana/src/markrock/src/old/addstar.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/addstar.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/addstar.c	(revision 2490)
@@ -0,0 +1,70 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, Nstars, Nimage, Nregions, Nmissed;
+  Stars *stars, *gstars();
+  Image image, *pimage, *gimages();
+  Catalog catalog;
+  GSCRegion *region, *gregions();
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: addstar filename\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile ();
+
+  stars = gstars (argv[1], &Nstars, &image);
+
+  pimage = gimages (&image, &Nimage);
+  region = gregions (&image, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    gcatalog (&region[i], &catalog);
+    find_matches (&region[i], stars, Nstars, &catalog, &image, pimage, Nimage);
+    wcatalog (&region[i], &catalog);
+  }
+  
+  for (Nmissed = i = 0; i < Nstars; i++) {
+    if (stars[i].found == -1) {
+      fprintf (stderr, "%d %f %f %f %f\n", i, stars[i].R, stars[i].D, stars[i].M, stars[i].dM);
+      Nmissed ++;
+    }
+  }
+  if (Nmissed) fprintf (stderr, "WARNING: %d stars in image were missed!\n", Nmissed);
+
+  wimage (argv[1], &image, Nstars);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile ();
+  fprintf (stderr, "SUCCESS\n");
+}
+
+
+  /* stars within a file are not all within 1 region file:
+     1) check if unfound stars are in current region 
+     2) if not, keep unfound for next pass */
+
+
+/* input star lists should be adjusted so 1 e/sec is mag 25.000 */ 
+
+
Index: /trunk/Ohana/src/markrock/src/old/aregion.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/aregion.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/aregion.c	(revision 2490)
@@ -0,0 +1,189 @@
+# include "markstar.h"
+
+double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+			 52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+			 0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+			 -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+		       "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+		       "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+		       "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			"n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			"s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			"s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		"disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		"disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+                   0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+/* find region file which contains ra, dec */
+aregion (region, f, ra, dec) 
+GSCRegion region[];
+FILE *f;
+double ra, dec;
+{
+
+  
+  
+  char buffer[28800], temp[50], file[50];
+  double dr, dd;
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done, nregion;
+  
+  while (ra < 0) {
+    ra += 360.0;
+  }
+    
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt\0", GSCDIR);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] = -180.0;
+    region[0].RA[1] =  540.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+# ifdef DEBUG
+    fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+# ifdef DEBUG
+      fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+# ifdef DEBUG
+    fprintf (stderr, "%f %f %f  %f %f %f  %s\n", DEC0, dec, DEC1, RA0, ra, RA1, temp);
+# endif
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    clear_lockfile ();
+    exit (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt\0", GSCDIR, Dec2Sections[NBigDec],&temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
+
+
+/**********/
+int hms_to_deg (h0, h1, d0, d1, string) 
+     char *string;
+     double *h0, *h1, *d0, *d1;
+{
+  
+  int flag_d0, flag_d1, flag_h0, flag_h1;
+  double tmp;
+  
+  *d0 = *h0 = *d1 = *h1 = 0;
+
+  flag_h0 = dparse (h0, 1, string);
+  flag_h1 = dparse (h1, 4, string);
+  flag_d0 = dparse (d0, 7, string);
+  flag_d1 = dparse (d1, 9, string);
+  *h0 *= flag_h0;
+  *h1 *= flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  dparse (&tmp, 2, string);
+  *h0 += tmp/60.0;
+  dparse (&tmp, 3, string);
+  *h0 += tmp/3600.0;
+  
+  dparse (&tmp, 5, string);
+  *h1 += tmp/60.0;
+  dparse (&tmp, 6, string);
+  *h1 += tmp/3600.0;
+  
+  dparse (&tmp, 8, string);
+  *d0 += tmp/60.0;
+
+  dparse (&tmp, 10, string);
+  *d1 += tmp/60.0;
+
+  *h0 *= 15*flag_h0;
+  *h1 *= 15*flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  return (TRUE);
+}
+
+
+/*
+      if (buffer[i*48 + 19] == ' ') continue;
+      strncpy (temp, &buffer[i*48 + 19], 20);       temp[20] = 0;
+      hms_to_deg (&RA,  &DEC, temp, ' ', 3);
+
+
+  dBigRA = 360.0 / (int)(0.5 + 48*cos(3.1415927*0.5*(BigDecBounds[NBigDec] + BigDecBounds[NBigDec + 1])/180.0));
+
+  NBigRA = ra / dBigRA;
+
+  NBig = NBigRA;
+  for (i = 0; (i < 12) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+  for (i = 13; (i < 24) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+
+
+  fprintf (stderr, "%d %d %d %d %f %f -> %f %f %f\n", NBigDec, NBigRA, NBigRASections[NBigDec], NBig, ra, dec, BigDecBounds[NBigDec], BigDecBounds[NBigDec + 1], dBigRA);
+*/
Index: /trunk/Ohana/src/markrock/src/old/dumpcat.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/dumpcat.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/dumpcat.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  int i, j, Nstars, Nimage, Nregions;
+  Average *average;
+  Measure *measure;
+  Missing *missing;
+  Catalog catalog;
+  GSCRegion region;
+  FILE *f;
+  
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: dumpcat catalog output mode(0,1,2,3)\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  strcpy (region.filename, argv[1]);
+
+  gcatalog (&region, &catalog);
+
+  f = fopen (argv[2], "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "failed to open file %s for write\n", argv[2]);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  average = catalog.average;
+  for (i = 0; i < catalog.Naverage; i++) {
+    fprintf (f, "%10.6f %10.6f %7.3f %3d %3d %8d %d\n", average[i].R, average[i].D, 
+	     0.001*average[i].M, average[i].Nm, average[i].Nn, average[i].offset, catalog.measure[average[i].offset].t);
+    if ((atof(argv[3]) == 1) || (atof(argv[3]) == 3)) {
+      measure = &catalog.measure[average[i].offset];
+      for (j = 0; j < average[i].Nm; j++) {
+	fprintf (f, "  %d %d %f %f %d\n", measure[j].dR, measure[j].dD, 0.001*measure[j].M, 
+		  measure[j].t, measure[j].average);
+      }
+    }
+    if ((atof(argv[3]) == 2) || (atof(argv[3]) == 3)) {
+      if (average[i].Nn > 0) {
+	missing = &catalog.missing[average[i].missing];
+	for (j = 0; j < average[i].Nn; j++) {
+	  fprintf (f, "  %f\n", missing[j].t);
+	}
+      } else { 
+	fprintf (f, "no missing obs\n");
+      }
+    }
+  }
+
+    
+
+  fclose (f);
+    
+
+}
Index: /trunk/Ohana/src/markrock/src/old/find_bright_stars.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/find_bright_stars.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/find_bright_stars.c	(revision 2490)
@@ -0,0 +1,142 @@
+# include "markstar.h"
+
+find_bright_stars (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, n, m, first_j, Nave, Ngsc;
+  Catalog GSCdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2;
+  char *mark;
+  double dX, dY, dR, MaxDist, MaxDist1, MaxRadius, radius, radius2;
+
+  load_gsc_data (&GSCdata, catstats);
+
+  Nave = catalog[0].Naverage;
+  Ngsc = GSCdata.Naverage;
+    
+  /* in the function below, it is better to have the catalog with
+     more stars associated with index 2 (j) */ 
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+  ALLOCATE (X1, float, Ngsc);
+  ALLOCATE (Y1, float, Ngsc);
+  ALLOCATE (N1, int, Ngsc);
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Ngsc; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], GSCdata.average[i].R, GSCdata.average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Ngsc > 1) sort_lists (X1, Y1, N1, Ngsc);
+  
+  /* first find stellar halos */
+  /* max radius (mag = -1) */
+  /** the j index moves quickly and is better associated with the catalog with more stars */
+  MaxRadius = BRIGHT_HALO_SLOPE * (-1.0 - BRIGHT_HALO_MAG); 
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*MaxRadius) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*MaxRadius) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    radius = MAX (BRIGHT_HALO_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_HALO_MAG), 0.0);
+    if (radius == 0) {
+      i++; 
+      continue;
+    }
+    radius2 = radius*radius;
+    for (; (dX > -2*radius) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < radius2) {  /* new measurement of this star */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find y spikes */
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -BRIGHT_YTRAIL_WIDTH) {
+      i++;
+      continue;
+    }
+    if (dX >= BRIGHT_YTRAIL_WIDTH) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist = MAX (BRIGHT_YTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_YTRAIL_MAG), 0.0);
+    for (; (dX > -BRIGHT_YTRAIL_WIDTH) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dX) < BRIGHT_YTRAIL_WIDTH) && (fabs(dY) < MaxDist)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find x spikes */
+  /** find catalog stars near GSC stars **/
+  MaxDist = MAX (BRIGHT_XTRAIL_SLOPE * (-1.0 - BRIGHT_XTRAIL_MAG), 0.0);
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -MaxDist) {
+      i++;
+      continue;
+    }
+    if (dX >= MaxDist) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist1 = MAX (BRIGHT_XTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_XTRAIL_MAG), 0.0);
+    for (; (dX > -MaxDist1) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dY) < BRIGHT_XTRAIL_WIDTH) && (fabs(dX) < MaxDist1)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+
+  /* done with search, mark selected stars */
+  for (i = 0; i < Nave; i++) {
+    if (mark[i]) {
+      catalog[0].average[N2[i]].code = ID_BLEED;
+    }
+  } 
+  
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (mark);
+  free (GSCdata.average);
+
+}
+
Index: /trunk/Ohana/src/markrock/src/old/find_bright_stars_test.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/find_bright_stars_test.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/find_bright_stars_test.c	(revision 2490)
@@ -0,0 +1,106 @@
+# include "markstar.h"
+
+find_bright_stars (catalog, catstats, filename)
+Catalog catalog[];
+CatStats catstats[];
+char *filename;
+{
+
+  int i, j, first_j, Nave, Ngsc;
+  Catalog GSCdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2, *match;
+  char *mark;
+  double dX, dY, dR, RADIUS2, BRIGHT_RADIUS, radius;
+
+  load_gsc_data (&GSCdata, filename);
+
+  Nave = catalog[0].Naverage;
+  Ngsc = GSCdata.Naverage;
+    
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  N1 = catstats[0].N;
+  ALLOCATE (mark, char, Nave);
+  ALLOCATE (match, int, Nave);
+  ALLOCATE (X2, float, Ngsc);
+  ALLOCATE (Y2, float, Ngsc);
+  ALLOCATE (N2, int, Ngsc);
+  bzero (mark, Nave);
+
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Ngsc; i++) {
+    fRD_to_XY (&X2[i], &Y2[i], GSCdata.average[i].R, GSCdata.average[i].D, tcoords);
+    N2[i] = i;
+  }
+  if (Ngsc > 1) sort_lists (X2, Y2, N2, Ngsc);
+  
+  /* max radius (mag = -1) */
+  BRIGHT_RADIUS = BRIGHT_SLOPE * (-1.0 - BRIGHT_MAG);
+
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Nave) && (j < Ngsc); ) {
+    
+    dX = X1[i] - X2[j];
+
+    if (dX <= -2*BRIGHT_RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*BRIGHT_RADIUS) {
+      j++;
+      continue;
+    }
+
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*BRIGHT_RADIUS) && (j < Ngsc); j++) {
+      radius = MAX (BRIGHT_SLOPE * (0.001*GSCdata.average[N2[j]].M - BRIGHT_MAG), 0.0);
+      RADIUS2 = radius*radius;
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < RADIUS2) {  /* new measurement of this star */
+	mark[i] = TRUE;
+	match[i] = N2[j];
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* done with search, mark selected stars */
+  
+  for (i = 0; i < Nave; i++) {
+    if (mark[i]) {
+      catalog[0].average[N1[i]].code = ID_BLEED;
+    }
+  } 
+  
+}
+
+	/* for test purposes, like determining the parameters, uncomment this 
+	n = N1[i];
+	m = N2[j];
+	fprintf (stdout, "%f %f %f %f %f %f\n", 
+GSCdata.average[m].R, GSCdata.average[m].D, 
+		 0.001*GSCdata.average[m].M, 
+catalog[0].average[n].R, catalog[0].average[n].D, 0.001*catalog[0].average[n].M); */
+  
+  /* for test purposes, like determining the parameters, uncomment this 
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+  exit (0); */
+
+
+
+	n = N1[i];
+	m = N2[j];
+	RD_to_XY (&X, &Y, Ghostdata[0].average[m].R, Ghostdata[0].average[m].D, &image[0].coords);
+	fprintf (stdout, "%f %f %f %f %f %f %d %f %f\n",
+		 Ghostdata[0].average[m].R, Ghostdata[0].average[m].D, 
+		 0.001*Ghostdata[0].average[m].M, catalog[0].average[n].R, 
+		 catalog[0].average[n].D, 0.001*catalog[0].average[n].M, 
+		 catalog[0].average[n].Nm, X, Y);
Index: /trunk/Ohana/src/markrock/src/old/find_images.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/find_images.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/find_images.c	(revision 2490)
@@ -0,0 +1,175 @@
+# include "markstar.h"
+double opening_angle ();
+
+Image *find_images (catstats, Nimages)
+CatStats catstats[];
+int *Nimages;
+{
+  
+  Header header;
+  Image *timage, *image;
+  int i, j, k, found, nimage, Nimage, NIMAGE, NTIMAGE, Nloop, Nlast;
+  int n, Nim, status;
+  FILE *f;
+  double Xc[5], Yc[5], Xi[5], Yi[5], r, d;
+  Coords *tcoords;
+
+  /* we make positional comparisons in the projection of catalog */
+  tcoords = &catstats[0].coords;
+  /* define catalog corners */
+  Xc[0] = catstats[0].RA[0]; Yc[0] = catstats[0].DEC[0];
+  Xc[1] = catstats[0].RA[1]; Yc[1] = catstats[0].DEC[0];
+  Xc[2] = catstats[0].RA[1]; Yc[2] = catstats[0].DEC[1];
+  Xc[3] = catstats[0].RA[0]; Yc[3] = catstats[0].DEC[1];
+  Xc[4] = catstats[0].RA[0]; Yc[4] = catstats[0].DEC[0];
+  for (j = 0; j < 5; j++) {
+    r = Xc[j]; d = Yc[j];
+    RD_to_XY (&Xc[j], &Yc[j], r, d, tcoords);
+  }
+
+  /* check if image datafile exists, get header, number of images */
+  if (!fits_read_header (ImageCat, &header)) {
+    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
+    clear_lockfile ();
+    exit (0);
+  }
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  if (Nimage == 0) {
+    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: trouble opening Image catalog: %s (2)\n", ImageCat);
+    clear_lockfile ();
+    exit (0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* set up buffers for images, temporary storage */
+  NTIMAGE = 100;
+  ALLOCATE (timage, Image, NTIMAGE);
+  NIMAGE = 100;
+  ALLOCATE (image, Image, NIMAGE);
+  nimage = 0;
+  Nloop = Nimage / NTIMAGE + 1;
+  Nlast = Nimage % NTIMAGE;
+  
+  /* read in images in groups of NTIMAGE (100) */
+  for (n = 0; n < Nloop; n++) {
+    Nim = (n == Nloop - 1) ? Nlast : NTIMAGE;
+    status = Fread (timage, sizeof(Image), Nim, f, "image");
+    if (status != Nim) {
+      fprintf (stderr, "ERROR: couldn't read images from image catalog: %s\n", ImageCat);
+      clear_lockfile ();
+      exit (0);
+    }
+    /* test each image in block */
+    for (i = 0; i < Nim; i++) {
+      /* define image corners */
+      Xi[0] = 0;            Yi[0] = 0;
+      Xi[1] = timage[i].NX; Yi[1] = 0;
+      Xi[2] = timage[i].NX; Yi[2] = timage[i].NY;
+      Xi[3] = 0;            Yi[3] = timage[i].NY;
+      Xi[4] = 0.5*timage[i].NX; Yi[4] = 0.5*timage[i].NY;
+      found = FALSE;
+      /* transform to tcoords */
+      for (j = 0; j < 5; j++) {
+	XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	RD_to_XY (&Xi[j], &Yi[j], r, d, tcoords);
+      }
+      /* check if edges cross */
+      for (j = 0; (j < 4) && !found; j++) {
+	for (k = 0; (k < 4) && !found; k++) {
+	  found |= edge_check (&Xi[j], &Yi[j], &Xc[k], &Yc[k]);
+	}
+      }
+      if (found) {
+	image[nimage] = timage[i]; 
+	image[nimage].code = 0;
+	nimage ++;
+	if (nimage == NIMAGE) {
+	  NIMAGE += 100;
+	  REALLOCATE (image, Image, NIMAGE);
+	}
+      }
+    }
+  }
+      
+  if (VERBOSE) { 
+    for (i = 0; i < nimage; i++) {
+      XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+      fprintf (stderr, "associated images: %d %8.4f %8.4f %10d %6d  %5.3f %6.3f %6.3f\n", 
+	       i, r, d, image[i].tzero, image[i].nstar, 0.001*image[i].secz, 
+	       0.001*image[i].Mcal, 0.001*image[i].dMcal);
+    }
+  }
+
+  REALLOCATE (image, Image, MAX (nimage, 1));
+  free (timage);
+  *Nimages = nimage;
+  fclose (f);
+  return (image);
+}
+
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+double opening_angle (x1, y1, x2, y2, x3, y3)
+double x1, y1, x2, y2, x3, y3;
+{
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
+
Index: /trunk/Ohana/src/markrock/src/old/find_line.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/find_line.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/find_line.c	(revision 2490)
@@ -0,0 +1,161 @@
+# include "markstar.h"
+
+find_line (catstats, mark, Npts, i, M, B, Angle)
+     CatStats catstats[];
+     double *M, *B, Angle;
+     int i, Npts;
+     char *mark;
+{
+  
+  float *R, *D;
+  int j, N;
+  double X, Y, X2, Y2, XY, m, b, det;
+  double dR, dD, Ra, De, angle;
+  char Flipped;
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+
+  /* fit a line to points near line */
+  Ra = R[i];
+  De = D[i];
+  X = Ra;
+  Y = De;
+  X2 = Ra*Ra;
+  Y2 = De*De;
+  XY = Ra*De;
+  N = 1;
+  /* points to the east */
+  for (j = i + 1; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      if (fabs(angle - Angle) < RAD_DEG) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* points to the west */
+  for (j = i - 1; !mark[i] && (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      if (fabs(angle - Angle) < RAD_DEG) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* determine coeffs */
+  Flipped = 0;
+  det = 1.0 / (X2*N - X*X);
+  m = det * (XY*N - X*Y);
+  b = det * (X2*Y - XY*X);
+  if (fabs(m) > 1.1) { /* use a line of R = m*D + b instead */
+    /* fprintf (stderr, "high slope object: %f %f  -> ", m, b); */
+    det = 1.0 / (Y2*N - Y*Y);
+    m = det * (XY*N - X*Y);
+    b = det * (Y2*X - XY*Y);
+    Flipped = 1;
+    /* fprintf (stderr, "%f %f\n", m, b); */
+  }
+
+  *M = m;
+  *B = b;
+  return (Flipped);
+
+}
+
+
+find_better_line (catstats, mark, Npts, i, M, B, axis)
+     CatStats catstats[];
+     double *M, *B;
+     int i, Npts, axis;
+     char *mark;
+{
+  
+  float *R, *D;
+  int j, N;
+  double X, Y, X2, Y2, XY, m, b, det;
+  double dR, dD, Ra, De, delta;
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+
+  /* fit a line to points near line */
+  Ra = R[i];
+  De = D[i];
+  X = Y = X2 = Y2 = XY = N = 0;
+  m = *M;  b = *B;
+
+  /* points to the east */
+  for (j = i; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      if (axis == 1) 
+	delta = R[j] - m*D[j] - b;
+      else
+	delta = D[j] - m*R[j] - b;
+      if (fabs(delta) < 2*TRAIL_WIDTH) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* points to the west */
+  for (j = i - 1; (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      if (axis == 1) 
+	delta = R[j] - m*D[j] - b;
+      else
+	delta = D[j] - m*R[j] - b;
+      if (fabs(delta) < 2*TRAIL_WIDTH) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* determine coeffs */
+  if (axis == 0) {
+    det = 1.0 / (X2*N - X*X);
+    m = det * (XY*N - X*Y);
+    b = det * (X2*Y - XY*X);
+  } else {
+    det = 1.0 / (Y2*N - Y*Y);
+    m = det * (XY*N - X*Y);
+    b = det * (Y2*X - XY*Y);
+  }
+
+  /* fprintf (stderr, "%f %f %d\n", m, b, N); */
+
+  *M = m;
+  *B = b;
+
+}
Index: /trunk/Ohana/src/markrock/src/old/find_matches.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/find_matches.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/find_matches.c	(revision 2490)
@@ -0,0 +1,87 @@
+# include "markstar.h"
+
+find_matches (catalog, catstats, Ghostdata, Nimage)
+CatStats catstats[];
+Catalog catalog[], Ghostdata[];
+int Nimage;
+{
+
+  int i, j, k, n, m, N, M, first_j;
+  double X, Y, RADIUS, RADIUS2;
+  float *X1, *Y1, *X2, *Y2;
+  float dX, dY, dR;
+  int *N1, *N2;
+  int Nstar, Nghost, Ng;
+  unsigned int flags;
+  Coords *tcoords;
+
+  Nstar = catalog[0].Naverage;
+  Nghost = Ghostdata[0].Naverage;
+
+  if (Nghost < 1) return (0);
+
+  /* it is better to have the catalog with fewer stars
+     assigned to the X1 set */
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+
+  ALLOCATE (X1, float, Nghost);
+  ALLOCATE (Y1, float, Nghost);
+  ALLOCATE (N1, int, Nghost);
+
+  /* project ghosts to the frame of the catalog */
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Nghost; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], Ghostdata[0].average[i].R, Ghostdata[0].average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Nghost > 1) sort_lists (X1, Y1, N1, Nghost);
+
+  /* choose a radius for matches */
+  RADIUS2 = GHOST_RADIUS*GHOST_RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nghost) && (j < Nstar); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*GHOST_RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*GHOST_RADIUS) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*GHOST_RADIUS) && (j < Nstar); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < RADIUS2) {  
+	/* this object may be a ghost star, 
+	   but only mark those measurements on the correct image */
+	M = N2[j];
+	m = catalog[0].average[M].offset;
+	Ng = 0;
+	for (k = 0; k < catalog[0].average[M].Nm; k++) {
+	  if (catalog[0].image[m+k] == Nimage) {
+	    catalog[0].measure[m+k].average |= GHOST_DATA;
+	    Ng ++;
+	  }
+	}
+	/* all measurements are ghosts */
+	if (catalog[0].average[M].Nm == Ng) {
+	  catalog[0].average[M].code = ID_GHOST;
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+
+  free (X1);
+  free (Y1);
+  free (N1);
+
+}
Index: /trunk/Ohana/src/markrock/src/old/find_trails.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/find_trails.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/find_trails.c	(revision 2490)
@@ -0,0 +1,41 @@
+# include "markstar.h"
+
+find_trails (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, N, Nave, axis, marked;
+  double density, spacing, Area, Angle, m, b, RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  char *mark;
+  int *N1;
+  Coords tcoords;
+  
+  Nave = catalog[0].Naverage;
+  N1 = catstats[0].N;
+
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  for (i = 0; i < Nave; i++) {
+    /* already marked, ignore */
+    if ((mark[i]) || 
+	(catalog[0].average[N1[i]].code == ID_BLEED) || 
+	(catalog[0].average[N1[i]].code == ID_GHOST))
+      continue;
+    /* a good star, ignore */
+    if ((catalog[0].average[N1[i]].Nm > 3) && 
+	(catalog[0].average[N1[i]].Nm > 4*catalog[0].average[N1[i]].Nn)) {
+      continue;
+    }
+    if (find_group (catstats, mark, Nave, i, &Angle)) {
+      /* this point has an excess nearby concentration, find the line */
+      axis = find_line (catstats, mark, Nave, i, &m, &b, Angle);
+      find_better_line (catstats, mark, Nave, i, &m, &b, axis);
+      mark_trail (catstats, mark, Nave, i, m, b, axis, catalog);
+    }
+  }
+}
+
Index: /trunk/Ohana/src/markrock/src/old/gimages.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/gimages.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/gimages.c	(revision 2490)
@@ -0,0 +1,214 @@
+# include "addstar.h"
+double opening_angle ();
+
+Image *gimages (image, Npimage)
+Image image[];
+int *Npimage;
+{
+  
+  int i, j, k, NIMAGE, Nimage, addtolist;
+  int NTIMAGE, Ntimage, ntimage;
+  int NPIMAGE, npimage;
+  FILE *f;
+  Image *timage, *pimage;
+  Coords tcoords;
+  Header header;
+  double r, d;
+  double Xi[5], Yi[5], Xo[5], Yo[5];  /* image and original corners */
+
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (ImageCat, &header)) {
+    if (VERBOSE) fprintf (stderr, "New image catalog %s (1)\n", ImageCat);
+    *Npimage = 0;
+    return ((Image *) NULL);
+  }
+
+  /* project onto rectilinear grid with 1 arcsec pixels */
+  /* we keep the original crpix1,2 and crref1,2 */
+  tcoords = image[0].coords;
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+  tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+  tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+  strcpy (tcoords.ctype, "RA---TAN");
+
+  /* define original corners */
+  Xo[0] = 0;           Yo[0] = 0;
+  Xo[1] = image[0].NX; Yo[1] = 0;
+  Xo[2] = image[0].NX; Yo[2] = image[0].NY;
+  Xo[3] = 0;           Yo[3] = image[0].NY;
+  Xo[4] = 0;           Yo[4] = 0;  /* so we can make a loop easily */
+  for (j = 0; j < 5; j++) {
+    XY_to_RD (&r, &d, Xo[j], Yo[j], &image[0].coords);
+    RD_to_XY (&Xo[j], &Yo[j], r, d, &tcoords);
+  }
+  
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "New image catalog: %s (2)\n", ImageCat);
+    free (header.buffer);
+    *Npimage = 0;
+    return ((Image *) NULL);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+
+  NTIMAGE = 100;
+  ALLOCATE (timage, Image, NTIMAGE);
+
+  npimage = 0;
+  NPIMAGE = 20;
+  ALLOCATE (pimage, Image, NPIMAGE);
+
+  for (Ntimage = 0; Ntimage < Nimage; Ntimage += ntimage) {
+    ntimage = Fread (timage, sizeof(Image), NTIMAGE, f, "image");
+    for (i = 0; i < ntimage; i++) {
+      addtolist = FALSE;
+      /* define image corners */
+      Xi[0] = 0;            Yi[0] = 0;
+      Xi[1] = timage[i].NX; Yi[1] = 0;
+      Xi[2] = timage[i].NX; Yi[2] = timage[i].NY;
+      Xi[3] = 0;            Yi[3] = timage[i].NY;
+      Xi[4] = 0;            Yi[4] = 0;  /* so we can make a loop easily */
+      /* transform to tcoords */
+      for (j = 0; j < 5; j++) {
+	XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	RD_to_XY (&Xi[j], &Yi[j], r, d, &tcoords);
+      }
+      /* check if any edges cross */
+      for (j = 0; j < 4; j++) {
+	for (k = 0; k < 4; k++) {
+	  addtolist |= edge_check (&Xi[j], &Yi[j], &Xo[k], &Yo[k]);
+	}
+      }
+      
+      /*
+      fprintf (stderr, "%f %f %f %d %f %f %d %d %d %f %f %s: %d\n", 0.1*timage[i].detection_limit, 0.1*timage[i].saturation_limit, 0.02*timage[i].cerror, 
+	       timage[i].tzero, 1e-4*timage[i].trate, 
+	       0.001*timage[i].secz, timage[i].nstar, timage[i].NX, timage[i].NY, 0.001*timage[i].Mcal, 0.1*timage[i].Xm, timage[i].name, addtolist);
+      
+      fprintf (stderr, "%s\n", timage[i].coords.ctype);
+      fprintf (stderr, "%f %f\n", timage[i].coords.crval1, timage[i].coords.crval2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.crpix1, timage[i].coords.crpix2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.pc1_1, timage[i].coords.pc1_2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.pc2_1, timage[i].coords.pc2_2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.cdelt1, timage[i].coords.cdelt2);      
+      */
+
+      if (addtolist) {
+	pimage[npimage] = timage[i];
+	npimage ++;
+	if (npimage == NPIMAGE) {
+	  NPIMAGE += 20;
+	  REALLOCATE (pimage, Image, NPIMAGE);
+	}
+      }
+    }
+
+    if (ntimage == 0) {
+      fprintf (stderr, "ERROR: expected %d images, only found %d\n", Nimage, Ntimage);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+
+  if (VERBOSE) fprintf (stderr, "found %d overlapping images\n", npimage);
+
+  fclose (f);
+  *Npimage = npimage;
+  return (pimage);
+
+}
+  
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+double opening_angle (x1, y1, x2, y2, x3, y3)
+double x1, y1, x2, y2, x3, y3;
+{
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
+
+
+
+
+/* probably not needed now 
+char *_parse_nextword();
+
+
+int fparse (X, NX, line)
+float *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
+
+*/
Index: /trunk/Ohana/src/markrock/src/old/gregions.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/gregions.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/gregions.c	(revision 2490)
@@ -0,0 +1,135 @@
+# include "markstar.h"
+
+GSCRegion *gregions1 (catstats, Nregions)
+CatStats catstats[];
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  int i, j, k, x, y, done, nregion, nregion2, NREGION;
+  double ra, dec, dx, dy, Xo[4], Yo[4];
+  FILE *f;
+
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: could not open GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  nregion = 0;
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+
+  if (catstats[0].DEC[0] == 86.25) { /* pole region */
+    dec = 86.0;
+    for (ra = 0.1; ra < 370; ra+= 30.0) {
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion - 1) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  } else {
+    for (x = 0; x < 2; x++) {
+      for (y = 0; y < 2; y++) {
+	for (dx = -0.1; dx <= 0.1; dx += 0.2) {
+	  for (dy = -0.1; dy <= 0.1; dy += 0.2) {
+	    ra  = catstats[0].RA[x] + dx;
+	    dec = catstats[0].DEC[y] + dy;
+	    aregion (&region[nregion], f, ra, dec);
+	    done = FALSE;
+	    for (j = 0; (j < nregion) && !done; j++) {
+	      if (!strcmp (region[nregion].filename, region[j].filename)) {
+		done = TRUE;
+	      }
+	    }
+	    if (!done) {
+	      nregion ++;
+	    } 
+	    if (nregion == NREGION) {
+	      NREGION += 10;
+	      REALLOCATE (region, GSCRegion, NREGION);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "using %d regions\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "region %d: %f %f  %f %f\n", i, region[i].RA[0], region[i].RA[1], region[i].DEC[0], region[i].DEC[1]);
+    } 
+  }
+
+  REALLOCATE (region, GSCRegion, MAX (nregion, 1));
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
+
+GSCRegion *gregions2 (image, Nregions)
+Image *image;
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dr, dd, dec, ra;
+  int i, j, done, nregion, NREGION;
+  
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", GSCFILE);
+    clear_lockfile ();
+    exit (0);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "found %d region files:\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "  %d %s\n", i, region[i].filename);
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /trunk/Ohana/src/markrock/src/old/gstars.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/gstars.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/gstars.c	(revision 2490)
@@ -0,0 +1,186 @@
+# include "addstar.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 31
+# define BLOCK 1000
+#include <sys/time.h>
+#include <time.h>
+
+Stars *gstars (file, NSTARS, image) 
+char file[];
+int *NSTARS;
+Image *image;
+{
+
+  FILE *f;
+  Header header;
+  int i, j, nstar;
+  int nbytes, Nbytes;
+  Stars *stars;
+  char *buffer, line[64], *c;
+  struct tm timeptr;
+  double tmp;
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't find image file %s\n", file);
+    clear_lockfile ();
+    exit(0);
+  }
+
+  /* open file */
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find data file %s\n", file);
+    clear_lockfile ();
+    exit(0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  c = strrchr (file, 0x2f);
+  if (c == (char *) NULL) {
+    strcpy (image[0].name, file);
+  } else { 
+    strcpy (image[0].name, (c+1));
+  }
+  /* get astrometry information */
+  strcpy (image[0].coords.ctype, "NONE");
+  fits_scan (&header, "CTYPE1",   "%s",  1, image[0].coords.ctype);
+  if (strcmp (image[0].coords.ctype, "RA---PLY")) {
+    fprintf (stderr, "ERROR: wrong astrometric info in header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  fits_scan (&header, "CDELT1",   "%f", 1, &image[0].coords.cdelt1); 
+  fits_scan (&header, "CDELT2",   "%f", 1, &image[0].coords.cdelt2);
+  fits_scan (&header, "CRVAL1",   "%lf", 1, &image[0].coords.crval1);
+  fits_scan (&header, "CRVAL2",   "%lf", 1, &image[0].coords.crval2);  
+  fits_scan (&header, "CRPIX1",   "%f", 1, &image[0].coords.crpix1);
+  fits_scan (&header, "CRPIX2",   "%f", 1, &image[0].coords.crpix2);
+  fits_scan (&header, "PC001001", "%f", 1, &image[0].coords.pc1_1);
+  fits_scan (&header, "PC001002", "%f", 1, &image[0].coords.pc1_2);
+  fits_scan (&header, "PC002001", "%f", 1, &image[0].coords.pc2_1);
+  fits_scan (&header, "PC002002", "%f", 1, &image[0].coords.pc2_2);
+  fits_scan (&header, "CERROR",   "%lf", 1, &tmp);
+  /* RA Terms */
+  fits_scan (&header, "PCA1X2Y0", "%f", 1, &image[0].coords.polyterms[0][0]);
+  fits_scan (&header, "PCA1X1Y1", "%f", 1, &image[0].coords.polyterms[1][0]);
+  fits_scan (&header, "PCA1X0Y2", "%f", 1, &image[0].coords.polyterms[2][0]);
+  fits_scan (&header, "PCA1X3Y0", "%f", 1, &image[0].coords.polyterms[3][0]);
+  fits_scan (&header, "PCA1X2Y1", "%f", 1, &image[0].coords.polyterms[4][0]);
+  fits_scan (&header, "PCA1X1Y2", "%f", 1, &image[0].coords.polyterms[5][0]);
+  fits_scan (&header, "PCA1X0Y3", "%f", 1, &image[0].coords.polyterms[6][0]);
+  /* Dec Terms */
+  fits_scan (&header, "PCA2X2Y0", "%f", 1, &image[0].coords.polyterms[0][1]);
+  fits_scan (&header, "PCA2X1Y1", "%f", 1, &image[0].coords.polyterms[1][1]);
+  fits_scan (&header, "PCA2X0Y2", "%f", 1, &image[0].coords.polyterms[2][1]);
+  fits_scan (&header, "PCA2X3Y0", "%f", 1, &image[0].coords.polyterms[3][1]);
+  fits_scan (&header, "PCA2X2Y1", "%f", 1, &image[0].coords.polyterms[4][1]);
+  fits_scan (&header, "PCA2X1Y2", "%f", 1, &image[0].coords.polyterms[5][1]);
+  fits_scan (&header, "PCA2X0Y3", "%f", 1, &image[0].coords.polyterms[6][1]);
+  image[0].coords.Npolyterms = 2; /* how many do we use? */
+  /* CERROR in data file is in pixels, convert to 20*arcsec */
+  image[0].cerror = tmp * 50.0 * image[0].coords.cdelt1 * 3600.0;
+  while (image[0].coords.crval1 < 0) image[0].coords.crval1 += 360.0;
+  while (image[0].coords.crval1 > 360.0) image[0].coords.crval1 -= 360.0;
+ 
+  fits_scan (&header, "NAXIS1",   "%hd", 1, &image[0].NX); 
+  fits_scan (&header, "NAXIS2",   "%hd", 1, &image[0].NY);
+  fits_scan (&header, "PHOTCODE", "%hd", 1, &image[0].source);
+  image[0].NX -= XOVERSCAN;
+  image[0].NY -= YOVERSCAN;
+
+  tmp = 0;
+  fits_scan (&header, "FLIMIT",   "%lf", 1, &tmp);
+  image[0].detection_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FSATUR",   "%lf", 1, &tmp);
+  image[0].saturation_limit = tmp * 10.0;
+
+  if (!fits_scan (&header, "TZERO",   "%d",  1, &image[0].tzero)) {
+    fits_scan (&header, "UT",   "%s",  1, line);
+    /* remove : characters */
+    for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (c, 0x3a))
+      *c = ' ';
+    sscanf (line, "%d %d %d", &timeptr.tm_hour, &timeptr.tm_min, &timeptr.tm_sec);
+    fits_scan (&header, "DATE-UT",   "%s",  1, line);
+    for (c = strchr (line, 0x2f); c != (char *) NULL; c = strchr (c, 0x2f))
+      *c = ' ';
+    sscanf (line, "%d %d %d", &timeptr.tm_year, &timeptr.tm_mon, &timeptr.tm_mday);
+    if (timeptr.tm_year < 90) { /* correct for year 2000 turnover */
+      timeptr.tm_year += 100;
+    }
+    image[0].tzero = mktime (&timeptr);
+  }
+
+  tmp = 0;
+  fits_scan (&header, "TRATE",   "%lf", 1, &tmp);
+  image[0].trate = 10000 * tmp;
+
+  tmp = 0;
+  fits_scan (&header, "AIRMASS", "%lf", 1, &tmp);
+  image[0].secz = 1000*tmp;
+
+  /* secz is in units milli-airmass */
+  image[0].Mcal =  ALPHA*(image[0].secz - 1000);
+  image[0].Xm   = 30.0;
+  image[0].code = 0;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+
+  /* find number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar);
+  if (image[0].nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  ALLOCATE (stars, Stars, image[0].nstar);
+  Nbytes = image[0].nstar*BYTES_STAR;
+
+  /* load in stars by blocks of 1000 */
+  nstar = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR));
+  for (i = 0; i < (int)(Nbytes / (BLOCK*BYTES_STAR)); i++) {
+    nbytes = Fread (buffer, 1, (BLOCK*BYTES_STAR), f, "char");
+    if (nbytes != BLOCK*BYTES_STAR) {
+      fprintf (stderr, "ERROR: failed to read in stars (1)\n");
+      clear_lockfile ();
+      exit (0);
+    }
+    for (j = 0; j < BLOCK; j++, nstar++) {
+      dparse (&stars[nstar].X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].M,  3, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].dM, 4, &buffer[j*BYTES_STAR]);
+      XY_to_RD (&stars[nstar].R, &stars[nstar].D, stars[nstar].X, stars[nstar].Y, &image[0].coords);
+      stars[nstar].found = -1;
+    }
+  }
+  /* left over fraction of a block */
+  nbytes = Fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f, "char");
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstar++) {
+    dparse (&stars[nstar].X, 1, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].Y, 2, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].M, 3, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].dM, 4, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&stars[nstar].R, &stars[nstar].D, stars[nstar].X, stars[nstar].Y, &image[0].coords);
+    stars[nstar].found = -1;
+  }
+
+  if (image[0].nstar != nstar) {
+    fprintf (stderr, "ERROR: failed to read in all stars (%d != %d)\n", image[0].nstar, nstar);
+    clear_lockfile ();
+    exit (0);
+  }
+  free (header.buffer);
+  free (buffer);
+ 
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+  *NSTARS = image[0].nstar;
+
+  return (stars);
+}
Index: /trunk/Ohana/src/markrock/src/old/load_gsc_data.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/load_gsc_data.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/load_gsc_data.c	(revision 2490)
@@ -0,0 +1,62 @@
+# include "markstar.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+load_gsc_data (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes, Nregions;
+  double R, D, M, MagLimit;
+  FILE *f;
+  GSCRegion *region, *gregions();
+  
+  region = gregions1 (catstats, &Nregions);
+
+  MagLimit = MAX (MAX (BRIGHT_HALO_MAG, BRIGHT_XTRAIL_MAG), BRIGHT_YTRAIL_MAG); 
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  Nbytes = BLOCK*BYTES_STAR;
+  
+  for (j = 0; j < Nregions; j++) {
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "no stars in %s, skipping\n", region[j].filename);
+      clear_lockfile ();
+      exit (0);
+    }
+    
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > MagLimit) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+    fclose (f);
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, nstar);
+  catalog[0].Naverage = nstar;
+  
+}
+
Index: /trunk/Ohana/src/markrock/src/old/load_gsc_data_ghost.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/load_gsc_data_ghost.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/load_gsc_data_ghost.c	(revision 2490)
@@ -0,0 +1,75 @@
+# include "markstar.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+/* this routine is basically identical to load_gsc_data, but
+   it is not limited to a single region file, and it merges the 
+   results */
+
+load_gsc_data_ghost (catalog, region, Nregion, image)
+Catalog catalog[];
+GSCRegion *region;
+int Nregion;
+Image image[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes;
+  double R, D, M, X, Y;
+  FILE *f;
+  Coords *tcoords;
+  int MinX, MinY, MaxX, MaxY;
+  
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  tcoords = &image[0].coords;
+  MinX = 0;
+  MinY = 0;
+  MaxX = image[0].NX;
+  MaxY = image[0].NY;
+  
+  for (j = 0; j < Nregion; j++) {
+    
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "no stars in %s, skipping\n", region[j].filename);
+      clear_lockfile ();
+      exit (0);
+    }
+    
+    Nbytes = BLOCK*BYTES_STAR;
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > GHOST_MAG) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	RD_to_XY (&X, &Y, R, D, tcoords);
+	if ((X < MinX) || (X > MaxX) || (Y < MinY) || (Y > MaxY)) continue;
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, MAX (nstar, 1));
+  catalog[0].Naverage = nstar;
+
+}
+
+
Index: /trunk/Ohana/src/markrock/src/old/mark_trail.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/mark_trail.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/mark_trail.c	(revision 2490)
@@ -0,0 +1,250 @@
+# include "markstar.h"
+int *make_common_list ();
+int *check_common_list ();
+
+mark_trail (catstats, mark, Nave, i, m, b, axis, catalog)
+     CatStats catstats[];
+     char *mark;
+     int i, Nave, axis;
+     double m, b;
+     Catalog catalog[];
+{
+
+  float *R, *D;
+  int j, k, jj, kk, N, NPTS, marked, start, end, Nm;
+  int *good, *seq, *N1;
+  double *dist, *dist2;
+  double d2, di, Di, dD, n, Dist, scale, norm;
+  double spacing;
+  int *list, Nlist;
+  int M, Nmeas, thisimage;
+
+  R = catstats[0].X;
+  D = catstats[0].Y;
+  N1 = catstats[0].N;
+  spacing = catstats[0].spacing;
+
+  NPTS = 200;
+  ALLOCATE (good, int, NPTS);
+  ALLOCATE (dist, double, NPTS);
+  ALLOCATE (dist2, double, NPTS);
+  ALLOCATE (seq, int, NPTS);
+
+  /* Find all points which lie near line */
+  /* save the entry number and distance along line */
+  N = 0;
+  scale = sqrt (1.0 + m*m);
+
+  if (axis == 1) {
+    for (j = 0; j < Nave; j++) {
+      norm = scale * fabs(R[j] - m*D[j] - b);
+      if (!mark[j] && (norm < TRAIL_WIDTH)) {
+	good[N] = j;
+	dist[N] = scale * (D[j] - D[i] + m*(R[j] - R[i]));
+	seq[N] = N;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 200;
+	  REALLOCATE (good, int, NPTS);
+	  REALLOCATE (dist, double, NPTS);
+	  REALLOCATE (dist2, double, NPTS);
+	  REALLOCATE (seq, int, NPTS);
+	}
+      }
+    }
+  } else {
+    for (j = 0; j < Nave; j++) {
+      norm = scale * fabs(D[j] - m*R[j] - b);
+      if (!mark[j] && (norm < TRAIL_WIDTH)) {
+	good[N] = j;
+	dist[N] = scale * (R[j] - R[i] + m*(D[j] - D[i]));
+	seq[N] = N;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 200;
+	  REALLOCATE (good, int, NPTS);
+	  REALLOCATE (dist, double, NPTS);
+	  REALLOCATE (dist2, double, NPTS);
+	  REALLOCATE (seq, int, NPTS);
+	}
+      }
+    }
+  }
+  
+  if (N < NPTSINLINE) 
+    return (0);
+
+  sort_seq (dist, seq, N);
+  
+  start = -1; end = -1;
+  for (j = 0; j < N-1; j++) {
+    /* if we have part of a line, and next point is in the line, check for common images */
+    if ((start != -1) && (fabs(dist[j] - dist[j+1]) < spacing)) {
+      list = check_common_list (list, N1[good[seq[j+1]]], &Nlist, catalog);
+      if (Nlist == 0) { /* if no common images, dump list and continue */
+	end = j + 1;
+	if (end - start > NPTSINLINE) {
+	  if (axis == 0)
+	    fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", m, b, N, end-start, start, end, dist[start], dist[end-1]);
+	  else
+	    fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", 1.0/m, -1.0*b/m, N, end-start, start, end, dist[start], dist[end-1]);
+	  for (k = start; k < end; k++) {
+	    M = N1[good[seq[k]]];
+	    mark[good[seq[k]]] = TRUE;
+	    /* we need to mark measurements from all images in common on the line */
+	    Nm = 0;
+	    for (jj = 0; jj < catalog[0].average[M].Nm; jj++) {
+	      Nmeas = catalog[0].average[M].offset + jj;
+	      thisimage = catalog[0].image[Nmeas];
+	      for (kk = 0; kk < Nlist; kk++) {
+		if (thisimage == list[kk]) {
+		  catalog[0].measure[Nmeas].average |= PART_OF_TRAIL;
+		  Nm ++;
+		}
+	      }
+	    }
+	    /* if there is only 1 measurement, mark object as bad */
+	    if (catalog[0].average[M].Nm == Nm) {
+	      catalog[0].average[M].code = ID_TRAIL;
+	    }
+	    catalog[0].average[M].code = ID_TRAIL;
+	  }
+	}
+	start = -1;
+	end = -1;
+      }
+    }
+    /* if we haven't yet found a line segment, check for the beginning */
+    if ((start < 0) && (fabs(dist[j] - dist[j+1]) < spacing)) {
+      start = j;
+      list = make_common_list (N1[good[seq[j]]], N1[good[seq[j+1]]], &Nlist, catalog);
+      if (Nlist == 0) { /* if no common images, move on */
+	start = -1;
+	free (list);
+      }
+    }
+    /* if we have a complete line, check for validity.  if it has enough members,
+	 mark them and continue searching for lines */
+    if ((start != -1) && ((fabs(dist[j] - dist[j+1]) >= spacing) || (j == N-2))) {
+      end = j + 1;
+      if (end - start > NPTSINLINE) {
+	if (axis == 0)
+	  fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", m, b, N, end-start, start, end, dist[start], dist[end-1]);
+	else
+	  fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", 1.0/m, -1.0*b/m, N, end-start, start, end, dist[start], dist[end-1]);
+	for (k = start; k < end; k++) {
+	  M = N1[good[seq[k]]];
+	  mark[good[seq[k]]] = TRUE;
+	  if (catalog[0].average[M].code == ID_BLEED) continue;
+	  /* we need to mark measurements from all images in common on the line */
+	  Nm = 0;
+	  for (jj = 0; jj < catalog[0].average[M].Nm; jj++) {
+	    Nmeas = catalog[0].average[M].offset + jj;
+	    thisimage = catalog[0].image[Nmeas];
+	    for (kk = 0; kk < Nlist; kk++) {
+	      if (thisimage == list[kk]) {
+		catalog[0].measure[Nmeas].average |= PART_OF_TRAIL;
+		Nm ++;
+	      }
+	    }
+	  }
+	  /* if there is only 1 measurement, mark object as bad */
+	  if (catalog[0].average[M].Nm == Nm) {
+	    catalog[0].average[M].code = ID_TRAIL;
+	  }
+	  catalog[0].average[M].code = ID_TRAIL;
+	}
+      }
+      free (list);
+      start = -1;
+      end = -1;
+    }
+  }
+}
+
+
+/* I is Average seq number for star 1, J for star 2 */
+int *make_common_list (I, J, Nlist, catalog)
+int I, J, *Nlist;
+Catalog catalog[];
+{
+
+  int i, j, N1, N2, nlist, NLIST;
+  int *list;
+
+  NLIST = 50;
+  ALLOCATE (list, int, NLIST);
+  nlist = 0;
+
+  for (i = 0; i < catalog[0].average[I].Nm; i++) {
+    N1 = catalog[0].average[I].offset + i;
+    if (catalog[0].image[N1] == -1)
+      continue; /* not a real measurement */
+    for (j = 0; j < catalog[0].average[J].Nm; j++) {
+      N2 = catalog[0].average[J].offset + j;
+      if (catalog[0].image[N2] == -1)
+	continue; /* not a real measurement */
+      if (catalog[0].image[N1] == catalog[0].image[N2]) {
+	list[nlist] = catalog[0].image[N1];
+	nlist ++;
+	if (nlist == NLIST - 1) {
+	  NLIST += 50;
+	  REALLOCATE (list, int, NLIST);
+	}
+      }
+    }
+  }
+  
+  REALLOCATE (list, int, MAX(nlist, 1));
+  *Nlist = nlist;
+  return (list);
+
+}
+
+
+
+/* J is Average seq number for star */
+int *check_common_list (inlist, J, Nlist, catalog)
+int *inlist, J, *Nlist;
+Catalog catalog[];
+{
+
+  int i, j, N2, Ninlist;
+  int *list, NLIST, nlist;
+
+  NLIST = 50;
+  ALLOCATE (list, int, NLIST);
+  nlist = 0;
+  Ninlist = *Nlist;
+
+  for (i = 0; i < Ninlist; i++) {
+    for (j = 0; j < catalog[0].average[J].Nm; j++) {
+      N2 = catalog[0].average[J].offset + j;
+      if (catalog[0].image[N2] == -1)
+	continue; /* not a real measurement */
+      if (inlist[i] == catalog[0].image[N2]) {
+	list[nlist] = inlist[i];
+	nlist ++;
+	if (nlist == NLIST - 1) {
+	  NLIST += 50;
+	  REALLOCATE (list, int, NLIST);
+	}
+      }
+    }
+  }
+  
+  /* if there are no common images, return the input list */
+  if (nlist != 0) {
+    free (inlist);
+    REALLOCATE (list, int, MAX(nlist, 1));
+    *Nlist = nlist;
+    return (list);
+  } else {
+    return (inlist);
+  }
+
+}
+
+
+/* measurements associated with image number -1 are not 
+   measurements we made, but are added, like USNO */
Index: /trunk/Ohana/src/markrock/src/old/markstar.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/markstar.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/markstar.c	(revision 2490)
@@ -0,0 +1,60 @@
+# include "markstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, Nstars, Nimage, Nregions, Nmissed;
+  Image *image, *find_images();
+  Catalog catalog;
+  CatStats catstats;
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  RESET = FALSE;
+  if ((i = get_argument (argc, argv, "-reset"))) {
+    RESET = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: markstar (catalog)\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile (); 
+
+  gcatalog (argv[1], &catalog);
+
+  gcatstats (&catalog, &catstats);
+
+  image = find_images (&catstats, &Nimage);
+
+  match_images (&catalog, image, Nimage);
+    
+  find_bright_stars (&catalog, &catstats); 
+
+  find_ghosts (&catalog, &catstats, argv[1], image, Nimage);  
+
+  find_trails (&catalog, &catstats);  
+
+  wcatalog (argv[1], &catalog);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+}
+
Index: /trunk/Ohana/src/markrock/src/old/match_images.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/match_images.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/match_images.c	(revision 2490)
@@ -0,0 +1,58 @@
+# include "markstar.h"
+
+match_images (catalog, image, Nimage)
+Catalog catalog[];
+Image   image[];
+int Nimage;
+{
+  
+  int j, k, found;
+  unsigned int *start, *stop;
+
+  /* this must be allocated so future free will not fail */
+  ALLOCATE (catalog[0].image, int, MAX (catalog[0].Nmeasure, 1));
+  if (catalog[0].Naverage == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars in catalog, skipping\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (start, unsigned int, Nimage);
+  ALLOCATE (stop,  unsigned int, Nimage);
+  for (j = 0; j < Nimage; j++) {
+    start[j] = image[j].tzero - MAX(0.05*image[j].trate*image[j].NY, 1);
+    stop[j]  = image[j].tzero + MAX(1.05*image[j].trate*image[j].NY, 1);
+  }
+
+  for (j = 0; j < catalog[0].Nmeasure; j++) {
+    found = FALSE;
+    if (catalog[0].measure[j].t == 0) {
+      catalog[0].image[j] = -1;
+      found = TRUE;
+    }
+    for (k = 0; (k < Nimage) && !found; k++) {
+      if ((catalog[0].measure[j].t >= start[k]) && 
+	  (catalog[0].measure[j].t <= stop[k])) {
+	catalog[0].image[j] = k;
+	found = TRUE;
+      }
+    }
+    if (!found) {
+      fprintf (stderr, "ERROR: can't find source image for this measurement: %d\n",
+	       catalog[0].measure[j].t);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+  free (start);
+  free (stop);
+}
+
+  /* this routine uses the time of each measurement to match the
+measurement with an image.  Since the measurement is only store to 1
+sec accuracy, which corresponds to roughly 30 rows at nominal speed,
+we can't tell exactly which image the star come from.  However, this
+doesn't matter, and in fact this helps a bit: a measurement from the
+top of one image is the same as from the bottom of the next.
+Therefore, we intentionally blur the edges of the images by 5%, which
+will help to tie together neighboring images... */
+
Index: /trunk/Ohana/src/markrock/src/old/photometry.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/photometry.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/photometry.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "markrock.h"
+
+double PhotRel (Measure *measure, PhotCodeData *photcodes, double ZP) {
+
+  int Np;
+  double Mrel, Klam;
+
+  Np = photcodes[0].hashcode[measure[0].source];
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Mrel = 0.001 * measure[0].M;
+    return (Mrel);
+  }
+
+  Klam = photcodes[0].code[Np].K;
+  
+  Mrel = 0.001*(measure[0].M + Klam*(measure[0].airmass - 1000) + photcodes[0].code[Np].C - measure[0].Mcal) - ZP;
+	  
+  return (Mrel);
+
+}
+
+double PhotInst (Measure *measure, PhotCodeData *photcodes, double ZP) {
+
+  int Np;
+  double M, Klam;
+
+  Np = photcodes[0].hashcode[measure[0].source];
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    M = 0.001 * measure[0].M;
+    return (M);
+  }
+
+  M = 0.001*(measure[0].M - measure[0].dt);
+	  
+  return (M);
+
+}
+
+double PhotAbs (Measure *measure, PhotCodeData *photcodes, double ZP) {
+
+  int Np;
+  double Mabs, Klam;
+
+  Np = photcodes[0].hashcode[measure[0].source];
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Mabs = 0.001 * measure[0].M;
+    return (Mabs);
+  }
+
+  Klam = photcodes[0].code[Np].K;
+  
+  /* Mabs = 0.001*(measure[0].M + Klam*(measure[0].airmass - 1000) + photcodes[0].code[Np].C) - ZP; */
+
+  Mabs = 0.001*(measure[0].M + Klam*(measure[0].airmass - 1000) + photcodes[0].code[Np].C) - ZP;
+  
+  return (Mabs);
+	  
+}
Index: /trunk/Ohana/src/markrock/src/old/sort_lists.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/sort_lists.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/sort_lists.c	(revision 2490)
@@ -0,0 +1,48 @@
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
Index: /trunk/Ohana/src/markrock/src/old/sort_stars.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/sort_stars.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/sort_stars.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "relphot.h"
+
+void sort_stars (radec, stars, Nstars)
+int  **radec;
+Star  *stars;
+int    Nstars;
+{
+  
+  int i;
+  double *RAs;
+
+  ALLOCATE (radec[0], int, Nstars);
+  ALLOCATE (RAs, double, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    radec[0][i] = i;
+    RAs[i] = stars[i].RA;
+  }
+
+  sort_seq (radec[0], RAs, Nstars);
+  free (RAs);
+
+}
+
+
+void sort_seq (seq, value, N) 
+int *seq;
+double *value;
+int N;
+{
+  int l,j,ir,i;
+  int temp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = seq[--l];
+    }
+    else {
+      temp = seq[ir];
+      seq[ir] = seq[0];
+      if (--ir == 0) {
+	seq[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[seq[j]] < value[seq[j+1]]) ++j;
+      if (value[temp] < value[seq[j]]) {
+	seq[i]=seq[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
+
+
Index: /trunk/Ohana/src/markrock/src/old/string.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/string.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/string.c	(revision 2490)
@@ -0,0 +1,64 @@
+# include <stdio.h>
+# include <math.h>
+# define TRUE  1
+# define FALSE 0
+
+int scan_line (f, line) 
+FILE *f;
+char line[];
+{
+
+  int i, status;
+  char c;
+  
+  status = EOF + 1;
+  
+  for (i = 0, c = 0; (c != '\n') && (status != EOF); i++) {
+    status = fscanf (f, "%c", &c);
+    line[i] = c;
+  }
+  line[i - 1] = 0;  /* this could make things crash! */
+
+  if (i > 1) {
+    status = EOF + 1;
+  }
+
+  return (status);
+
+}
+
+char *_parse_nextword(string)
+char *string;
+{
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (; isspace (*string); string++);
+  for (; (*string != 0) && !isspace (*string); string++);
+  for (; isspace (*string); string++);
+  return (string);
+}
+
+int dparse (X, NX, line)
+double *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
Index: /trunk/Ohana/src/markrock/src/old/wimage.c
===================================================================
--- /trunk/Ohana/src/markrock/src/old/wimage.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/old/wimage.c	(revision 2490)
@@ -0,0 +1,67 @@
+# include "addstar.h"
+
+wimage (filename, image, Nstars)
+char *filename;
+Image image[];
+int Nstars;
+{
+  
+  int Nimages, status;
+  FILE *f;
+  Header header;
+
+  if (!fits_read_header (ImageCat, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't find %s, creating a new one\n", ImageCat);
+    if (!fits_read_header (ImageTemplate, &header)) {
+      fprintf (stderr, "ERROR: can't find template header %s\n", ImageTemplate);
+      clear_lockfile ();
+      exit (0);
+    }
+    f = fopen (ImageCat, "w");
+    if (f == NULL) {
+      fprintf (stderr, "ERROR: can't create/open image catalog file: %s\n", ImageCat);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+  
+  Nimages = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimages);
+  Nimages ++;
+  fits_modify (&header, "NIMAGES", "%d", 1, Nimages);
+
+  f = fopen (ImageCat, "r+");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't create/open image catalog file: %s\n", ImageCat);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  /* position to begining of file to write header */
+  fseek (f, 0, SEEK_SET);
+  status = Fwrite (header.buffer, 1, header.size, f, "char");
+  if (status != header.size) {
+    fprintf (stderr, "ERRPR: failed writing data to image header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  fseek (f, 0, SEEK_END);
+  fprintf (stderr, "Image: %d\n", sizeof(Image));
+  status = Fwrite (image, sizeof(Image), 1, f, "image");
+  if (status != 1) {
+    fprintf (stderr, "ERRPR: failed writing data to image catalog\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  fclose (f);
+  
+
+}
+
+/* the image we add in this routine is always a new image.  
+   We only need to do two things:
+     1) append the data for the image to the end of the file
+     2) update the NIMAGES field in the header (which means, read in header, re-write)
+ */
Index: /trunk/Ohana/src/markrock/src/sorts.c
===================================================================
--- /trunk/Ohana/src/markrock/src/sorts.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/sorts.c	(revision 2490)
@@ -0,0 +1,231 @@
+
+sort_set (X, Y, T, S, N) 
+float *X, *Y;
+int *S, N;
+int *T;
+{
+  int l,j,ir,i;
+  unsigned int tT;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tT = T[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tT = T[ir];
+      T[ir] = T[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	T[0] = tT;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	T[i] = T[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    T[i] = tT;
+    S[i] = tS;
+  }
+}
+
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+sort_entries (X, Y, N) 
+     double *X, *Y;
+     int N;
+{
+  int l,j,ir,i;
+  double tX, tY;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+  }
+}
+
+
+
+sort (X, N) 
+     double *X;
+     int N;
+{
+  int l,j,ir,i;
+  double tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+  }
+}
+
+
+sort_seq (X, S, N) 
+     double *X;
+     int *S;
+     int N;
+{
+  int l,j,ir,i;
+  int tS;
+  double tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    S[i] = tS;
+  }
+}
+
Index: /trunk/Ohana/src/markrock/src/wcatalog.c
===================================================================
--- /trunk/Ohana/src/markrock/src/wcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/wcatalog.c	(revision 2490)
@@ -0,0 +1,41 @@
+# include "markrock.h"
+
+wcatalog (Catalog *catalog) {
+  
+  int status;
+  char filename[256];
+
+  fits_modify (&catalog[0].header, "MARKROCK", "%t", 1, TRUE);
+
+  save_catalog (catalog, VERBOSE);
+
+  if (catalog[0].Naverage) {
+    free (catalog[0].average); 
+    catalog[0].Naverage = 0;
+  }
+  if (catalog[0].Nmeasure) {
+    free (catalog[0].measure); 
+    catalog[0].Nmeasure = 0;
+  }
+  if (catalog[0].Nmissing) {
+    free (catalog[0].missing); 
+    catalog[0].Nmissing = 0;
+  }
+  if (catalog[0].Nsecfilt) {
+    free (catalog[0].secfilt); 
+    catalog[0].Nsecfilt = 0;
+  }
+
+  switch (status) {
+  case 0:
+    fprintf (stderr, "error saving catalog\n");
+    exit (0);
+  case 1:
+  case 2:
+    return (status);
+  default:
+    fprintf (stderr, "unknown exit status for save_catalog\n");
+    return (FALSE);
+  }
+}
+
Index: /trunk/Ohana/src/markrock/src/wrocks.c
===================================================================
--- /trunk/Ohana/src/markrock/src/wrocks.c	(revision 2490)
+++ /trunk/Ohana/src/markrock/src/wrocks.c	(revision 2490)
@@ -0,0 +1,71 @@
+# include "markrock.h"
+
+wrocks (Rocks *rocks, int Nrocks) {
+  
+  int i, j;
+  FILE *f;
+  double X, Y, t, dSx, dSy, dS, speed;
+  double Sx, Sy, Sxt, Syt, St, St2, Sn;
+  double Mx, Bx, My, By, D;
+  unsigned int Tref;
+
+  f = fopen (RockCat, "a+");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't create/open rock catalog file: %s\n", RockCat);
+    exit (0);
+  }
+  /* position to begining of file to write header */
+  fseek (f, 0, SEEK_END);
+
+  /* get statistics on rocks */
+
+  for (i = 0; i< Nrocks; i++) {
+    /* fit a line to the three points, the ask for the scatter about the solution */
+    Tref = rocks[i].t[0];
+    Sx = Sy = Sxt = Syt = St = St2 = Sn = 0;
+    for (j = 0; j < 3; j++) {
+      X = rocks[i].X[j];
+      Y = rocks[i].Y[j];
+      if (rocks[i].t[j] > Tref) 
+	t = rocks[i].t[j] - Tref;
+      else
+	t = -1*((double)(Tref - rocks[i].t[j]));
+      Sx  += X;
+      Sy  += Y;
+      Sxt += X*t;
+      Syt += Y*t;
+      St  += t;
+      St2 += t*t;
+      Sn  += 1;
+    }
+    D = St2*Sn - St*St;
+    My = (Syt*Sn - Sy*St) / D;
+    By = (Sy*St2 - Syt*St) / D;
+    Mx = (Sxt*Sn - Sx*St) / D;
+    Bx = (Sx*St2 - Sxt*St) / D;
+    
+    dS = 0;
+    for (j = 0; j < 3; j++) {
+      X = rocks[i].X[j];
+      Y = rocks[i].Y[j];
+      if (rocks[i].t[j] > Tref) 
+	t = rocks[i].t[j] - Tref;
+      else 
+	t = -1*((double)(Tref - rocks[i].t[j]));
+      dSx = (Mx*t + Bx - X);
+      dSy = (My*t + By - Y);
+      dS += dSx*dSx + dSy*dSy;
+    }
+    dS = sqrt (dS/3);
+    speed = hypot (Mx, My);
+    fprintf (f, "%5.2f %9.4e ", dS, speed);
+    for (j = 0; j < 3; j++) {
+      fprintf (f, "%10d %10.6f %10.6f %6.3f ", rocks[i].t[j], rocks[i].ra[j], rocks[i].dec[j], rocks[i].mag[j]);
+    }
+    /* fprintf (f, "%3d %3d %3d\n", rocks[i].N[0], rocks[i].N[1], rocks[i].N[2]); */
+    fprintf (f, "\n");
+  }
+  fclose (f);
+  
+
+}
Index: /trunk/Ohana/src/markstar/Makefile
===================================================================
--- /trunk/Ohana/src/markstar/Makefile	(revision 2490)
+++ /trunk/Ohana/src/markstar/Makefile	(revision 2490)
@@ -0,0 +1,66 @@
+include ../../Configure
+HOME 	=	$(ROOT)/src/markstar
+CONFIG  =	$(ROOT)/config
+PROGRAM =       markstar
+
+BIN	=	$(HOME)/bin
+INC	= 	$(HOME)/include
+SRC	=	$(HOME)/src
+MAN	=	$(HOME)/doc
+DESTBIN	=	$(LBIN)
+DESTLIB	=	$(LLIB)
+DESTINC	=	$(LINC)
+DESTMAN	=	$(LMAN)
+
+#  
+INCS	= 	-I$(INC) -I$(LINC) -I$(XINC) -I$(LINC)/$(ARCH)
+LIBS	= 	-L$(LLIB) -lFITS -lohana -lm 
+CFLAGS	=	-o $*.$(ARCH).o $(INCS)
+CCFLAGS	=	$(INCS) $(LIBS) 
+
+MARKSTAR = \
+$(SRC)/markstar.$(ARCH).o 	$(SRC)/gcatalog.$(ARCH).o   \
+$(SRC)/coordops.$(ARCH).o	$(SRC)/sorts.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o 	\
+$(SRC)/check_lockfile.$(ARCH).o \
+$(SRC)/find_trails.$(ARCH).o	$(SRC)/find_group.$(ARCH).o \
+$(SRC)/find_line.$(ARCH).o	$(SRC)/mark_trail.$(ARCH).o \
+$(SRC)/load_gsc_data.$(ARCH).o	$(SRC)/find_bright_stars.$(ARCH).o \
+$(SRC)/wcatalog.$(ARCH).o	$(SRC)/find_images.$(ARCH).o	\
+$(SRC)/load_gsc_data_ghost.$(ARCH).o	$(SRC)/find_ghosts.$(ARCH).o \
+$(SRC)/gcatstats.$(ARCH).o	$(SRC)/match_images.$(ARCH).o	\
+$(SRC)/gregions.$(ARCH).o	$(SRC)/aregion.$(ARCH).o	\
+$(SRC)/find_matches.$(ARCH).o	$(SRC)/check_permissions.$(ARCH).o
+
+
+OBJ = $(MARKSTAR)
+
+default: $(PROGRAM)
+
+$(MARKSTAR): $(INC)/markstar.h
+
+# dependancy rules for binary code ##########################
+$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+
+$(BIN)/$(PROGRAM).$(ARCH): $(OBJ)
+	$(CC) $(OBJ) -o $(BIN)/$(PROGRAM).$(ARCH) $(CCFLAGS)
+
+install: $(DESTBIN)/$(PROGRAM)
+
+$(DESTBIN)/$(PROGRAM): $(BIN)/$(PROGRAM).$(ARCH)
+	rm -f $(DESTBIN)/$(PROGRAM)
+	cp $(BIN)/$(PROGRAM).$(ARCH) $(DESTBIN)/$(PROGRAM)
+
+# utilities #################################################
+clean:	
+	rm -f $(BIN)/*.$(ARCH)
+	rm -f `find . -name "*.o"`
+	rm -f `find . -name "*~"`
+	rm -f `find . -name "#*"`
+
+.SUFFIXES: .$(ARCH).o
+
+.c.$(ARCH).o:
+	$(CC) $(CFLAGS) -c $<
+
+
Index: /trunk/Ohana/src/markstar/doc/example.txt
===================================================================
--- /trunk/Ohana/src/markstar/doc/example.txt	(revision 2490)
+++ /trunk/Ohana/src/markstar/doc/example.txt	(revision 2490)
@@ -0,0 +1,13 @@
+
+rats: foreach f ( */*.cpt )
+foreach? echo $f
+foreach? echo $f >> bright.log
+foreach? (markstar -v $f >> bright.dat) >>& bright.log
+foreach? end
+
+
+
+ echo $f
+ echo $f >> bright.log
+ (markstar -v $f >> bright.dat) >>& bright.log
+ end
Index: /trunk/Ohana/src/markstar/doc/process.txt
===================================================================
--- /trunk/Ohana/src/markstar/doc/process.txt	(revision 2490)
+++ /trunk/Ohana/src/markstar/doc/process.txt	(revision 2490)
@@ -0,0 +1,69 @@
+
+hi chad,
+
+the process i use is a bit complex, but makes some reasonable
+comprimises about distance between points in a line and processing
+time.  
+
+First, the process I am about to describe is run on every "star" in
+the image.  However, the whole process gets speeded up in part because
+entries which are known stars can be ignored and entries which are
+already identified as part of a line associated with an earlier entry
+get ignored as well.  In fact, this step is done for a new part of the
+sky before the USNO stars are identified without much reduction in the
+processing speed, so the fact that you don't identify fixed stars in
+your data should not really be an issue.
+
+In the following, I use the term "star" to mean any detected object
+in the image frame.
+
+So, let me now discuss the process for a given test star, call it
+S(0).  
+
+The first step is to find likely directions with trails.  I first look
+at all other stars within a specific radius (say 100") around that
+star, call them S(i).  For each star S(i), I find the angle between
+S(i) and S(0).  I accumulate a histogram of these angles, a bin size
+of say a degree. (Note, both the Radius and the BinSize should be
+parameters that might change depending on the density of stars).  If
+any of the angle bins have a significant number of entries, then this
+is the likely direction of a trail.  There are three things to note
+about this process.  First, it makes processing the lists much quicker
+if you have the stars sorted by X or Y (or RA or DEC) and use that
+information in your search for the stars within 100".  Second, I
+define a significance cutoff for an angle bin based on the density of
+stars in the field (this is a useful parameter for all of the
+comparisons I discuss).  Once any of the angle bins surpasses the
+significance criterion, I stop searching around this test star and
+just work on the identified angle.  I assume that if the test star
+just happens to lie at the intersection of two lines, the other line
+will be identified by another test star.  Finally, the angle histogram
+only needs to run from 0 to 180, and angles in the range 180 to 360
+should be reflected back into the first half to increase the number
+statistics.  In general, your test star will be somewhere in the
+middle of a line.
+
+Once an angle of interest is found, I fit a line to all of the points
+in that angle bin, then narrow down improve the fit by refitting to
+all points within a fixed distance of the line.  You can itereate on
+the second step if the line is not well determined the first time
+around.  One point of interest:  for the line fits, if the angle of
+the line is 0 - 45 deg, I fit the line Y = mX + b, but if the angle is
+45 - 90 deg, I fit the line X = mY + b, to keep the slope near 1.  
+
+Once I have a good fit to a line, I try to decide if the line is
+really a trail or if it is just a coincidence of points.  I demand 
+both a minimum linear density of points in the line (related to the
+density of stars in the frame) and a minimum number of points in the
+line.  Another thing to watch out for is including points well beyond
+the end of the line which just happen to lie along the line.  I demand
+that the distance between points be less than some distance related to
+the linear density.  
+
+I hope this is a helpful description.  The routine I run is quite
+quick.  It takes about 10 seconds for a 1 degree region (about 10,000
+real stars) to do the line search, the bright star wings, and the
+search for ghosts on a 300 MHz Pentium II.  
+
+good luck
+gene
Index: /trunk/Ohana/src/markstar/include/markstar.h
===================================================================
--- /trunk/Ohana/src/markstar/include/markstar.h	(revision 2490)
+++ /trunk/Ohana/src/markstar/include/markstar.h	(revision 2490)
@@ -0,0 +1,43 @@
+# include <ohana.h>
+# include <loneos.h>
+
+int    VERBOSE;
+int    RESET;
+int    FORCE_RUN;
+
+/* global variables set in parameter file */
+char   CATDIR[256];
+char   GSCDIR[256];
+char   ImageCat[256];
+char   GSCFILE[256];
+
+double RADIUS;
+double TRAIL_WIDTH;
+int    NBINS;
+int    NPTSINLINE;
+double MIN_DENSITY;
+double NSIGMA;
+
+double BRIGHT_HALO_MAG;
+double BRIGHT_HALO_SLOPE;
+double BRIGHT_XTRAIL_WIDTH;
+double BRIGHT_XTRAIL_MAG;
+double BRIGHT_XTRAIL_SLOPE;
+double BRIGHT_YTRAIL_WIDTH;
+double BRIGHT_YTRAIL_MAG;
+double BRIGHT_YTRAIL_SLOPE;
+
+double GHOST_MAG;
+double GHOST_RADIUS;
+double OPTICAL_AXIS1;
+double OPTICAL_AXIS2;
+
+typedef struct {
+  Coords coords;
+  float *X, *Y;
+  int *N;
+  double RA[2], DEC[2];
+  double Area, density, spacing;
+} CatStats;
+
+PhotCodeData photcodes;
Index: /trunk/Ohana/src/markstar/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/markstar/src/ConfigInit.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/ConfigInit.c	(revision 2490)
@@ -0,0 +1,53 @@
+# include "markstar.h"
+
+ConfigInit (int *argc, char **argv) {
+
+  char *config, *file;
+  char PhotCodeFile[256];
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (0);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+  /* used in other pipeline functions */
+  ScanConfig (config, "IMAGE_CATALOG",   "%s",  0, ImageCat);
+  ScanConfig (config, "CATDIR",          "%s",  0, CATDIR);
+  ScanConfig (config, "GSCDIR",          "%s",  0, GSCDIR);
+  ScanConfig (config, "GSCFILE",         "%s",  0, GSCFILE);
+  /* unique to markstar */
+  ScanConfig (config, "SEARCH_RADIUS",   "%lf", 0, &RADIUS);
+  ScanConfig (config, "TRAIL_WIDTH",     "%lf", 0, &TRAIL_WIDTH);
+  ScanConfig (config, "NANGLE_BINS",     "%d",  0, &NBINS);
+  ScanConfig (config, "NPTSINLINE",      "%d",  0, &NPTSINLINE);
+  ScanConfig (config, "MIN_DENSITY",     "%lf", 0, &MIN_DENSITY);
+  ScanConfig (config, "SPACE_SIGMA",     "%lf", 0, &NSIGMA); 
+
+  ScanConfig (config, "BRIGHT_HALO_MAG",     "%lf", 0, &BRIGHT_HALO_MAG);
+  ScanConfig (config, "BRIGHT_HALO_SLOPE",   "%lf", 0, &BRIGHT_HALO_SLOPE);
+  ScanConfig (config, "BRIGHT_XTRAIL_WIDTH", "%lf", 0, &BRIGHT_XTRAIL_WIDTH);
+  ScanConfig (config, "BRIGHT_XTRAIL_MAG",   "%lf", 0, &BRIGHT_XTRAIL_MAG);
+  ScanConfig (config, "BRIGHT_XTRAIL_SLOPE", "%lf", 0, &BRIGHT_XTRAIL_SLOPE);
+  ScanConfig (config, "BRIGHT_YTRAIL_WIDTH", "%lf", 0, &BRIGHT_YTRAIL_WIDTH);
+  ScanConfig (config, "BRIGHT_YTRAIL_MAG",   "%lf", 0, &BRIGHT_YTRAIL_MAG);
+  ScanConfig (config, "BRIGHT_YTRAIL_SLOPE", "%lf", 0, &BRIGHT_YTRAIL_SLOPE);
+
+  ScanConfig (config, "GHOST_MAG",       "%lf", 0, &GHOST_MAG);
+  ScanConfig (config, "GHOST_RADIUS",    "%lf", 0, &GHOST_RADIUS);
+  ScanConfig (config, "OPTICAL_AXIS1",   "%lf", 0, &OPTICAL_AXIS1);
+  ScanConfig (config, "OPTICAL_AXIS2",   "%lf", 0, &OPTICAL_AXIS2);
+  ScanConfig (config, "PHOTCODE_FILE",          "%s", 0, PhotCodeFile);
+ 
+  if (!LoadPhotcodes (PhotCodeFile, &photcodes)) {
+    fprintf (stderr, "error loading photcodes\n");
+    exit (0);
+  }
+
+  free (config);
+  free (file);
+}
Index: /trunk/Ohana/src/markstar/src/aregion.c
===================================================================
--- /trunk/Ohana/src/markstar/src/aregion.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/aregion.c	(revision 2490)
@@ -0,0 +1,186 @@
+# include "markstar.h"
+
+double BigDecBounds[] = {0.0, 7.5, 15.0, 22.5, 30.0, 37.5, 45.0, 
+			 52.5, 60.0, 67.5, 75.0, 82.5, 90.0,
+			 0.0, -7.5, -15.0, -22.5, -30.0, -37.5, -45.0, 
+			 -52.5, -60.0, -67.5, -75.0, -82.5, -90.0};
+char *DecSections[] = {"N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", 
+		       "N5230", "N6000", "N6730", "N7500", "N8230", "weirdness", 
+		       "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", 
+		       "S5230", "S6000", "S6730", "S7500", "S8230", "weirdness"};
+
+char *Dec2Sections[] = {"n0000", "n0730", "n1500", "n2230", "n3000", "n3730", "n4500", 
+			"n5230", "n6000", "n6730", "n7500", "n8230", "weirdness", 
+			"s0000", "s0730", "s1500", "s2230", "s3000", "s3730", "s4500", 
+			"s5230", "s6000", "s6730", "s7500", "s8230", "weirdness"};
+
+char *disk[] = {"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "disk 1", 
+		"disk 1", "disk 1", "disk 1", "disk 1", "disk 1", "weirdness", 
+		"disk 1", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "disk 2", 
+		"disk 2", "disk 2", "disk 2", "disk 2", "disk 2", "weirdness"};
+
+int NBigRASections [] = {48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3, 48, 47, 45, 43, 40, 36, 32, 28, 21, 15, 9, 3, 3};
+
+int NDecLines[] = {593, 584, 551, 530, 522, 465, 406, 362, 280, 198, 123, 24, 
+                   0, 597, 578, 574, 577, 534, 499, 442, 376, 294, 212, 144, 48};
+
+/* find region file which contains ra, dec */
+aregion (region, f, ra, dec) 
+GSCRegion region[];
+FILE *f;
+double ra, dec;
+{
+  
+  
+  char buffer[28800], temp[50], file[50];
+  double dr, dd;
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done, nregion;
+  
+  while (ra < 0) { ra += 360.0; }
+  while (ra >= 360.0) { ra -= 360.0; }
+    
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt\0", GSCDIR);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] = -180.0;
+    region[0].RA[1] =  540.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+# ifdef DEBUG
+    fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+# ifdef DEBUG
+      fprintf (stderr, "%d %f %f %f\n", i, dec, BigDecBounds[i], BigDecBounds[i+1]);
+# endif
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+# ifdef DEBUG
+    fprintf (stderr, "%f %f %f  %f %f %f  %s\n", DEC0, dec, DEC1, RA0, ra, RA1, temp);
+# endif
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    exit (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt\0", GSCDIR, Dec2Sections[NBigDec],&temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
+
+
+/**********/
+int hms_to_deg (h0, h1, d0, d1, string) 
+     char *string;
+     double *h0, *h1, *d0, *d1;
+{
+  
+  int flag_d0, flag_d1, flag_h0, flag_h1;
+  double tmp;
+  
+  *d0 = *h0 = *d1 = *h1 = 0;
+
+  flag_h0 = dparse (h0, 1, string);
+  flag_h1 = dparse (h1, 4, string);
+  flag_d0 = dparse (d0, 7, string);
+  flag_d1 = dparse (d1, 9, string);
+  *h0 *= flag_h0;
+  *h1 *= flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  dparse (&tmp, 2, string);
+  *h0 += tmp/60.0;
+  dparse (&tmp, 3, string);
+  *h0 += tmp/3600.0;
+  
+  dparse (&tmp, 5, string);
+  *h1 += tmp/60.0;
+  dparse (&tmp, 6, string);
+  *h1 += tmp/3600.0;
+  
+  dparse (&tmp, 8, string);
+  *d0 += tmp/60.0;
+
+  dparse (&tmp, 10, string);
+  *d1 += tmp/60.0;
+
+  *h0 *= 15*flag_h0;
+  *h1 *= 15*flag_h1;
+  *d0 *= flag_d0;
+  *d1 *= flag_d1;
+
+  return (TRUE);
+}
+
+
+/*
+      if (buffer[i*48 + 19] == ' ') continue;
+      strncpy (temp, &buffer[i*48 + 19], 20);       temp[20] = 0;
+      hms_to_deg (&RA,  &DEC, temp, ' ', 3);
+
+
+  dBigRA = 360.0 / (int)(0.5 + 48*cos(3.1415927*0.5*(BigDecBounds[NBigDec] + BigDecBounds[NBigDec + 1])/180.0));
+
+  NBigRA = ra / dBigRA;
+
+  NBig = NBigRA;
+  for (i = 0; (i < 12) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+  for (i = 13; (i < 24) && (i < NBigDec); i++) {
+    NBig += NBigRASections[i];
+  }
+
+
+  fprintf (stderr, "%d %d %d %d %f %f -> %f %f %f\n", NBigDec, NBigRA, NBigRASections[NBigDec], NBig, ra, dec, BigDecBounds[NBigDec], BigDecBounds[NBigDec + 1], dBigRA);
+*/
Index: /trunk/Ohana/src/markstar/src/check_lockfile.c
===================================================================
--- /trunk/Ohana/src/markstar/src/check_lockfile.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/check_lockfile.c	(revision 2490)
@@ -0,0 +1,39 @@
+# include "markstar.h"
+
+check_lockfile ()
+{
+  
+  FILE *f;
+  char filename[128];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    fprintf (stderr, "ERROR: catalog %s is locked, try again later\n", CATDIR);
+    exit (0);
+  }
+
+  f = fopen (filename, "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't set lock file %s\n", filename);
+    exit (0);
+  }
+  fclose (f);
+
+}
+
+clear_lockfile ()
+{
+  
+  char filename[128], line[256];
+  struct stat filestat;
+
+  sprintf (filename, "%s/lock\0", CATDIR);
+  if (stat (filename, &filestat) != -1) {
+    sprintf (line, "rm %s\0", filename);
+    system (line);
+  } else {
+    fprintf (stderr, "can't remove lockfile, why not?\n");
+  }
+
+}
Index: /trunk/Ohana/src/markstar/src/check_permissions.c
===================================================================
--- /trunk/Ohana/src/markstar/src/check_permissions.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/check_permissions.c	(revision 2490)
@@ -0,0 +1,63 @@
+# include "markstar.h"
+
+check_permissions (char *basefile) {
+  
+  FILE *f;
+  char *c, dir[256], filename[256];
+  struct stat filestat;
+  uid_t fuid, uid;
+  gid_t fgid, gid;
+  int status;
+
+  uid = getuid();
+  gid = getgid();
+
+  /* check permission to write to directory */
+  sprintf (filename, "%s\0", basefile);
+  c = strrchr (filename, '/');
+  if (c == (char *) NULL) {
+    strcpy (dir, ".");
+  } else {
+    *c = 0;
+    strcpy (dir, filename);
+  }
+  status = stat (dir, &filestat);
+  if (status == -1) {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  } 
+  if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRWXU)) ||
+      ((gid == filestat.st_gid) && (filestat.st_mode & S_IRWXG)) || 
+      (filestat.st_mode & S_IRWXO)) {
+  } else {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (0);
+  }
+  
+  /* check permission to write to file */
+  sprintf (filename, "%s\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+  /* check permission to write to backup file */
+  sprintf (filename, "%s~\0", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (0);
+    }
+  }
+  
+}
Index: /trunk/Ohana/src/markstar/src/config.c
===================================================================
--- /trunk/Ohana/src/markstar/src/config.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/config.c	(revision 2490)
@@ -0,0 +1,110 @@
+# include <ohana.h>
+# define D_NBYTES 4096
+
+char *LoadConfigFile (filename) 
+char *filename; 
+{
+  
+  FILE *f;
+  int i, done, Nbytes, NBYTES, size;
+  char *config;
+  
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "couldn't find %s\n", filename);
+    return ((char *) NULL);
+  }
+ 
+  NBYTES = D_NBYTES;
+  ALLOCATE (config, char, NBYTES);
+ 
+  size = 0;
+  done = FALSE;
+  for (i = 0; !done; i++) {
+    Nbytes = Fread (&config[i*D_NBYTES], sizeof(char), D_NBYTES, f, "char");
+    size += Nbytes;
+    if (Nbytes < D_NBYTES) 
+      done = TRUE;
+    else {
+      NBYTES += D_NBYTES;
+      REALLOCATE (config, char, NBYTES);
+    }
+  }
+  
+  config[size] = '\n';
+  config[size+1] = 0;
+  REALLOCATE (config, char, size + 2);
+ 
+  fclose (f);
+
+  return (config);
+}
+
+int ScanConfig /* we expect one more field: the pointer to the value requested */
+# ifndef ANSI
+(config, field, mode, va_alist) 
+ char *config; char *field, *mode; va_dcl
+# else
+(char       config[],
+ char       field[],
+ char       mode[],...)
+# endif
+{
+ 
+  int i, j;
+  char *p, *p2, tmp[256];
+  va_list argp;
+  double value;
+  
+# ifndef ANSI
+  va_start (argp);
+# else
+  va_start (argp, N);
+# endif
+  
+  /* find the correct line with field */
+  p2 = config;
+  for (i = 0; ; i++) {
+    if (!strncmp (field, p2, strlen(field))) {
+      p = p2 + strlen (field);
+      break;
+    }
+    else {
+      p2 = strchr (p2, '\n');
+      if (p2 == (char *) NULL) {
+	fprintf (stderr, "entry %s not found in config file\n", field);
+	return (FALSE);
+      }
+      else p2++;
+    }
+  }
+  if (!strcmp (mode, "%s")) {
+    p2 = strchr (p, '\n');
+    if (p2 == (char *) NULL)
+      p2 = config + strlen(config);
+    bcopy (p, tmp, (p2-p));
+    tmp[(p2-p)] = 0;
+    stripwhite (tmp);
+    p2 = va_arg (argp, char *);
+    strcpy (p2, tmp);
+  }
+  else {
+ 
+    /* try to get a numerical value from the field */
+    value = strtod (p, &p2);
+    if ((*p2 == 'd') || (*p2 == 'D')) 
+      value *= pow (10.0, atof (p2 + 1));
+    
+    if (!strcmp (mode, "%d"))  *va_arg (argp, int *)       = value;
+    if (!strcmp (mode, "%u"))  *va_arg (argp, unsigned *)  = value;
+    if (!strcmp (mode, "%ld")) *va_arg (argp, long *)      = value;
+    if (!strcmp (mode, "%hd")) *va_arg (argp, short *)     = value;
+    if (!strcmp (mode, "%f"))  *va_arg (argp, float *)     = value;
+    if (!strcmp (mode, "%lf")) *va_arg (argp, double *)    = value;
+    
+  }
+ 
+  va_end (argp);
+  return (TRUE);
+  
+}
Index: /trunk/Ohana/src/markstar/src/coordops.c
===================================================================
--- /trunk/Ohana/src/markstar/src/coordops.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/coordops.c	(revision 2490)
@@ -0,0 +1,331 @@
+# include "markstar.h"
+
+XY_to_RD (ra, dec, x, y, coords)
+double *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  double L, M, X, Y, T, Z;
+  double R, sphi, cphi, stht, ctht;
+  double alpha, delta, salp, calp, sdel, sdp, cdp;
+  
+  *ra  = 0;
+  *dec = 0;
+
+  /** convert pixel coordinates to cartesian system **/
+  stht = ctht = 1;
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    X = coords[0].cdelt1*(x - coords[0].crpix1 + x*x*coords[0].polyterms[0][0] + x*y*coords[0].polyterms[1][0] + y*y*coords[0].polyterms[2][0]
+			  + x*x*x*coords[0].polyterms[3][0] + x*x*y*coords[0].polyterms[4][0] + x*y*y*coords[0].polyterms[5][0] + y*y*y*coords[0].polyterms[6][0]);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2 + x*x*coords[0].polyterms[0][1] + x*y*coords[0].polyterms[1][1] + y*y*coords[0].polyterms[2][1]
+			  + x*x*x*coords[0].polyterms[3][1] + x*x*y*coords[0].polyterms[4][1] + x*y*y*coords[0].polyterms[5][1] + y*y*y*coords[0].polyterms[6][1]);
+  } else {
+    X = coords[0].cdelt1*(x - coords[0].crpix1);
+    Y = coords[0].cdelt2*(y - coords[0].crpix2);
+  }    
+
+  L = (X*coords[0].pc1_1 + Y*coords[0].pc1_2);
+  M = (X*coords[0].pc2_1 + Y*coords[0].pc2_2);
+  /* in FITS ref, L,M = x, y  alpha, delta = phi, theta */
+
+  /**** Zenithal Projections ****/
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || 
+      !strcmp(&coords[0].ctype[4], "-TAN") || 
+      !strcmp(&coords[0].ctype[4], "-SIN") || 
+      !strcmp(&coords[0].ctype[4], "-ZEA") || 
+      !strcmp(&coords[0].ctype[0], "MM")) {
+    R = hypot (L,M);
+    if ((L == 0) && (M == 0)) {
+      sphi = 0;
+      cphi = 1;
+    }
+    else {
+      sphi =  L / R;
+      cphi = -M / R;
+    }
+
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || 
+	!strcmp(&coords[0].ctype[4], "-TAN")) {
+      if (R == 0) {
+	stht = 1.0;
+	ctht = 0.0;
+      }
+      else {
+	T = DEG_RAD / R;
+	stht =   T / sqrt ( 1.0 + T*T);
+	ctht = 1.0 / sqrt ( 1.0 + T*T);
+      }
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || 
+	!strcmp(&coords[0].ctype[0], "MM")) {
+      ctht = RAD_DEG * R;
+      stht = sqrt (1 - ctht*ctht);
+    }
+    if (!strcmp(&coords[0].ctype[4], "-ZEA")) {
+      stht = 1 - 0.5*SQ(R*RAD_DEG);
+      ctht = sqrt (1 - stht*stht);
+    }
+
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    
+    sdel = stht*sdp - ctht*cphi*cdp;
+    salp = ctht*sphi;
+    calp = stht*cdp + ctht*cphi*sdp;
+    alpha = atan2 (salp, calp);
+    delta = asin (sdel);
+    
+    *ra  = DEG_RAD*alpha + coords[0].crval1;
+    *dec = DEG_RAD*delta;
+  }
+
+  /**** Locally Cartesian Projections ****/
+  if (!strcmp(&coords[0].ctype[4], "-LIN") || !strcmp(&coords[0].ctype[0], "GENE")) {
+    *ra  = L + coords[0].crval1;
+    *dec = M + coords[0].crval2;
+  }
+
+  /**** Other Conventional Projections ****/
+  if (!strcmp(&coords[0].ctype[4], "-AIT")) {
+    Z = sqrt (1.0 - SQ(RAD_DEG*0.25*L) - SQ(RAD_DEG*0.5*M));
+    alpha = 2.0 * DEG_RAD * atan2 (RAD_DEG*0.5*Z*L, 2.0*SQ(Z) - 1.0);
+    delta = DEG_RAD * asin (RAD_DEG*M*Z);
+    *ra  = alpha + coords[0].crval1;
+    *dec = delta + coords[0].crval2;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-GLS")) {
+    /* L,M in degrees, alpha,delta in degrees */
+    alpha = L / cos (RAD_DEG * M);
+    delta = M;
+    *ra  = alpha + coords[0].crval1;
+    *dec = delta + coords[0].crval2;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-PAR")) {
+    /* L,M in degrees, alpha,delta in degrees */
+    alpha = L / (1.0 - SQ(2.0*M/180));
+    delta = 3 * DEG_RAD * asin (M/180.0);
+    *ra  = alpha + coords[0].crval1;
+    *dec = delta + coords[0].crval2;
+  }
+}
+
+
+
+RD_to_XY (x, y, ra, dec, coords)
+double *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  double phi, theta;
+  double tmp_d;
+  double X, Y, sphi, cphi, stht;
+  double salp, calp, sdel, cdel, sdp, cdp;
+  double P, CP, A, Rc;
+  int status;
+
+  X = Y = 1;
+  status = TRUE;
+  if (!strcmp(&coords[0].ctype[4], "-PLY")) {
+    /* fprintf (stderr, "approximate to polynomial TAN plane fit\n"); */
+  }
+
+  *x = 0;
+  *y = 0;
+
+  /**** Locally Cartesian Projections ****/
+  if (!strcmp(&coords[0].ctype[0], "GENE") || !strcmp(&coords[0].ctype[4], "-LIN")) {
+    X = (ra  - coords[0].crval1);
+    Y = (dec - coords[0].crval2);
+  }
+  
+  /**** Zenithal Projections ****/
+  if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") || !strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+    sdp  = sin(RAD_DEG*coords[0].crval2);
+    cdp  = cos(RAD_DEG*coords[0].crval2);
+    salp = sin(RAD_DEG*(ra - coords[0].crval1));
+    calp = cos(RAD_DEG*(ra - coords[0].crval1));
+    sdel = sin(RAD_DEG*dec);
+    cdel = cos(RAD_DEG*dec);
+
+    stht = sdel*sdp + cdel*cdp*calp;  /* sin(theta) */
+    sphi = cdel*salp;  /* = cos(theta)*sin(phi) */
+    cphi = cdel*sdp*calp - sdel*cdp; /* = cos(theta)*cos(phi) */
+    if (stht < 0) status = FALSE;
+    
+    if (!strcmp(&coords[0].ctype[4], "-PLY") || !strcmp(&coords[0].ctype[4], "-TAN") ) {
+      X =  DEG_RAD * sphi / stht;
+      Y = -DEG_RAD * cphi / stht;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-SIN") || !strcmp(&coords[0].ctype[0], "MM")) {
+      X =  DEG_RAD * sphi;
+      Y = -DEG_RAD * cphi;
+    }
+    if (!strcmp(&coords[0].ctype[4], "-ZEA")) {
+      Rc = DEG_RAD * M_SQRT2 / sqrt (1 + stht);
+      X =  Rc * sphi;
+      Y = -Rc * cphi;
+    }
+  }
+
+  /**** Other Standard Projections ****/
+  if (!strcmp(&coords[0].ctype[4], "-AIT")) {
+    phi = RAD_DEG*(ra - coords[0].crval1);
+    theta = RAD_DEG*(dec - coords[0].crval2);
+    P = 1.0 + cos (theta) * cos (0.5*phi);
+    if (P != 0.0) {
+      A =  DEG_RAD * sqrt (2.0 / P);
+      X =  2.0 * A * cos (theta) * sin (0.5*phi);
+      Y =  A * sin (theta);
+    } else { 
+      X =  0.0;
+      Y =  0.0;
+    }	
+  }
+  if (!strcmp(&coords[0].ctype[4], "-GLS")) {
+    phi = ra - coords[0].crval1;
+    theta = dec - coords[0].crval2;
+    X = phi * cos(RAD_DEG * theta);
+    Y = theta;
+  }
+  if (!strcmp(&coords[0].ctype[4], "-PAR")) {
+    phi = ra - coords[0].crval1;
+    theta = dec - coords[0].crval2;
+    X = phi * (2.0*cos(2*RAD_DEG*theta/3.0) - 1);
+    Y = 180.0 * sin (RAD_DEG*theta/3.0);
+  }
+   
+  tmp_d = 1.0 / (coords[0].pc1_1*coords[0].pc2_2 - coords[0].pc1_2*coords[0].pc2_1);
+  *x = tmp_d * (coords[0].pc2_2*X - coords[0].pc1_2*Y) / coords[0].cdelt1 + coords[0].crpix1;
+  *y = tmp_d * (coords[0].pc1_1*Y - coords[0].pc2_1*X) / coords[0].cdelt2 + coords[0].crpix2;
+
+  return (status);
+ 
+}
+
+
+fRD_to_XY (x, y, ra, dec, coords)
+float *x, *y;
+double  ra, dec;
+Coords coords[];
+{
+
+  int status;
+  double tmpx, tmpy;
+
+  status = RD_to_XY (&tmpx, &tmpy, ra, dec, coords);
+  *x = tmpx;
+  *y = tmpy;
+  
+  return (status);
+
+}
+
+fXY_to_RD (ra, dec, x, y, coords)
+float *ra, *dec;
+double  x, y;
+Coords coords[];
+{
+
+  int status;
+  double tmpr, tmpd;
+
+  status = XY_to_RD (&tmpr, &tmpd, x, y, coords);
+  *ra = tmpr;
+  *dec = tmpd;
+  
+  return (status);
+
+}
+
+GetCoords (coords, header) 
+Coords coords[];
+Header header[];
+{
+
+  int status;
+  double rotate;
+
+  rotate = 0.0;
+  coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+  coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+  coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+  coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+  strcpy (coords[0].ctype, "NONE");
+
+  status = TRUE; 
+  if (fits_scan (header, "CTYPE2", "%s", 1, coords[0].ctype)) {
+    status  = fits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+    status &= fits_scan (header, "CRPIX1", "%lf", 1, &coords[0].crpix1);
+    status &= fits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+    status &= fits_scan (header, "CRPIX2", "%lf", 1, &coords[0].crpix2);
+    if (fits_scan (header, "CDELT1", "%lf", 1, &coords[0].cdelt1)) {
+      status &= fits_scan (header, "CDELT2", "%lf", 1, &coords[0].cdelt2);
+      if (fits_scan (header, "CROTA2", "%lf", 1, &rotate)) {
+	coords[0].pc1_1 =  cos(rotate*RAD_DEG);
+	coords[0].pc1_2 = -sin(rotate*RAD_DEG);
+	coords[0].pc2_1 =  sin(rotate*RAD_DEG);
+	coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+      }
+      if (fits_scan (header, "PC001001", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "PC001002", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "PC002001", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "PC002002", "%lf", 1, &coords[0].pc2_2);
+      }
+    }
+    else {
+      if (fits_scan (header, "CD1_1", "%lf", 1, &coords[0].pc1_1)) {
+	status &= fits_scan (header, "CD1_2", "%lf", 1, &coords[0].pc1_2);
+	status &= fits_scan (header, "CD2_1", "%lf", 1, &coords[0].pc2_1);
+	status &= fits_scan (header, "CD2_2", "%lf", 1, &coords[0].pc2_2);
+	coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      }
+      else {
+	status = FALSE;
+      }
+    }
+  }
+  else {
+    if (fits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1)) {
+      status  = fits_scan (header, "RA_X", "%lf", 1, &coords[0].pc1_1);
+      status &= fits_scan (header, "RA_Y", "%lf", 1, &coords[0].pc1_2);
+      status &= fits_scan (header, "DEC_O", "%lf", 1, &coords[0].crval2);  
+      status &= fits_scan (header, "DEC_X", "%lf", 1, &coords[0].pc2_1);
+      status &= fits_scan (header, "DEC_Y", "%lf", 1, &coords[0].pc2_2);
+      coords[0].crpix1 = coords[0].crpix2 = 0.0;
+      coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
+      strcpy (coords[0].ctype, "GENE");
+    }
+  }
+  if (!status) {
+    fprintf (stderr, "error getting all elements for coordinate mode %d\n", coords[0].ctype);
+    coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
+    coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
+    coords[0].pc1_1 = coords[0].pc2_2 = 1.0;
+    coords[0].pc2_1 = coords[0].pc1_2 = 0.0;
+    strcpy (coords[0].ctype, "NONE");
+  }
+}
+
+
+  /* -PLY projection is an extrapolation of the -TAN projection. 
+     In addition to the usual linear terms of CRPIXi, PC00i00j, there are 
+     higher order polynomial terms (up to 3rd order):
+     Axis 1 terms:
+     PCA1X2Y0 = coords.polyterm[0][0] = x^2                                             
+     PCA1X1Y1 = coords.polyterm[1][0] = xy                                          
+     PCA1X0Y2 = coords.polyterm[2][0] = y^2                                             
+     PCA1X3Y0 = coords.polyterm[3][0] = x^3                                             
+     PCA1X2Y1 = coords.polyterm[4][0] = x^2 y                                             
+     PCA1X1Y2 = coords.polyterm[5][0] = x y^2                                             
+     PCA1X0Y3 = coords.polyterm[6][0] = y^2                                              
+     Axis 2 terms:
+     PCA2X2Y0 = coords.polyterm[0][1] = x^2                                               
+     PCA2X1Y1 = coords.polyterm[1][1] = xy                                                
+     PCA2X0Y2 = coords.polyterm[2][1] = y^2                                               
+     PCA2X3Y0 = coords.polyterm[3][1] = x^3                                               
+     PCA2X2Y1 = coords.polyterm[4][1] = x^2 y                                             
+     PCA2X1Y2 = coords.polyterm[5][1] = x y^2                                             
+     PCA2X0Y3 = coords.polyterm[6][1] = y^2                                               
+  */
Index: /trunk/Ohana/src/markstar/src/find_bright_stars.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_bright_stars.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_bright_stars.c	(revision 2490)
@@ -0,0 +1,142 @@
+# include "markstar.h"
+
+find_bright_stars (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, n, m, first_j, Nave, Ngsc;
+  Catalog GSCdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2;
+  char *mark;
+  double dX, dY, dR, MaxDist, MaxDist1, MaxRadius, radius, radius2;
+
+  load_gsc_data (&GSCdata, catstats);
+
+  Nave = catalog[0].Naverage;
+  Ngsc = GSCdata.Naverage;
+    
+  /* in the function below, it is better to have the catalog with
+     more stars associated with index 2 (j) */ 
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+  ALLOCATE (X1, float, Ngsc);
+  ALLOCATE (Y1, float, Ngsc);
+  ALLOCATE (N1, int, Ngsc);
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Ngsc; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], GSCdata.average[i].R, GSCdata.average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Ngsc > 1) sort_lists (X1, Y1, N1, Ngsc);
+  
+  /* first find stellar halos */
+  /* max radius (mag = -1) */
+  /** the j index moves quickly and is better associated with the catalog with more stars */
+  MaxRadius = BRIGHT_HALO_SLOPE * (-1.0 - BRIGHT_HALO_MAG); 
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*MaxRadius) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*MaxRadius) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    radius = MAX (BRIGHT_HALO_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_HALO_MAG), 0.0);
+    if (radius == 0) {
+      i++; 
+      continue;
+    }
+    radius2 = radius*radius;
+    for (; (dX > -2*radius) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < radius2) {  /* new measurement of this star */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find y spikes */
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -BRIGHT_YTRAIL_WIDTH) {
+      i++;
+      continue;
+    }
+    if (dX >= BRIGHT_YTRAIL_WIDTH) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist = MAX (BRIGHT_YTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_YTRAIL_MAG), 0.0);
+    for (; (dX > -BRIGHT_YTRAIL_WIDTH) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dX) < BRIGHT_YTRAIL_WIDTH) && (fabs(dY) < MaxDist)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* next find x spikes */
+  /** find catalog stars near GSC stars **/
+  MaxDist = MAX (BRIGHT_XTRAIL_SLOPE * (-1.0 - BRIGHT_XTRAIL_MAG), 0.0);
+  for (i = j = 0; (i < Ngsc) && (j < Nave); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -MaxDist) {
+      i++;
+      continue;
+    }
+    if (dX >= MaxDist) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    MaxDist1 = MAX (BRIGHT_XTRAIL_SLOPE * (0.001*GSCdata.average[N1[i]].M - BRIGHT_XTRAIL_MAG), 0.0);
+    for (; (dX > -MaxDist1) && (j < Nave); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      if ((fabs(dY) < BRIGHT_XTRAIL_WIDTH) && (fabs(dX) < MaxDist1)) {  /* star on spike */
+	mark[j] = TRUE;
+      }
+    }
+    j = first_j;
+    i++;
+  }
+
+  /* done with search, mark selected stars */
+  for (i = 0; i < Nave; i++) {
+    if (mark[i]) {
+      catalog[0].average[N2[i]].code = ID_BLEED;
+    }
+  } 
+  
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (mark);
+  free (GSCdata.average);
+
+}
+
Index: /trunk/Ohana/src/markstar/src/find_ghosts.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_ghosts.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_ghosts.c	(revision 2490)
@@ -0,0 +1,70 @@
+# include "markstar.h"
+
+find_ghosts (catalog, catstats, filename, image, Nimage)
+Catalog catalog[];
+CatStats catstats[];
+char *filename;
+Image image[];
+int Nimage;
+{
+
+  int i, j, first_j, Nave, Ngsc, Nregions;
+  Catalog GSCdata, Ghostdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2, *match;
+  char *mark;
+  double dX, dY, dR, RADIUS2, BRIGHT_RADIUS, radius, X, Y, R, D;
+  Image timage;
+  GSCRegion *region, *gregions2();
+
+  for (i = 0; i < Nimage; i++) {
+    
+    /* coords structure for ghost image */
+    timage = image[i];
+    timage.coords.cdelt1 = -1*image[i].coords.cdelt1;
+    timage.coords.cdelt2 = -1*image[i].coords.cdelt2;
+    timage.coords.crpix1 = 2*OPTICAL_AXIS1 - image[i].coords.crpix1;
+    timage.coords.crpix2 = 2*OPTICAL_AXIS2 - image[i].coords.crpix2;
+
+    region = gregions2 (&timage, &Nregions);
+    
+    /* find ghost stars */
+    load_gsc_data_ghost (&GSCdata, region, Nregions, &timage);
+
+    /* refect ghost stars to find locations of ghosts */
+    ALLOCATE (Ghostdata.average, Average, MAX (GSCdata.Naverage, 1));
+    for (j = 0; j < GSCdata.Naverage; j++) {
+      RD_to_XY (&X, &Y, GSCdata.average[j].R, GSCdata.average[j].D, &timage);
+      fXY_to_RD (&Ghostdata.average[j].R, &Ghostdata.average[j].D, X, Y, &image[i]);
+      Ghostdata.average[j].M = GSCdata.average[j].M;
+    }    
+    Ghostdata.Naverage = GSCdata.Naverage;
+
+    /* match ghosts and image stars, mark ghosts */
+    find_matches (catalog, catstats, &Ghostdata, i);
+
+    free (Ghostdata.average);
+    free (GSCdata.average);
+  }
+
+}
+
+/* 
+
+   just to be clear on some of the terms:
+
+   the "ghost" is the fuzzy patch of light on an image caused by
+     a reflected star
+
+   the "ghost star" is the star in the sky which causes a ghost
+
+   the "ghost image" is the image location on the sky 
+     where ghost stars may come from.
+
+   the "image stars" are observed stars at the location of the
+     ghost - these are detections of the ghost
+
+
+*/
Index: /trunk/Ohana/src/markstar/src/find_group.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_group.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_group.c	(revision 2490)
@@ -0,0 +1,65 @@
+# include "markstar.h"
+
+find_group (catstats, mark, Npts, i, ANGLE)
+     CatStats catstats[];
+     double *ANGLE;
+     int i, Npts;
+     char *mark;
+{
+ 
+  float *R, *D;
+  int j, N, bin, Ndegbin;
+  unsigned short int *A;
+  double Ra, De, dR, dD, angle, limit;
+
+   /* assign some parameter values */
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+  Ndegbin = NBINS / 180.0;
+  ALLOCATE (A, unsigned short int, NBINS + 1)
+  bzero (A, (NBINS+1)*sizeof(short));
+
+  /* look for points concentrated in an angle bin */
+  if (mark[i]) return (FALSE);
+  Ra = R[i];
+  De = D[i];
+  N = 0;
+  /* points east */
+  for (j = i + 1; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;  /* only NaN if dD = dR = 0 */
+      if (angle < 0) angle += M_PI;
+      bin = angle*DEG_RAD*Ndegbin;
+      A[bin] ++;
+      N ++;
+    }
+  }
+  /* points west */
+  for (j = i - 1; (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      bin = angle*DEG_RAD*Ndegbin;
+      A[bin] ++;	
+      N ++;
+    }
+  }
+  limit = NSIGMA*sqrt((double)(N)/(double)(NBINS));
+  for (j = 0; j < NBINS; j++) {
+    if (A[j] > limit) {
+      *ANGLE = j / (DEG_RAD*Ndegbin);
+      return (TRUE);
+    }
+  }
+  return (FALSE);
+}
+  
Index: /trunk/Ohana/src/markstar/src/find_images.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_images.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_images.c	(revision 2490)
@@ -0,0 +1,213 @@
+# include "markstar.h"
+double opening_angle ();
+
+Image *find_images (catstats, Nimages)
+CatStats catstats[];
+int *Nimages;
+{
+  
+  Header header;
+  Image *timage, *image;
+  int i, j, k, found, nimage, Nimage, NIMAGE, NTIMAGE, Nloop, Nlast;
+  int n, Nim, status, InRange;
+  FILE *f;
+  double Xc[6], Yc[6], Xi[6], Yi[6], r, d, x, y, dx, dy;
+  Coords *tcoords;
+
+  /* we make positional comparisons in the projection of catalog */
+  tcoords = &catstats[0].coords;
+  /* define catalog corners */
+  Xc[0] = catstats[0].RA[0]; Yc[0] = catstats[0].DEC[0];
+  Xc[1] = catstats[0].RA[1]; Yc[1] = catstats[0].DEC[0];
+  Xc[2] = catstats[0].RA[1]; Yc[2] = catstats[0].DEC[1];
+  Xc[3] = catstats[0].RA[0]; Yc[3] = catstats[0].DEC[1];
+  Xc[4] = catstats[0].RA[0]; Yc[4] = catstats[0].DEC[0];
+  for (j = 0; j < 5; j++) {
+    r = Xc[j]; d = Yc[j];
+    RD_to_XY (&Xc[j], &Yc[j], r, d, tcoords);
+  }
+
+  /* check if image datafile exists, get header, number of images */
+  if (!fits_read_header (ImageCat, &header)) {
+    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
+    exit (0);
+  }
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  if (Nimage == 0) {
+    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
+    exit (0);
+  }
+
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: trouble opening Image catalog: %s (2)\n", ImageCat);
+    exit (0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* set up buffers for images, temporary storage */
+  NTIMAGE = 100;
+  ALLOCATE (timage, Image, NTIMAGE);
+  NIMAGE = 100;
+  ALLOCATE (image, Image, NIMAGE);
+  nimage = 0;
+  Nloop = Nimage / NTIMAGE + 1;
+  Nlast = Nimage % NTIMAGE;
+  
+  /* read in images in groups of NTIMAGE (100) */
+  for (n = 0; n < Nloop; n++) {
+    Nim = (n == Nloop - 1) ? Nlast : NTIMAGE;
+    status = Fread (timage, sizeof(Image), Nim, f, "image");
+    if (status != Nim) {
+      fprintf (stderr, "ERROR: couldn't read images from image catalog: %s\n", ImageCat);
+      exit (0);
+    }
+    /* test each image in block */
+    for (i = 0; i < Nim; i++) {
+      /* define image corners */
+      Xi[0] = 0;            Yi[0] = 0;
+      Xi[1] = timage[i].NX; Yi[1] = 0;
+      Xi[2] = timage[i].NX; Yi[2] = timage[i].NY;
+      Xi[3] = 0;            Yi[3] = timage[i].NY;
+      Xi[4] = 0;            Yi[4] = 0;
+      found = FALSE;
+      /* transform to tcoords */
+      if (catstats[0].DEC[1] > 86.25) { /* pole */
+	for (j = 0; j < 5; j++) {
+	  XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	  if (d > catstats[0].DEC[0] - 0.5) found = TRUE;
+	}
+      } else {
+	for (j = 0; j < 6; j++) {
+	  XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	  InRange = RD_to_XY (&Xi[j], &Yi[j], r, d, tcoords);
+	  if (!InRange) {
+	    /* if RD_to_XY returns false, the coords are ~180 away from
+	       the projection center */ 
+	    goto imskip;
+	  }
+	}
+	/* check if image corner inside catalog */
+	for (j = 0; (j < 4) && !found; j++) {
+	  found |= corner_check (&Xi[j], &Yi[j], &Xc[0], &Yc[0]);
+	}
+	/* check if catalog corner inside image */
+	for (j = 0; (j < 4) && !found; j++) {
+	  found |= corner_check (&Xc[j], &Yc[j], &Xi[0], &Yi[0]);
+	}
+	/* check if edges cross */
+	for (j = 0; (j < 4) && !found; j++) {
+	  for (k = 0; (k < 4) && !found; k++) {
+	    found |= edge_check (&Xi[j], &Yi[j], &Xc[k], &Yc[k]);
+	  }
+	}
+      }
+      if (found) {
+	image[nimage] = timage[i]; 
+	image[nimage].code = 0;
+	nimage ++;
+	if (nimage == NIMAGE) {
+	  NIMAGE += 100;
+	  REALLOCATE (image, Image, NIMAGE);
+	}
+      }
+    imskip:
+    }
+  }
+      
+  if (VERBOSE) { 
+    for (i = 0; i < nimage; i++) {
+      XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+      fprintf (stderr, "associated images: %d %8.4f %8.4f %10d %6d  %5.3f %6.3f %6.3f\n", 
+	       i, r, d, image[i].tzero, image[i].nstar, 0.001*image[i].secz, 
+	       0.001*image[i].Mcal, 0.001*image[i].dMcal);
+    }
+  }
+
+  REALLOCATE (image, Image, MAX (nimage, 1));
+  free (timage);
+  *Nimages = nimage;
+  fclose (f);
+  return (image);
+}
+
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+/* returns the opening angle between the three points (2 is in middle) 
+   in range -pi to pi */
+double opening_angle (x1, y1, x2, y2, x3, y3)
+double x1, y1, x2, y2, x3, y3;
+{
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
+
+/* check if point x1,y1 is in box formed by x2[0-4] */
+int corner_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  int i;
+  double theta;
+
+  theta = 0;
+
+  for (i = 0; i < 4; i++) {
+    theta += opening_angle (x2[i], y2[i], x1[0], y1[0], x2[i+1], y2[i+1]); 
+  }
+  if (fabs(theta) > 6) {
+    return (TRUE);
+  } else {
+    return (FALSE);
+  }
+}
Index: /trunk/Ohana/src/markstar/src/find_line.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_line.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_line.c	(revision 2490)
@@ -0,0 +1,161 @@
+# include "markstar.h"
+
+find_line (catstats, mark, Npts, i, M, B, Angle)
+     CatStats catstats[];
+     double *M, *B, Angle;
+     int i, Npts;
+     char *mark;
+{
+  
+  float *R, *D;
+  int j, N;
+  double X, Y, X2, Y2, XY, m, b, det;
+  double dR, dD, Ra, De, angle;
+  char Flipped;
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+
+  /* fit a line to points near line */
+  Ra = R[i];
+  De = D[i];
+  X = Ra;
+  Y = De;
+  X2 = Ra*Ra;
+  Y2 = De*De;
+  XY = Ra*De;
+  N = 1;
+  /* points to the east */
+  for (j = i + 1; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      if (fabs(angle - Angle) < RAD_DEG) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* points to the west */
+  for (j = i - 1; !mark[i] && (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    if (mark[j]) continue;
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      angle = atan2 (dD,dR);
+      if (!finite(angle)) continue;
+      if (angle < 0) angle += M_PI;
+      if (fabs(angle - Angle) < RAD_DEG) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* determine coeffs */
+  Flipped = 0;
+  det = 1.0 / (X2*N - X*X);
+  m = det * (XY*N - X*Y);
+  b = det * (X2*Y - XY*X);
+  if (fabs(m) > 1.1) { /* use a line of R = m*D + b instead */
+    /* fprintf (stderr, "high slope object: %f %f  -> ", m, b); */
+    det = 1.0 / (Y2*N - Y*Y);
+    m = det * (XY*N - X*Y);
+    b = det * (Y2*X - XY*Y);
+    Flipped = 1;
+    /* fprintf (stderr, "%f %f\n", m, b); */
+  }
+
+  *M = m;
+  *B = b;
+  return (Flipped);
+
+}
+
+
+find_better_line (catstats, mark, Npts, i, M, B, axis)
+     CatStats catstats[];
+     double *M, *B;
+     int i, Npts, axis;
+     char *mark;
+{
+  
+  float *R, *D;
+  int j, N;
+  double X, Y, X2, Y2, XY, m, b, det;
+  double dR, dD, Ra, De, delta;
+  
+  R = catstats[0].X;
+  D = catstats[0].Y;
+
+  /* fit a line to points near line */
+  Ra = R[i];
+  De = D[i];
+  X = Y = X2 = Y2 = XY = N = 0;
+  m = *M;  b = *B;
+
+  /* points to the east */
+  for (j = i; (j < Npts) && (R[j] - Ra < RADIUS); j++) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      if (axis == 1) 
+	delta = R[j] - m*D[j] - b;
+      else
+	delta = D[j] - m*R[j] - b;
+      if (fabs(delta) < 2*TRAIL_WIDTH) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* points to the west */
+  for (j = i - 1; (j >= 0) && (Ra - R[j] < RADIUS); j--) {
+    dD = D[j] - De;
+    if (fabs(dD) < RADIUS) {
+      dR = R[j] - Ra;
+      if (axis == 1) 
+	delta = R[j] - m*D[j] - b;
+      else
+	delta = D[j] - m*R[j] - b;
+      if (fabs(delta) < 2*TRAIL_WIDTH) {
+	X += R[j];
+	Y += D[j];
+	X2 += R[j]*R[j];
+	Y2 += D[j]*D[j];
+	N ++;
+	XY += R[j]*D[j];
+      }
+    }
+  }
+  /* determine coeffs */
+  if (axis == 0) {
+    det = 1.0 / (X2*N - X*X);
+    m = det * (XY*N - X*Y);
+    b = det * (X2*Y - XY*X);
+  } else {
+    det = 1.0 / (Y2*N - Y*Y);
+    m = det * (XY*N - X*Y);
+    b = det * (Y2*X - XY*Y);
+  }
+
+  /* fprintf (stderr, "%f %f %d\n", m, b, N); */
+
+  *M = m;
+  *B = b;
+
+}
Index: /trunk/Ohana/src/markstar/src/find_matches.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_matches.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_matches.c	(revision 2490)
@@ -0,0 +1,87 @@
+# include "markstar.h"
+
+find_matches (catalog, catstats, Ghostdata, Nimage)
+CatStats catstats[];
+Catalog catalog[], Ghostdata[];
+int Nimage;
+{
+
+  int i, j, k, n, m, N, M, first_j;
+  double X, Y, RADIUS, RADIUS2;
+  float *X1, *Y1, *X2, *Y2;
+  float dX, dY, dR;
+  int *N1, *N2;
+  int Nstar, Nghost, Ng;
+  unsigned int flags;
+  Coords *tcoords;
+
+  Nstar = catalog[0].Naverage;
+  Nghost = Ghostdata[0].Naverage;
+
+  if (Nghost < 1) return (0);
+
+  /* it is better to have the catalog with fewer stars
+     assigned to the X1 set */
+  X2 = catstats[0].X;
+  Y2 = catstats[0].Y;
+  N2 = catstats[0].N;
+
+  ALLOCATE (X1, float, Nghost);
+  ALLOCATE (Y1, float, Nghost);
+  ALLOCATE (N1, int, Nghost);
+
+  /* project ghosts to the frame of the catalog */
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Nghost; i++) {
+    fRD_to_XY (&X1[i], &Y1[i], Ghostdata[0].average[i].R, Ghostdata[0].average[i].D, tcoords);
+    N1[i] = i;
+  }
+  if (Nghost > 1) sort_lists (X1, Y1, N1, Nghost);
+
+  /* choose a radius for matches */
+  RADIUS2 = GHOST_RADIUS*GHOST_RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nghost) && (j < Nstar); ) {
+    dX = X1[i] - X2[j];
+    if (dX <= -2*GHOST_RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*GHOST_RADIUS) {
+      j++;
+      continue;
+    }
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*GHOST_RADIUS) && (j < Nstar); j++) {
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < RADIUS2) {  
+	/* this object may be a ghost star, 
+	   but only mark those measurements on the correct image */
+	M = N2[j];
+	m = catalog[0].average[M].offset;
+	Ng = 0;
+	for (k = 0; k < catalog[0].average[M].Nm; k++) {
+	  if (catalog[0].image[m+k] == Nimage) {
+	    catalog[0].measure[m+k].average |= GHOST_DATA;
+	    Ng ++;
+	  }
+	}
+	/* all measurements are ghosts */
+	if (catalog[0].average[M].Nm == Ng) {
+	  catalog[0].average[M].code = ID_GHOST;
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+
+  free (X1);
+  free (Y1);
+  free (N1);
+
+}
Index: /trunk/Ohana/src/markstar/src/find_trails.c
===================================================================
--- /trunk/Ohana/src/markstar/src/find_trails.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/find_trails.c	(revision 2490)
@@ -0,0 +1,41 @@
+# include "markstar.h"
+
+find_trails (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i, j, N, Nave, axis, marked;
+  double density, spacing, Area, Angle, m, b, RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  char *mark;
+  int *N1;
+  Coords tcoords;
+  
+  Nave = catalog[0].Naverage;
+  N1 = catstats[0].N;
+
+  ALLOCATE (mark, char, Nave);
+  bzero (mark, Nave);
+
+  for (i = 0; i < Nave; i++) {
+    /* already marked, ignore */
+    if ((mark[i]) || 
+	(catalog[0].average[N1[i]].code == ID_BLEED) || 
+	(catalog[0].average[N1[i]].code == ID_GHOST))
+      continue;
+    /* a good star, ignore */
+    if ((catalog[0].average[N1[i]].Nm > 3) && 
+	(catalog[0].average[N1[i]].Nm > 4*catalog[0].average[N1[i]].Nn)) {
+      continue;
+    }
+    if (find_group (catstats, mark, Nave, i, &Angle)) {
+      /* this point has an excess nearby concentration, find the line */
+      axis = find_line (catstats, mark, Nave, i, &m, &b, Angle);
+      find_better_line (catstats, mark, Nave, i, &m, &b, axis);
+      mark_trail (catstats, mark, Nave, i, m, b, axis, catalog);
+    }
+  }
+}
+
Index: /trunk/Ohana/src/markstar/src/gcatalog.c
===================================================================
--- /trunk/Ohana/src/markstar/src/gcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/gcatalog.c	(revision 2490)
@@ -0,0 +1,41 @@
+# include "markstar.h"
+
+gcatalog (char *catname, Catalog *catalog) {
+  
+  char filename[128];
+  int i, status, mode;
+  unsigned int NotTrail;
+  unsigned short NotBad;
+
+  sprintf (filename, "%s/%s\0", CATDIR, catname);
+
+  mode = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+  status = load_catalog (filename, catalog, mode, VERBOSE);
+
+  switch (status) {
+  case 2:
+  case 0:
+    exit (0);
+  case 1:
+    break;
+  } 
+  if (catalog[0].Nsecfilt != photcodes.Nsecfilt) {
+    fprintf (stderr, "ERROR: mismatch in secondary photometry values\n");
+    exit (0);
+  }
+
+  if (RESET) {
+    NotBad = (0xffff ^ 0xc003);
+    for (i = 0; i < catalog[0].Naverage; i++) {
+      if ((catalog[0].average[i].code & ID_MOVING) &&
+	  (catalog[0].average[i].code & ID_BAD_OBJECT) &&
+	  (catalog[0].average[i].code & 0x0003)) {
+	/* this will set the correct bit for each to 0 */ 
+	catalog[0].average[i].code &= NotBad;
+      }
+    }
+    for (i = 0; i < catalog[0].Nmeasure; i++) {
+      catalog[0].measure[i].average &= ~PART_OF_TRAIL;
+    }
+  }
+}
Index: /trunk/Ohana/src/markstar/src/gcatstats.c
===================================================================
--- /trunk/Ohana/src/markstar/src/gcatstats.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/gcatstats.c	(revision 2490)
@@ -0,0 +1,67 @@
+# include "markstar.h"
+
+gcatstats (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  int i;
+  double RaCenter, DecCenter;
+  double MinRA, MaxRA, MinDEC, MaxDEC;
+  float *X1, *Y1;
+  int *N1;
+  Coords tcoords;
+  
+  fits_scan (&catalog[0].header, "RA0", "%lf", 1, &MinRA);
+  fits_scan (&catalog[0].header, "RA1", "%lf", 1, &MaxRA);
+  fits_scan (&catalog[0].header, "DEC0", "%lf", 1, &MinDEC);
+  fits_scan (&catalog[0].header, "DEC1", "%lf", 1, &MaxDEC);
+
+  /* double check on region RA and DEC ranges */
+  DecCenter = 0.5*(MinDEC + MaxDEC);
+  RaCenter = 0.5*(MinRA + MaxRA);
+  if (MaxDEC > 86.25) {  /* we are on the pole */
+    DecCenter = 90.0;
+    RaCenter = 0.0;
+  }
+
+  catstats[0].RA[0] = MinRA;
+  catstats[0].RA[1] = MaxRA;
+  catstats[0].DEC[0] = MinDEC;
+  catstats[0].DEC[1] = MaxDEC;
+  catstats[0].Area = (MaxDEC - MinDEC)*(MaxRA - MinRA) / cos (RAD_DEG*DecCenter);
+  if (MaxDEC > 86.25) {  /* we are on the pole */
+    catstats[0].Area = 44.2;
+  }
+  catstats[0].density = catalog[0].Naverage / (3600*3600*catstats[0].Area);
+  /* catstats[0].density = MIN_DENSITY; */
+  catstats[0].spacing = 1.0 / (NSIGMA * catstats[0].density * 2*TRAIL_WIDTH);
+  fprintf (stderr, "Area, density, spacing: %f %f %f\n", catstats[0].Area, 
+	   catstats[0].density, catstats[0].spacing);
+  /* number of stars per square arcsec */
+
+  /** allocate local arrays **/
+  ALLOCATE (catstats[0].X, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].Y, float, catalog[0].Naverage);
+  ALLOCATE (catstats[0].N, int,   catalog[0].Naverage);
+
+  /* project onto rectilinear grid with 1 arcsec pixels, sort by X */
+  /* reference for coords is center of field  */
+  catstats[0].coords.crval1 = RaCenter;
+  catstats[0].coords.crval2 = DecCenter;
+  catstats[0].coords.crpix1 = catstats[0].coords.crpix2 = 0.0;
+  catstats[0].coords.cdelt1 = catstats[0].coords.cdelt2 = 1.0 / 3600.0;
+  catstats[0].coords.pc1_1 = catstats[0].coords.pc2_2 = 1.0;
+  catstats[0].coords.pc1_2 = catstats[0].coords.pc2_1 = 0.0;
+  strcpy (catstats[0].coords.ctype, "RA---TAN");
+
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  for (i = 0; i < catalog[0].Naverage; i++, X1++, Y1++) {
+    fRD_to_XY (X1, Y1, catalog[0].average[i].R, catalog[0].average[i].D, &catstats[0].coords);
+    catstats[0].N[i] = i;
+  }
+  if (catalog[0].Naverage > 1) sort_lists (catstats[0].X, catstats[0].Y, catstats[0].N, catalog[0].Naverage);
+  
+}
+
Index: /trunk/Ohana/src/markstar/src/gregions.c
===================================================================
--- /trunk/Ohana/src/markstar/src/gregions.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/gregions.c	(revision 2490)
@@ -0,0 +1,134 @@
+# include "markstar.h"
+
+GSCRegion *gregions1 (catstats, Nregions)
+CatStats catstats[];
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  int i, j, k, x, y, done, nregion, nregion2, NREGION;
+  double ra, dec, dx, dy, Xo[4], Yo[4];
+  FILE *f;
+
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: could not open GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  nregion = 0;
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+
+  if (catstats[0].DEC[0] == 86.25) { /* pole region */
+    dec = 86.0;
+    for (ra = 0.1; ra < 370; ra+= 30.0) {
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion - 1) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  } else {
+    for (x = 0; x < 2; x++) {
+      for (y = 0; y < 2; y++) {
+	for (dx = -0.1; dx <= 0.1; dx += 0.2) {
+	  for (dy = -0.1; dy <= 0.1; dy += 0.2) {
+	    ra  = catstats[0].RA[x] + dx;
+	    dec = catstats[0].DEC[y] + dy;
+	    aregion (&region[nregion], f, ra, dec);
+	    done = FALSE;
+	    for (j = 0; (j < nregion) && !done; j++) {
+	      if (!strcmp (region[nregion].filename, region[j].filename)) {
+		done = TRUE;
+	      }
+	    }
+	    if (!done) {
+	      nregion ++;
+	    } 
+	    if (nregion == NREGION) {
+	      NREGION += 10;
+	      REALLOCATE (region, GSCRegion, NREGION);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "using %d regions\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "region %d: %f %f  %f %f\n", i, region[i].RA[0], region[i].RA[1], region[i].DEC[0], region[i].DEC[1]);
+    } 
+  }
+
+  REALLOCATE (region, GSCRegion, MAX (nregion, 1));
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
+
+GSCRegion *gregions2 (image, Nregions)
+Image *image;
+int *Nregions;
+{
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dr, dd, dec, ra;
+  int i, j, done, nregion, NREGION;
+  
+  f = fopen (GSCFILE, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", GSCFILE);
+    exit (0);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "found %d region files:\n", nregion);
+    for (i = 0; i < nregion; i++) {
+      fprintf (stderr, "  %d %s\n", i, region[i].filename);
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /trunk/Ohana/src/markstar/src/load_gsc_data.c
===================================================================
--- /trunk/Ohana/src/markstar/src/load_gsc_data.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/load_gsc_data.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "markstar.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+load_gsc_data (catalog, catstats)
+Catalog catalog[];
+CatStats catstats[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes, Nregions;
+  double R, D, M, MagLimit;
+  FILE *f;
+  GSCRegion *region, *gregions1(), *gregions2();
+  
+  region = gregions1 (catstats, &Nregions);
+
+  MagLimit = MAX (MAX (BRIGHT_HALO_MAG, BRIGHT_XTRAIL_MAG), BRIGHT_YTRAIL_MAG); 
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  Nbytes = BLOCK*BYTES_STAR;
+  
+  for (j = 0; j < Nregions; j++) {
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "GSC file for region %s missing\n", region[j].filename);
+      exit (0);
+    }
+    
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > MagLimit) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+    fclose (f);
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, nstar);
+  catalog[0].Naverage = nstar;
+  
+}
+
Index: /trunk/Ohana/src/markstar/src/load_gsc_data_ghost.c
===================================================================
--- /trunk/Ohana/src/markstar/src/load_gsc_data_ghost.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/load_gsc_data_ghost.c	(revision 2490)
@@ -0,0 +1,75 @@
+# include "markstar.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+/* this routine is basically identical to load_gsc_data, but
+   it is not limited to a single region file, and it merges the 
+   results */
+
+load_gsc_data_ghost (catalog, region, Nregion, image)
+Catalog catalog[];
+GSCRegion *region;
+int Nregion;
+Image image[];
+{
+
+  /* load data from the GSC files */
+  char filename[128];
+  char *tbuffer;
+  int nstar, NSTARS;
+  int i, j, Nbytes, nbytes;
+  double R, D, M, X, Y;
+  FILE *f;
+  Coords *tcoords;
+  int MinX, MinY, MaxX, MaxY;
+  
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog[0].average, Average, NSTARS);
+  tcoords = &image[0].coords;
+  MinX = 0;
+  MinY = 0;
+  MaxX = image[0].NX;
+  MaxY = image[0].NY;
+  
+  for (j = 0; j < Nregion; j++) {
+    
+    f = fopen (region[j].filename, "r");
+    if (f == (FILE *) NULL) {
+      fprintf (stderr, "no GSC file for region %s (2)\n", region[j].filename);
+      exit (0);
+    }
+    
+    Nbytes = BLOCK*BYTES_STAR;
+    while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+      for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	if (M > GHOST_MAG) continue;
+	dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	RD_to_XY (&X, &Y, R, D, tcoords);
+	if ((X < MinX) || (X > MaxX) || (Y < MinY) || (Y > MaxY)) continue;
+	catalog[0].average[nstar].R = R;
+	catalog[0].average[nstar].D = D;
+	catalog[0].average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog[0].average, Average, NSTARS);
+	}
+      }
+    }
+    fclose (f);
+
+  }
+
+  free (tbuffer);
+  REALLOCATE (catalog[0].average, Average, MAX (nstar, 1));
+  catalog[0].Naverage = nstar;
+
+}
+
+
Index: /trunk/Ohana/src/markstar/src/mark_trail.c
===================================================================
--- /trunk/Ohana/src/markstar/src/mark_trail.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/mark_trail.c	(revision 2490)
@@ -0,0 +1,272 @@
+# include "markstar.h"
+int *make_common_list ();
+int *check_common_list ();
+
+mark_trail (catstats, mark, Nave, i, m, b, axis, catalog)
+     CatStats catstats[];
+     char *mark;
+     int i, Nave, axis;
+     double m, b;
+     Catalog catalog[];
+{
+
+  float *R, *D;
+  int j, k, jj, kk, N, NPTS, marked, start, end, Nm;
+  int *good, *seq, *N1;
+  double *dist, *dist2;
+  double d2, di, Di, dD, n, Dist, scale, norm;
+  double spacing;
+  int *list, Nlist;
+  int M, Nmeas, thisimage;
+
+  R = catstats[0].X;
+  D = catstats[0].Y;
+  N1 = catstats[0].N;
+  spacing = catstats[0].spacing;
+
+  NPTS = 200;
+  ALLOCATE (good, int, NPTS);
+  ALLOCATE (dist, double, NPTS);
+  ALLOCATE (dist2, double, NPTS);
+  ALLOCATE (seq, int, NPTS);
+
+  /* Find all points which lie near line */
+  /* save the entry number and distance along line */
+  N = 0;
+  scale = sqrt (1.0 + m*m);
+
+  if (axis == 1) {
+    for (j = 0; j < Nave; j++) {
+      norm = scale * fabs(R[j] - m*D[j] - b);
+      if (!mark[j] && (norm < TRAIL_WIDTH)) {
+	good[N] = j;
+	dist[N] = scale * (D[j] - D[i] + m*(R[j] - R[i]));
+	seq[N] = N;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 200;
+	  REALLOCATE (good, int, NPTS);
+	  REALLOCATE (dist, double, NPTS);
+	  REALLOCATE (dist2, double, NPTS);
+	  REALLOCATE (seq, int, NPTS);
+	}
+      }
+    }
+  } else {
+    for (j = 0; j < Nave; j++) {
+      norm = scale * fabs(D[j] - m*R[j] - b);
+      if (!mark[j] && (norm < TRAIL_WIDTH)) {
+	good[N] = j;
+	dist[N] = scale * (R[j] - R[i] + m*(D[j] - D[i]));
+	seq[N] = N;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 200;
+	  REALLOCATE (good, int, NPTS);
+	  REALLOCATE (dist, double, NPTS);
+	  REALLOCATE (dist2, double, NPTS);
+	  REALLOCATE (seq, int, NPTS);
+	}
+      }
+    }
+  }
+  
+  if (N < NPTSINLINE) 
+    return (0);
+
+  sort_seq (dist, seq, N);
+  
+  start = -1; end = -1;
+  for (j = 0; j < N-1; j++) {
+    /* if we have part of a line, and next point is in the line, check for common images */
+    if ((start != -1) && (fabs(dist[j] - dist[j+1]) < spacing)) {
+      list = check_common_list (list, N1[good[seq[j+1]]], &Nlist, catalog);
+      if (Nlist == 0) { /* if no common images, dump list and continue */
+	end = j + 1;
+	if (end - start > NPTSINLINE) {
+	  if (axis == 0)
+	    fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", m, b, N, end-start, start, end, dist[start], dist[end-1]);
+	  else
+	    fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", 1.0/m, -1.0*b/m, N, end-start, start, end, dist[start], dist[end-1]);
+	  for (k = start; k < end; k++) {
+	    M = N1[good[seq[k]]];
+	    mark[good[seq[k]]] = TRUE;
+	    /* we need to mark measurements from all images in common on the line */
+	    Nm = 0;
+	    for (jj = 0; jj < catalog[0].average[M].Nm; jj++) {
+	      Nmeas = catalog[0].average[M].offset + jj;
+	      thisimage = catalog[0].image[Nmeas];
+	      for (kk = 0; kk < Nlist; kk++) {
+		if (thisimage == list[kk]) {
+		  catalog[0].measure[Nmeas].average |= PART_OF_TRAIL;
+		  Nm ++;
+		}
+	      }
+	    }
+	    /* if there is only 1 measurement, mark object as bad */
+	    if (catalog[0].average[M].Nm == Nm) {
+	      catalog[0].average[M].code = ID_TRAIL;
+	    }
+	    catalog[0].average[M].code = ID_TRAIL;
+	  }
+	}
+	start = -1;
+	end = -1;
+      }
+    }
+    /* if we haven't yet found a line segment, check for the beginning */
+    if ((start < 0) && (fabs(dist[j] - dist[j+1]) < spacing)) {
+      start = j;
+      list = make_common_list (N1[good[seq[j]]], N1[good[seq[j+1]]], &Nlist, catalog);
+      if (Nlist == 0) { /* if no common images, move on */
+	start = -1;
+	free (list);
+      }
+    }
+    /* if we have a complete line, check for validity.  if it has enough members,
+	 mark them and continue searching for lines */
+    if ((start != -1) && ((fabs(dist[j] - dist[j+1]) >= spacing) || (j == N-2))) {
+      end = j + 1;
+      if (end - start > NPTSINLINE) {
+	if (axis == 0)
+	  fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", m, b, N, end-start, start, end, dist[start], dist[end-1]);
+	else
+	  fprintf (stderr, "marking line %f %f  %d pts  %d  %d %d, %f %f\n", 1.0/m, -1.0*b/m, N, end-start, start, end, dist[start], dist[end-1]);
+	for (k = start; k < end; k++) {
+	  M = N1[good[seq[k]]];
+	  mark[good[seq[k]]] = TRUE;
+	  if (catalog[0].average[M].code == ID_BLEED) continue;
+	  /* we need to mark measurements from all images in common on the line */
+	  Nm = 0;
+	  for (jj = 0; jj < catalog[0].average[M].Nm; jj++) {
+	    Nmeas = catalog[0].average[M].offset + jj;
+	    thisimage = catalog[0].image[Nmeas];
+	    for (kk = 0; kk < Nlist; kk++) {
+	      if (thisimage == list[kk]) {
+		catalog[0].measure[Nmeas].average |= PART_OF_TRAIL;
+		Nm ++;
+	      }
+	    }
+	  }
+	  /* if there is only 1 measurement, mark object as bad */
+	  if (catalog[0].average[M].Nm == Nm) {
+	    catalog[0].average[M].code = ID_TRAIL;
+	  }
+	  catalog[0].average[M].code = ID_TRAIL;
+	}
+      }
+      free (list);
+      start = -1;
+      end = -1;
+    }
+  }
+}
+
+
+/* I is Average seq number for star 1, J for star 2 */
+/* make a list of images in common between two measurements */
+int *make_common_list (I, J, Nlist, catalog)
+int I, J, *Nlist;
+Catalog catalog[];
+{
+
+  int i, j, N1, N2, nlist, NLIST;
+  int *list;
+  int k, already;
+
+  NLIST = 50;
+  ALLOCATE (list, int, NLIST);
+  nlist = 0;
+
+  for (i = 0; i < catalog[0].average[I].Nm; i++) {
+    N1 = catalog[0].average[I].offset + i;
+    if (catalog[0].image[N1] == -1)
+      continue; /* not a real measurement */
+    for (j = 0; j < catalog[0].average[J].Nm; j++) {
+      N2 = catalog[0].average[J].offset + j;
+      if (catalog[0].image[N2] == -1)
+	continue; /* not a real measurement */
+      if (catalog[0].image[N1] == catalog[0].image[N2]) {
+	already = FALSE; 
+	for (k = 0; !already && (k < nlist); k++) {
+	  if (catalog[0].image[N1] == list[k]) { 
+	    already = TRUE;
+	  }
+	}
+	if (!already) {
+	  list[nlist] = catalog[0].image[N1];
+	  nlist ++;
+	  if (nlist == NLIST - 1) {
+	    NLIST += 50;
+	    REALLOCATE (list, int, NLIST);
+	  }
+	}
+      }
+    }
+  }
+  
+  REALLOCATE (list, int, MAX(nlist, 1));
+  *Nlist = nlist;
+  return (list);
+
+}
+
+
+
+/* J is Average seq number for star */
+
+int *check_common_list (inlist, J, Nlist, catalog)
+int *inlist, J, *Nlist;
+Catalog catalog[];
+{
+
+  int i, j, N2, Ninlist;
+  int *list, NLIST, nlist;
+  int already, found, k;
+
+  NLIST = 50;
+  ALLOCATE (list, int, NLIST);
+  nlist = 0;
+  Ninlist = *Nlist;
+
+  for (j = 0; j < catalog[0].average[J].Nm; j++) {
+    N2 = catalog[0].average[J].offset + j;
+    found = FALSE;
+    for (i = 0; !found && (i < Ninlist); i++) {
+      if (catalog[0].image[N2] == -1)
+	continue; /* not a real measurement */
+      if (inlist[i] == catalog[0].image[N2]) {
+	found = TRUE;
+	already = FALSE; 
+	for (k = 0; !already && (k < nlist); k++) {
+	  if (inlist[i] == list[k]) {
+	    already = TRUE;
+	  }
+	}
+	if (!already) {
+	  list[nlist] = inlist[i];
+	  nlist ++;
+	  if (nlist == NLIST - 1) {
+	    NLIST += 50;
+	    REALLOCATE (list, int, NLIST);
+	  }
+	}
+      }
+    }
+  }
+  
+  /* if there are no common images, return the input list */
+  if (nlist != 0) {
+    free (inlist);
+    REALLOCATE (list, int, MAX(nlist, 1));
+    *Nlist = nlist;
+    return (list);
+  } else {
+    return (inlist);
+  }
+
+}
+
+
+/* measurements associated with image number -1 are not 
+   measurements we made, but are added, like USNO */
Index: /trunk/Ohana/src/markstar/src/markstar.c
===================================================================
--- /trunk/Ohana/src/markstar/src/markstar.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/markstar.c	(revision 2490)
@@ -0,0 +1,67 @@
+# include "markstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, Nstars, Nimage, Nregions, Nmissed;
+  Image *image, *find_images();
+  Catalog catalog;
+  CatStats catstats;
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (&argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  FORCE_RUN = FALSE;
+  if ((i = get_argument (argc, argv, "-f"))) {
+    FORCE_RUN = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  RESET = FALSE;
+  if ((i = get_argument (argc, argv, "-reset"))) {
+    RESET = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: markstar (catalog)\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile (); 
+  check_permissions (argv[1]);
+
+  gcatalog (argv[1], &catalog);
+
+  gcatstats (&catalog, &catstats);
+
+  image = find_images (&catstats, &Nimage);
+
+  match_images (&catalog, image, Nimage);
+    
+  find_trails (&catalog, &catstats, i);  
+
+  /* find_bright_stars (&catalog, &catstats);  */
+
+  /* find_ghosts (&catalog, &catstats, argv[1], image, Nimage); */
+
+
+  wcatalog (argv[1], &catalog);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+}
+
Index: /trunk/Ohana/src/markstar/src/match_images.c
===================================================================
--- /trunk/Ohana/src/markstar/src/match_images.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/match_images.c	(revision 2490)
@@ -0,0 +1,62 @@
+# include "markstar.h"
+
+match_images (catalog, image, Nimage)
+Catalog catalog[];
+Image   image[];
+int Nimage;
+{
+  
+  int j, k, found;
+  unsigned int *start, *stop;
+  short int *source;
+
+  /* this must be allocated so future free will not fail */
+  ALLOCATE (catalog[0].image, int, MAX (catalog[0].Nmeasure, 1));
+  if (catalog[0].Naverage == 0) {
+    if (VERBOSE) fprintf (stderr, "no stars in catalog, skipping\n");
+    return (FALSE);
+  }
+
+  ALLOCATE (start, unsigned int, Nimage);
+  ALLOCATE (stop,  unsigned int, Nimage);
+  ALLOCATE (source, short int, Nimage);
+  for (j = 0; j < Nimage; j++) {
+    start[j] = image[j].tzero - MAX(0.05*image[j].trate*image[j].NY, 1);
+    stop[j]  = image[j].tzero + MAX(1.05*image[j].trate*image[j].NY, 1);
+    source[j] = image[j].source;
+  }
+
+  for (j = 0; j < catalog[0].Nmeasure; j++) {
+    found = FALSE;
+    if (catalog[0].measure[j].t == 0) {
+      catalog[0].image[j] = -1;
+      found = TRUE;
+    }
+    for (k = 0; (k < Nimage) && !found; k++) {
+      if ((catalog[0].measure[j].t >= start[k]) && 
+	  (catalog[0].measure[j].t <= stop[k])  &&
+	  (catalog[0].measure[j].source == source[k])) {
+	catalog[0].image[j] = k;
+	found = TRUE;
+      }
+    }
+    if (!found) {
+      fprintf (stderr, "ERROR: can't find source image for this measurement: %d %d)\n",
+	       catalog[0].measure[j].t, catalog[0].measure[j].source);
+      exit (0);
+    }
+  }
+  free (start);
+  free (stop);
+  free (source);
+}
+
+  /* this routine uses the time of each measurement to match the
+measurement with an image.  Since the measurement is only store to 1
+sec accuracy, which corresponds to roughly 30 rows at nominal speed,
+we can't tell exactly which image the star come from.  However, this
+doesn't matter, and in fact this helps a bit: a measurement from the
+top of one image is the same as from the bottom of the next.
+Therefore, we intentionally blur the edges of the images by 5%, which
+will help to tie together neighboring images... */
+
Index: /trunk/Ohana/src/markstar/src/old/add_unfound.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/add_unfound.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/add_unfound.c	(revision 2490)
@@ -0,0 +1,35 @@
+  /* incorporate unmatched image stars -- after all catalogs searched... */
+  for (i = 0; i < Nstars; i++) {
+    if (!found[i]) {
+      catalog[0].average[Nave].R = stars[N1[i]].R;
+      catalog[0].average[Nave].D = stars[N1[i]].D;
+      catalog[0].average[Nave].M = 1000.0*stars[N1[i]].M;
+      catalog[0].average[Nave].Nm = 1;
+      catalog[0].average[Nave].Xp = catalog[0].average[Nave].Xm = 0.0;
+      catalog[0].average[Nave].offset = Nmeas;
+      catalog[0].measure[Nmeas].dR  = 0.0;
+      catalog[0].measure[Nmeas].dD  = 0.0;
+      catalog[0].measure[Nmeas].M   = 1000.0*stars[N1[i]].M;
+      catalog[0].measure[Nmeas].dM  = stars[N1[i]].dM;
+      catalog[0].measure[Nmeas].t  = 3600.0 + stars[N1[i]].Y*0.1;
+      catalog[0].measure[Nmeas].average = (0x00ffffff & Nave);
+      /* time of star = time of image + offset + Y*rate */
+      Nave ++;
+      if (Nave == 0x1000000) {
+	fprintf (stderr, "too many stars in catalog\n");
+	clear_lockfile ();
+	exit (0);
+      }
+      if (Nave == NAVE) {
+	NAVE = Nave + 1000;
+	REALLOCATE (next, int, NAVE);
+	REALLOCATE (catalog[0].average, Average, NAVE);
+      }
+      Nmeas ++;
+      if (Nmeas == NMEAS) {
+	NMEAS = Nmeas + 1000;
+	REALLOCATE (next, int, NMEAS);
+	REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      }
+    }
+  }
Index: /trunk/Ohana/src/markstar/src/old/addstar.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/addstar.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/addstar.c	(revision 2490)
@@ -0,0 +1,70 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  FILE *f;
+  int i, Nstars, Nimage, Nregions, Nmissed;
+  Stars *stars, *gstars();
+  Image image, *pimage, *gimages();
+  Catalog catalog;
+  GSCRegion *region, *gregions();
+  struct timeval now, then;  
+  
+  gettimeofday (&then, (void *) NULL);
+  ConfigInit (argc, argv);
+
+  VERBOSE = FALSE;
+  if ((i = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (i, &argc, argv);
+  }
+  if (argc < 2) {
+    fprintf (stderr, "ERROR: Usage: addstar filename\n");
+    exit (0);
+  }
+
+  /* if lockfile exists, program will complain and quit */
+  check_lockfile ();
+
+  stars = gstars (argv[1], &Nstars, &image);
+
+  pimage = gimages (&image, &Nimage);
+  region = gregions (&image, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    gcatalog (&region[i], &catalog);
+    find_matches (&region[i], stars, Nstars, &catalog, &image, pimage, Nimage);
+    wcatalog (&region[i], &catalog);
+  }
+  
+  for (Nmissed = i = 0; i < Nstars; i++) {
+    if (stars[i].found == -1) {
+      fprintf (stderr, "%d %f %f %f %f\n", i, stars[i].R, stars[i].D, stars[i].M, stars[i].dM);
+      Nmissed ++;
+    }
+  }
+  if (Nmissed) fprintf (stderr, "WARNING: %d stars in image were missed!\n", Nmissed);
+
+  wimage (argv[1], &image, Nstars);
+
+  if (VERBOSE) {
+    gettimeofday (&now, (void *) NULL);
+    fprintf (stderr, "%s: elapsed time = %.2f sec\n", argv[1], 
+	     (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec));
+  }
+  clear_lockfile ();
+  fprintf (stderr, "SUCCESS\n");
+}
+
+
+  /* stars within a file are not all within 1 region file:
+     1) check if unfound stars are in current region 
+     2) if not, keep unfound for next pass */
+
+
+/* input star lists should be adjusted so 1 e/sec is mag 25.000 */ 
+
+
Index: /trunk/Ohana/src/markstar/src/old/dumpcat.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/dumpcat.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/dumpcat.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "addstar.h"
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+
+  int i, j, Nstars, Nimage, Nregions;
+  Average *average;
+  Measure *measure;
+  Missing *missing;
+  Catalog catalog;
+  GSCRegion region;
+  FILE *f;
+  
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: dumpcat catalog output mode(0,1,2,3)\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  strcpy (region.filename, argv[1]);
+
+  gcatalog (&region, &catalog);
+
+  f = fopen (argv[2], "w");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "failed to open file %s for write\n", argv[2]);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  average = catalog.average;
+  for (i = 0; i < catalog.Naverage; i++) {
+    fprintf (f, "%10.6f %10.6f %7.3f %3d %3d %8d %d\n", average[i].R, average[i].D, 
+	     0.001*average[i].M, average[i].Nm, average[i].Nn, average[i].offset, catalog.measure[average[i].offset].t);
+    if ((atof(argv[3]) == 1) || (atof(argv[3]) == 3)) {
+      measure = &catalog.measure[average[i].offset];
+      for (j = 0; j < average[i].Nm; j++) {
+	fprintf (f, "  %d %d %f %f %d\n", measure[j].dR, measure[j].dD, 0.001*measure[j].M, 
+		  measure[j].t, measure[j].average);
+      }
+    }
+    if ((atof(argv[3]) == 2) || (atof(argv[3]) == 3)) {
+      if (average[i].Nn > 0) {
+	missing = &catalog.missing[average[i].missing];
+	for (j = 0; j < average[i].Nn; j++) {
+	  fprintf (f, "  %f\n", missing[j].t);
+	}
+      } else { 
+	fprintf (f, "no missing obs\n");
+      }
+    }
+  }
+
+    
+
+  fclose (f);
+    
+
+}
Index: /trunk/Ohana/src/markstar/src/old/find_bright_stars_test.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/find_bright_stars_test.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/find_bright_stars_test.c	(revision 2490)
@@ -0,0 +1,106 @@
+# include "markstar.h"
+
+find_bright_stars (catalog, catstats, filename)
+Catalog catalog[];
+CatStats catstats[];
+char *filename;
+{
+
+  int i, j, first_j, Nave, Ngsc;
+  Catalog GSCdata;
+  double MinRA, MinDEC, MaxRA, MaxDEC, RaCenter, DecCenter;
+  Coords *tcoords;
+  float *X1, *Y1, *X2, *Y2;
+  int *N1, *N2, *match;
+  char *mark;
+  double dX, dY, dR, RADIUS2, BRIGHT_RADIUS, radius;
+
+  load_gsc_data (&GSCdata, filename);
+
+  Nave = catalog[0].Naverage;
+  Ngsc = GSCdata.Naverage;
+    
+  X1 = catstats[0].X;
+  Y1 = catstats[0].Y;
+  N1 = catstats[0].N;
+  ALLOCATE (mark, char, Nave);
+  ALLOCATE (match, int, Nave);
+  ALLOCATE (X2, float, Ngsc);
+  ALLOCATE (Y2, float, Ngsc);
+  ALLOCATE (N2, int, Ngsc);
+  bzero (mark, Nave);
+
+  tcoords = &catstats[0].coords;
+  for (i = 0; i < Ngsc; i++) {
+    fRD_to_XY (&X2[i], &Y2[i], GSCdata.average[i].R, GSCdata.average[i].D, tcoords);
+    N2[i] = i;
+  }
+  if (Ngsc > 1) sort_lists (X2, Y2, N2, Ngsc);
+  
+  /* max radius (mag = -1) */
+  BRIGHT_RADIUS = BRIGHT_SLOPE * (-1.0 - BRIGHT_MAG);
+
+  /** find catalog stars near GSC stars **/
+  for (i = j = 0; (i < Nave) && (j < Ngsc); ) {
+    
+    dX = X1[i] - X2[j];
+
+    if (dX <= -2*BRIGHT_RADIUS) {
+      i++;
+      continue;
+    }
+    if (dX >= 2*BRIGHT_RADIUS) {
+      j++;
+      continue;
+    }
+
+    /* negative dX: j is too large, positive dX, i is too large */
+    first_j = j;
+    for (; (dX > -2*BRIGHT_RADIUS) && (j < Ngsc); j++) {
+      radius = MAX (BRIGHT_SLOPE * (0.001*GSCdata.average[N2[j]].M - BRIGHT_MAG), 0.0);
+      RADIUS2 = radius*radius;
+      dX = X1[i] - X2[j];
+      dY = Y1[i] - Y2[j];
+      dR = dX*dX + dY*dY;
+      if (dR < RADIUS2) {  /* new measurement of this star */
+	mark[i] = TRUE;
+	match[i] = N2[j];
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  
+  /* done with search, mark selected stars */
+  
+  for (i = 0; i < Nave; i++) {
+    if (mark[i]) {
+      catalog[0].average[N1[i]].code = ID_BLEED;
+    }
+  } 
+  
+}
+
+	/* for test purposes, like determining the parameters, uncomment this 
+	n = N1[i];
+	m = N2[j];
+	fprintf (stdout, "%f %f %f %f %f %f\n", 
+GSCdata.average[m].R, GSCdata.average[m].D, 
+		 0.001*GSCdata.average[m].M, 
+catalog[0].average[n].R, catalog[0].average[n].D, 0.001*catalog[0].average[n].M); */
+  
+  /* for test purposes, like determining the parameters, uncomment this 
+  clear_lockfile (); 
+  fprintf (stderr, "SUCCESS\n");
+  exit (0); */
+
+
+
+	n = N1[i];
+	m = N2[j];
+	RD_to_XY (&X, &Y, Ghostdata[0].average[m].R, Ghostdata[0].average[m].D, &image[0].coords);
+	fprintf (stdout, "%f %f %f %f %f %f %d %f %f\n",
+		 Ghostdata[0].average[m].R, Ghostdata[0].average[m].D, 
+		 0.001*Ghostdata[0].average[m].M, catalog[0].average[n].R, 
+		 catalog[0].average[n].D, 0.001*catalog[0].average[n].M, 
+		 catalog[0].average[n].Nm, X, Y);
Index: /trunk/Ohana/src/markstar/src/old/gimages.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/gimages.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/gimages.c	(revision 2490)
@@ -0,0 +1,214 @@
+# include "addstar.h"
+double opening_angle ();
+
+Image *gimages (image, Npimage)
+Image image[];
+int *Npimage;
+{
+  
+  int i, j, k, NIMAGE, Nimage, addtolist;
+  int NTIMAGE, Ntimage, ntimage;
+  int NPIMAGE, npimage;
+  FILE *f;
+  Image *timage, *pimage;
+  Coords tcoords;
+  Header header;
+  double r, d;
+  double Xi[5], Yi[5], Xo[5], Yo[5];  /* image and original corners */
+
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (ImageCat, &header)) {
+    if (VERBOSE) fprintf (stderr, "New image catalog %s (1)\n", ImageCat);
+    *Npimage = 0;
+    return ((Image *) NULL);
+  }
+
+  /* project onto rectilinear grid with 1 arcsec pixels */
+  /* we keep the original crpix1,2 and crref1,2 */
+  tcoords = image[0].coords;
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+  tcoords.pc1_1 = tcoords.pc2_2 = 1.0;
+  tcoords.pc1_2 = tcoords.pc2_1 = 0.0;
+  strcpy (tcoords.ctype, "RA---TAN");
+
+  /* define original corners */
+  Xo[0] = 0;           Yo[0] = 0;
+  Xo[1] = image[0].NX; Yo[1] = 0;
+  Xo[2] = image[0].NX; Yo[2] = image[0].NY;
+  Xo[3] = 0;           Yo[3] = image[0].NY;
+  Xo[4] = 0;           Yo[4] = 0;  /* so we can make a loop easily */
+  for (j = 0; j < 5; j++) {
+    XY_to_RD (&r, &d, Xo[j], Yo[j], &image[0].coords);
+    RD_to_XY (&Xo[j], &Yo[j], r, d, &tcoords);
+  }
+  
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "New image catalog: %s (2)\n", ImageCat);
+    free (header.buffer);
+    *Npimage = 0;
+    return ((Image *) NULL);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+
+  NTIMAGE = 100;
+  ALLOCATE (timage, Image, NTIMAGE);
+
+  npimage = 0;
+  NPIMAGE = 20;
+  ALLOCATE (pimage, Image, NPIMAGE);
+
+  for (Ntimage = 0; Ntimage < Nimage; Ntimage += ntimage) {
+    ntimage = Fread (timage, sizeof(Image), NTIMAGE, f, "image");
+    for (i = 0; i < ntimage; i++) {
+      addtolist = FALSE;
+      /* define image corners */
+      Xi[0] = 0;            Yi[0] = 0;
+      Xi[1] = timage[i].NX; Yi[1] = 0;
+      Xi[2] = timage[i].NX; Yi[2] = timage[i].NY;
+      Xi[3] = 0;            Yi[3] = timage[i].NY;
+      Xi[4] = 0;            Yi[4] = 0;  /* so we can make a loop easily */
+      /* transform to tcoords */
+      for (j = 0; j < 5; j++) {
+	XY_to_RD (&r, &d, Xi[j], Yi[j], &timage[i].coords);
+	RD_to_XY (&Xi[j], &Yi[j], r, d, &tcoords);
+      }
+      /* check if any edges cross */
+      for (j = 0; j < 4; j++) {
+	for (k = 0; k < 4; k++) {
+	  addtolist |= edge_check (&Xi[j], &Yi[j], &Xo[k], &Yo[k]);
+	}
+      }
+      
+      /*
+      fprintf (stderr, "%f %f %f %d %f %f %d %d %d %f %f %s: %d\n", 0.1*timage[i].detection_limit, 0.1*timage[i].saturation_limit, 0.02*timage[i].cerror, 
+	       timage[i].tzero, 1e-4*timage[i].trate, 
+	       0.001*timage[i].secz, timage[i].nstar, timage[i].NX, timage[i].NY, 0.001*timage[i].Mcal, 0.1*timage[i].Xm, timage[i].name, addtolist);
+      
+      fprintf (stderr, "%s\n", timage[i].coords.ctype);
+      fprintf (stderr, "%f %f\n", timage[i].coords.crval1, timage[i].coords.crval2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.crpix1, timage[i].coords.crpix2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.pc1_1, timage[i].coords.pc1_2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.pc2_1, timage[i].coords.pc2_2);
+      fprintf (stderr, "%f %f\n", timage[i].coords.cdelt1, timage[i].coords.cdelt2);      
+      */
+
+      if (addtolist) {
+	pimage[npimage] = timage[i];
+	npimage ++;
+	if (npimage == NPIMAGE) {
+	  NPIMAGE += 20;
+	  REALLOCATE (pimage, Image, NPIMAGE);
+	}
+      }
+    }
+
+    if (ntimage == 0) {
+      fprintf (stderr, "ERROR: expected %d images, only found %d\n", Nimage, Ntimage);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+
+  if (VERBOSE) fprintf (stderr, "found %d overlapping images\n", npimage);
+
+  fclose (f);
+  *Npimage = npimage;
+  return (pimage);
+
+}
+  
+int edge_check (x1, y1, x2, y2)
+double *x1, *y1, *x2, *y2;
+{
+
+  double theta1, theta2;
+  double Theta1, Theta2;
+
+  theta1 = opening_angle (x1[0], y1[0], x2[0], y2[0], x1[1], y1[1]); 
+  theta2 = opening_angle (x1[0], y1[0], x2[0], y2[0], x2[1], y2[1]); 
+
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  Theta1 = theta1;
+  Theta2 = theta2;
+  theta1 = opening_angle (x2[0], y2[0], x1[1], y1[1], x2[1], y2[1]); 
+  theta2 = opening_angle (x2[0], y2[0], x1[1], y1[1], x1[0], y1[0]); 
+  
+ 
+  if (theta1*theta2 < 0.0) {
+    return (FALSE);
+  }
+
+  if (fabs(theta1) < fabs(theta2)) {
+    return (FALSE);
+  }
+
+  return (TRUE);
+
+}
+
+double opening_angle (x1, y1, x2, y2, x3, y3)
+double x1, y1, x2, y2, x3, y3;
+{
+
+  double dx1, dy1, dx2, dy2, ct, st, theta;
+
+  dx1 = x1 - x2;
+  dy1 = y1 - y2;
+  
+  dx2 = x3 - x2;
+  dy2 = y3 - y2;
+  
+  ct = (dx1*dx2 + dy1*dy2);
+  st = (dx1*dy2 - dx2*dy1);
+
+  theta = atan2 (st, ct);
+
+  return (theta);
+
+}
+
+
+
+
+/* probably not needed now 
+char *_parse_nextword();
+
+
+int fparse (X, NX, line)
+float *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
+
+*/
Index: /trunk/Ohana/src/markstar/src/old/gstars.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/gstars.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/gstars.c	(revision 2490)
@@ -0,0 +1,186 @@
+# include "addstar.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 31
+# define BLOCK 1000
+#include <sys/time.h>
+#include <time.h>
+
+Stars *gstars (file, NSTARS, image) 
+char file[];
+int *NSTARS;
+Image *image;
+{
+
+  FILE *f;
+  Header header;
+  int i, j, nstar;
+  int nbytes, Nbytes;
+  Stars *stars;
+  char *buffer, line[64], *c;
+  struct tm timeptr;
+  double tmp;
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't find image file %s\n", file);
+    clear_lockfile ();
+    exit(0);
+  }
+
+  /* open file */
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find data file %s\n", file);
+    clear_lockfile ();
+    exit(0);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  c = strrchr (file, 0x2f);
+  if (c == (char *) NULL) {
+    strcpy (image[0].name, file);
+  } else { 
+    strcpy (image[0].name, (c+1));
+  }
+  /* get astrometry information */
+  strcpy (image[0].coords.ctype, "NONE");
+  fits_scan (&header, "CTYPE1",   "%s",  1, image[0].coords.ctype);
+  if (strcmp (image[0].coords.ctype, "RA---PLY")) {
+    fprintf (stderr, "ERROR: wrong astrometric info in header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  fits_scan (&header, "CDELT1",   "%f", 1, &image[0].coords.cdelt1); 
+  fits_scan (&header, "CDELT2",   "%f", 1, &image[0].coords.cdelt2);
+  fits_scan (&header, "CRVAL1",   "%lf", 1, &image[0].coords.crval1);
+  fits_scan (&header, "CRVAL2",   "%lf", 1, &image[0].coords.crval2);  
+  fits_scan (&header, "CRPIX1",   "%f", 1, &image[0].coords.crpix1);
+  fits_scan (&header, "CRPIX2",   "%f", 1, &image[0].coords.crpix2);
+  fits_scan (&header, "PC001001", "%f", 1, &image[0].coords.pc1_1);
+  fits_scan (&header, "PC001002", "%f", 1, &image[0].coords.pc1_2);
+  fits_scan (&header, "PC002001", "%f", 1, &image[0].coords.pc2_1);
+  fits_scan (&header, "PC002002", "%f", 1, &image[0].coords.pc2_2);
+  fits_scan (&header, "CERROR",   "%lf", 1, &tmp);
+  /* RA Terms */
+  fits_scan (&header, "PCA1X2Y0", "%f", 1, &image[0].coords.polyterms[0][0]);
+  fits_scan (&header, "PCA1X1Y1", "%f", 1, &image[0].coords.polyterms[1][0]);
+  fits_scan (&header, "PCA1X0Y2", "%f", 1, &image[0].coords.polyterms[2][0]);
+  fits_scan (&header, "PCA1X3Y0", "%f", 1, &image[0].coords.polyterms[3][0]);
+  fits_scan (&header, "PCA1X2Y1", "%f", 1, &image[0].coords.polyterms[4][0]);
+  fits_scan (&header, "PCA1X1Y2", "%f", 1, &image[0].coords.polyterms[5][0]);
+  fits_scan (&header, "PCA1X0Y3", "%f", 1, &image[0].coords.polyterms[6][0]);
+  /* Dec Terms */
+  fits_scan (&header, "PCA2X2Y0", "%f", 1, &image[0].coords.polyterms[0][1]);
+  fits_scan (&header, "PCA2X1Y1", "%f", 1, &image[0].coords.polyterms[1][1]);
+  fits_scan (&header, "PCA2X0Y2", "%f", 1, &image[0].coords.polyterms[2][1]);
+  fits_scan (&header, "PCA2X3Y0", "%f", 1, &image[0].coords.polyterms[3][1]);
+  fits_scan (&header, "PCA2X2Y1", "%f", 1, &image[0].coords.polyterms[4][1]);
+  fits_scan (&header, "PCA2X1Y2", "%f", 1, &image[0].coords.polyterms[5][1]);
+  fits_scan (&header, "PCA2X0Y3", "%f", 1, &image[0].coords.polyterms[6][1]);
+  image[0].coords.Npolyterms = 2; /* how many do we use? */
+  /* CERROR in data file is in pixels, convert to 20*arcsec */
+  image[0].cerror = tmp * 50.0 * image[0].coords.cdelt1 * 3600.0;
+  while (image[0].coords.crval1 < 0) image[0].coords.crval1 += 360.0;
+  while (image[0].coords.crval1 > 360.0) image[0].coords.crval1 -= 360.0;
+ 
+  fits_scan (&header, "NAXIS1",   "%hd", 1, &image[0].NX); 
+  fits_scan (&header, "NAXIS2",   "%hd", 1, &image[0].NY);
+  fits_scan (&header, "PHOTCODE", "%hd", 1, &image[0].source);
+  image[0].NX -= XOVERSCAN;
+  image[0].NY -= YOVERSCAN;
+
+  tmp = 0;
+  fits_scan (&header, "FLIMIT",   "%lf", 1, &tmp);
+  image[0].detection_limit = tmp * 10.0;
+
+  tmp = 0;
+  fits_scan (&header, "FSATUR",   "%lf", 1, &tmp);
+  image[0].saturation_limit = tmp * 10.0;
+
+  if (!fits_scan (&header, "TZERO",   "%d",  1, &image[0].tzero)) {
+    fits_scan (&header, "UT",   "%s",  1, line);
+    /* remove : characters */
+    for (c = strchr (line, 0x3a); c != (char *) NULL; c = strchr (c, 0x3a))
+      *c = ' ';
+    sscanf (line, "%d %d %d", &timeptr.tm_hour, &timeptr.tm_min, &timeptr.tm_sec);
+    fits_scan (&header, "DATE-UT",   "%s",  1, line);
+    for (c = strchr (line, 0x2f); c != (char *) NULL; c = strchr (c, 0x2f))
+      *c = ' ';
+    sscanf (line, "%d %d %d", &timeptr.tm_year, &timeptr.tm_mon, &timeptr.tm_mday);
+    if (timeptr.tm_year < 90) { /* correct for year 2000 turnover */
+      timeptr.tm_year += 100;
+    }
+    image[0].tzero = mktime (&timeptr);
+  }
+
+  tmp = 0;
+  fits_scan (&header, "TRATE",   "%lf", 1, &tmp);
+  image[0].trate = 10000 * tmp;
+
+  tmp = 0;
+  fits_scan (&header, "AIRMASS", "%lf", 1, &tmp);
+  image[0].secz = 1000*tmp;
+
+  /* secz is in units milli-airmass */
+  image[0].Mcal =  ALPHA*(image[0].secz - 1000);
+  image[0].Xm   = 30.0;
+  image[0].code = 0;
+  bzero (image[0].dummy, sizeof(image[0].dummy));
+
+  /* find number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &image[0].nstar);
+  if (image[0].nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  ALLOCATE (stars, Stars, image[0].nstar);
+  Nbytes = image[0].nstar*BYTES_STAR;
+
+  /* load in stars by blocks of 1000 */
+  nstar = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR));
+  for (i = 0; i < (int)(Nbytes / (BLOCK*BYTES_STAR)); i++) {
+    nbytes = Fread (buffer, 1, (BLOCK*BYTES_STAR), f, "char");
+    if (nbytes != BLOCK*BYTES_STAR) {
+      fprintf (stderr, "ERROR: failed to read in stars (1)\n");
+      clear_lockfile ();
+      exit (0);
+    }
+    for (j = 0; j < BLOCK; j++, nstar++) {
+      dparse (&stars[nstar].X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].M,  3, &buffer[j*BYTES_STAR]);
+      dparse (&stars[nstar].dM, 4, &buffer[j*BYTES_STAR]);
+      XY_to_RD (&stars[nstar].R, &stars[nstar].D, stars[nstar].X, stars[nstar].Y, &image[0].coords);
+      stars[nstar].found = -1;
+    }
+  }
+  /* left over fraction of a block */
+  nbytes = Fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f, "char");
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    clear_lockfile ();
+    exit (0);
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstar++) {
+    dparse (&stars[nstar].X, 1, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].Y, 2, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].M, 3, &buffer[j*BYTES_STAR]);
+    dparse (&stars[nstar].dM, 4, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&stars[nstar].R, &stars[nstar].D, stars[nstar].X, stars[nstar].Y, &image[0].coords);
+    stars[nstar].found = -1;
+  }
+
+  if (image[0].nstar != nstar) {
+    fprintf (stderr, "ERROR: failed to read in all stars (%d != %d)\n", image[0].nstar, nstar);
+    clear_lockfile ();
+    exit (0);
+  }
+  free (header.buffer);
+  free (buffer);
+ 
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+  *NSTARS = image[0].nstar;
+
+  return (stars);
+}
Index: /trunk/Ohana/src/markstar/src/old/sort_lists.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/sort_lists.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/sort_lists.c	(revision 2490)
@@ -0,0 +1,48 @@
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
Index: /trunk/Ohana/src/markstar/src/old/sort_stars.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/sort_stars.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/sort_stars.c	(revision 2490)
@@ -0,0 +1,61 @@
+# include "relphot.h"
+
+void sort_stars (radec, stars, Nstars)
+int  **radec;
+Star  *stars;
+int    Nstars;
+{
+  
+  int i;
+  double *RAs;
+
+  ALLOCATE (radec[0], int, Nstars);
+  ALLOCATE (RAs, double, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    radec[0][i] = i;
+    RAs[i] = stars[i].RA;
+  }
+
+  sort_seq (radec[0], RAs, Nstars);
+  free (RAs);
+
+}
+
+
+void sort_seq (seq, value, N) 
+int *seq;
+double *value;
+int N;
+{
+  int l,j,ir,i;
+  int temp;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      temp = seq[--l];
+    }
+    else {
+      temp = seq[ir];
+      seq[ir] = seq[0];
+      if (--ir == 0) {
+	seq[0] = temp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && value[seq[j]] < value[seq[j+1]]) ++j;
+      if (value[temp] < value[seq[j]]) {
+	seq[i]=seq[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    seq[i] = temp;
+  }
+}
+
+
Index: /trunk/Ohana/src/markstar/src/old/string.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/string.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/string.c	(revision 2490)
@@ -0,0 +1,64 @@
+# include <stdio.h>
+# include <math.h>
+# define TRUE  1
+# define FALSE 0
+
+int scan_line (f, line) 
+FILE *f;
+char line[];
+{
+
+  int i, status;
+  char c;
+  
+  status = EOF + 1;
+  
+  for (i = 0, c = 0; (c != '\n') && (status != EOF); i++) {
+    status = fscanf (f, "%c", &c);
+    line[i] = c;
+  }
+  line[i - 1] = 0;  /* this could make things crash! */
+
+  if (i > 1) {
+    status = EOF + 1;
+  }
+
+  return (status);
+
+}
+
+char *_parse_nextword(string)
+char *string;
+{
+  if (string == (char *) NULL) return ((char *) NULL);
+
+  for (; isspace (*string); string++);
+  for (; (*string != 0) && !isspace (*string); string++);
+  for (; isspace (*string); string++);
+  return (string);
+}
+
+int dparse (X, NX, line)
+double *X;
+int NX;
+char *line;
+{
+
+  int i;
+  char *word;
+  char *ptr;
+
+  word = line;
+  for (i = 0; i < NX - 1; i++)
+    word = _parse_nextword (word);
+
+  *X = strtod (word, &ptr);
+  if (ptr == word)
+    return (FALSE);
+  else {
+    if (word[0] == '-') 
+      return (-1);
+    else
+      return (1);
+  }
+}
Index: /trunk/Ohana/src/markstar/src/old/wimage.c
===================================================================
--- /trunk/Ohana/src/markstar/src/old/wimage.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/old/wimage.c	(revision 2490)
@@ -0,0 +1,67 @@
+# include "addstar.h"
+
+wimage (filename, image, Nstars)
+char *filename;
+Image image[];
+int Nstars;
+{
+  
+  int Nimages, status;
+  FILE *f;
+  Header header;
+
+  if (!fits_read_header (ImageCat, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't find %s, creating a new one\n", ImageCat);
+    if (!fits_read_header (ImageTemplate, &header)) {
+      fprintf (stderr, "ERROR: can't find template header %s\n", ImageTemplate);
+      clear_lockfile ();
+      exit (0);
+    }
+    f = fopen (ImageCat, "w");
+    if (f == NULL) {
+      fprintf (stderr, "ERROR: can't create/open image catalog file: %s\n", ImageCat);
+      clear_lockfile ();
+      exit (0);
+    }
+  }
+  
+  Nimages = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimages);
+  Nimages ++;
+  fits_modify (&header, "NIMAGES", "%d", 1, Nimages);
+
+  f = fopen (ImageCat, "r+");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't create/open image catalog file: %s\n", ImageCat);
+    clear_lockfile ();
+    exit (0);
+  }
+
+  /* position to begining of file to write header */
+  fseek (f, 0, SEEK_SET);
+  status = Fwrite (header.buffer, 1, header.size, f, "char");
+  if (status != header.size) {
+    fprintf (stderr, "ERRPR: failed writing data to image header\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  fseek (f, 0, SEEK_END);
+  fprintf (stderr, "Image: %d\n", sizeof(Image));
+  status = Fwrite (image, sizeof(Image), 1, f, "image");
+  if (status != 1) {
+    fprintf (stderr, "ERRPR: failed writing data to image catalog\n");
+    clear_lockfile ();
+    exit (0);
+  }
+
+  fclose (f);
+  
+
+}
+
+/* the image we add in this routine is always a new image.  
+   We only need to do two things:
+     1) append the data for the image to the end of the file
+     2) update the NIMAGES field in the header (which means, read in header, re-write)
+ */
Index: /trunk/Ohana/src/markstar/src/sorts.c
===================================================================
--- /trunk/Ohana/src/markstar/src/sorts.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/sorts.c	(revision 2490)
@@ -0,0 +1,175 @@
+
+
+sort_lists (X, Y, S, N) 
+float *X, *Y;
+int *S, N;
+{
+  int l,j,ir,i;
+  double tX, tY, tS;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+    S[i] = tS;
+  }
+}
+
+sort_entries (X, Y, N) 
+     double *X, *Y;
+     int N;
+{
+  int l,j,ir,i;
+  double tX, tY;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tY = Y[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tY = Y[ir];
+      Y[ir] = Y[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	Y[0] = tY;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	Y[i] = Y[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    Y[i] = tY;
+  }
+}
+
+
+
+sort (X, N) 
+     double *X;
+     int N;
+{
+  int l,j,ir,i;
+  double tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+  }
+}
+
+
+sort_seq (X, S, N) 
+     double *X;
+     int *S;
+     int N;
+{
+  int l,j,ir,i;
+  int tS;
+  double tX;
+  
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tX = X[l];
+      tS = S[l];
+    }
+    else {
+      tX = X[ir];
+      X[ir] = X[0];
+      tS = S[ir];
+      S[ir] = S[0];
+      if (--ir == 0) {
+	X[0] = tX;
+	S[0] = tS;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && X[j] < X[j+1]) j++;
+      if (tX < X[j]) {
+	X[i] = X[j];
+	S[i] = S[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    X[i] = tX;
+    S[i] = tS;
+  }
+}
+
Index: /trunk/Ohana/src/markstar/src/wcatalog.c
===================================================================
--- /trunk/Ohana/src/markstar/src/wcatalog.c	(revision 2490)
+++ /trunk/Ohana/src/markstar/src/wcatalog.c	(revision 2490)
@@ -0,0 +1,41 @@
+# include "markstar.h"
+
+wcatalog (char *catname, Catalog *catalog) {
+  
+  int status;
+  char filename[256];
+
+  fits_modify (&catalog[0].header, "MARKSTAR", "%t", 1, TRUE);
+
+  sprintf (filename, "%s/%s\0", CATDIR, catname);
+  status = save_catalog (filename, catalog, VERBOSE);
+
+  if (catalog[0].Naverage) {
+    free (catalog[0].average); 
+    catalog[0].Naverage = 0;
+  }
+  if (catalog[0].Nmeasure) {
+    free (catalog[0].measure); 
+    catalog[0].Nmeasure = 0;
+  }
+  if (catalog[0].Nmissing) {
+    free (catalog[0].missing); 
+    catalog[0].Nmissing = 0;
+  }
+  if (catalog[0].Nsecfilt) {
+    free (catalog[0].secfilt); 
+    catalog[0].Nsecfilt = 0;
+  }
+
+  switch (status) {
+  case 0:
+    exit (0);
+  case 1:
+  case 2:
+    return (status);
+  default:
+    fprintf (stderr, "unknown exit status for save_catalog\n");
+    return (FALSE);
+  }
+}
+
